migrate from std::filesystem::path to io::path (WIP)

This commit is contained in:
MihailRis 2025-01-30 22:23:13 +03:00
parent 1e22882284
commit e0314803c0
72 changed files with 1189 additions and 791 deletions

View File

@ -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<LayoutCfg>(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<std::filesystem::path>& alternatives
const std::vector<io::path>& alternatives
) {
if (assets->get<Texture>(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();
}
}
}

View File

@ -1,6 +1,5 @@
#pragma once
#include <filesystem>
#include <functional>
#include <map>
#include <set>
@ -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<std::filesystem::path>& alternatives
const std::vector<io::path>& alternatives
);
};

View File

@ -48,16 +48,14 @@ assetload::postfunc assetload::texture(
const std::string& name,
const std::shared_ptr<AssetCfg>&
) {
auto actualFile = paths->find(filename + ".png").u8string();
auto actualFile = paths->find(filename + ".png");
try {
std::shared_ptr<ImageData> image(
imageio::read(fs::u8path(actualFile)).release()
);
std::shared_ptr<ImageData> 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<AssetCfg>&
) {
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<AtlasCfg>(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<std::string> 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<AssetCfg>&
) {
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::File>(vec3::load(path.u8string(), bytes));
auto modelVEC3 = std::make_shared<vec3::File>(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::Model>(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<std::pair<std::string, int>> 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;

View File

@ -4,6 +4,7 @@
#include <stdexcept>
#include <utility>
#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<PCM> 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<PCM> 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<PCM> audio::load_PCM(const fs::path& file, bool headerOnly) {
throw std::runtime_error("unsupported audio format");
}
std::unique_ptr<Sound> audio::load_sound(const fs::path& file, bool keepPCM) {
std::unique_ptr<Sound> audio::load_sound(const io::path& file, bool keepPCM) {
std::shared_ptr<PCM> pcm(
load_PCM(file, !keepPCM && backend->isDummy()).release()
);
@ -207,8 +208,8 @@ std::unique_ptr<Sound> audio::create_sound(
return backend->createSound(std::move(pcm), keepPCM);
}
std::unique_ptr<PCMStream> audio::open_PCM_stream(const fs::path& file) {
std::string ext = file.extension().u8string();
std::unique_ptr<PCMStream> 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<PCMStream> audio::open_PCM_stream(const fs::path& file) {
}
std::unique_ptr<Stream> 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,

View File

@ -1,14 +1,12 @@
#pragma once
#include <filesystem>
#include <glm/glm.hpp>
#include <memory>
#include <vector>
#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<PCM> load_PCM(const fs::path& file, bool headerOnly);
std::unique_ptr<PCM> 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<Sound> load_sound(const fs::path& file, bool keepPCM);
std::unique_ptr<Sound> 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<PCMStream> open_PCM_stream(const fs::path& file);
std::unique_ptr<PCMStream> 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<Stream> open_stream(const fs::path& file, bool keepSource);
std::unique_ptr<Stream> 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,

View File

@ -6,12 +6,9 @@
#include <utility>
#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;

View File

@ -1,10 +1,11 @@
#pragma once
#include <filesystem>
#include <string>
#include <unordered_map>
#include <vector>
#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
);

View File

@ -1,6 +1,5 @@
#include "imageio.hpp"
#include <filesystem>
#include <functional>
#include <unordered_map>
@ -8,8 +7,6 @@
#include "io/io.hpp"
#include "png.hpp"
namespace fs = std::filesystem;
using image_reader =
std::function<std::unique_ptr<ImageData>(const ubyte*, size_t)>;
using image_writer = std::function<void(const std::string&, const ImageData*)>;
@ -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<ImageData> imageio::read(const fs::path& filename) {
auto found = readers.find(extensionOf(filename.u8string()));
std::unique_ptr<ImageData> 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<ImageData>(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);
}

View File

@ -2,7 +2,8 @@
#include <memory>
#include <string>
#include <filesystem>
#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<ImageData> read(const std::filesystem::path& file);
void write(const std::string& filename, const ImageData* image);
std::unique_ptr<ImageData> read(const io::path& file);
void write(const io::path& file, const ImageData* image);
}

View File

@ -5,6 +5,7 @@
#include <string>
#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<audio::PCM> 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<char> data;
@ -166,10 +167,10 @@ public:
}
};
std::unique_ptr<PCMStream> ogg::create_stream(const fs::path& file) {
std::unique_ptr<PCMStream> 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<OggStream>(vf);

View File

@ -1,6 +1,8 @@
#pragma once
#include <filesystem>
#include <memory>
#include "io/fwd.hpp"
namespace audio {
struct PCM;
@ -9,9 +11,9 @@ namespace audio {
namespace ogg {
std::unique_ptr<audio::PCM> load_pcm(
const std::filesystem::path& file, bool headerOnly
const io::path& file, bool headerOnly
);
std::unique_ptr<audio::PCMStream> create_stream(
const std::filesystem::path& file
const io::path& file
);
}

View File

@ -212,7 +212,7 @@ std::unique_ptr<Texture> png::load_texture(const ubyte* bytes, size_t size) {
}
std::unique_ptr<Texture> 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) {

View File

@ -6,6 +6,7 @@
#include <string>
#include <vector>
#include "io/io.hpp"
#include "audio/audio.hpp"
#include "debug/Logger.hpp"
@ -118,11 +119,11 @@ public:
}
};
std::unique_ptr<audio::PCMStream> wav::create_stream(const fs::path& file) {
std::ifstream in(file, std::ios::binary);
std::unique_ptr<audio::PCMStream> 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<audio::PCMStream> wav::create_stream(const fs::path& file) {
}
std::unique_ptr<audio::PCM> wav::load_pcm(
const fs::path& file, bool headerOnly
const io::path& file, bool headerOnly
) {
auto stream = wav::create_stream(file);

View File

@ -1,6 +1,8 @@
#pragma once
#include <filesystem>
#include <memory>
#include "io/fwd.hpp"
namespace audio {
struct PCM;
@ -9,9 +11,9 @@ namespace audio {
namespace wav {
std::unique_ptr<audio::PCM> load_pcm(
const std::filesystem::path& file, bool headerOnly
const io::path& file, bool headerOnly
);
std::unique_ptr<audio::PCMStream> create_stream(
const std::filesystem::path& file
const io::path& file
);
}

View File

@ -43,55 +43,57 @@ ContentLoader::ContentLoader(
}
static void detect_defs(
const fs::path& folder,
const io::path& folder,
const std::string& prefix,
std::vector<std::string>& 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<std::tuple<std::string, std::string>>& 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<std::tuple<std::string, std::string>> 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<std::string, std::string, std::string> create_unit_id(
@ -566,7 +568,7 @@ static std::tuple<std::string, std::string, std::string> 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<std::pair<std::string, std::string>> 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<void(const fs::path&)> handler
const io::path& dir, std::function<void(const io::path&)> 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<T>& 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()
);
});
}

View File

@ -1,14 +1,12 @@
#pragma once
#include <filesystem>
#include <memory>
#include <string>
#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
);

View File

@ -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<std::string> 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<ContentPack>& packs
const std::string& path, const io::path& folder, std::vector<ContentPack>& 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<std::string> ContentPack::worldPacksList(const fs::path& folder) {
fs::path listfile = folder / fs::path("packs.list");
if (!fs::is_regular_file(listfile)) {
std::vector<std::string> 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)

View File

@ -1,27 +1,27 @@
#pragma once
#include <filesystem>
#include <stdexcept>
#include <string>
#include <vector>
#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<DependencyPack> 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<std::string> 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<ContentPack>& packs
);
static std::vector<std::string> 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 "";
}
}
};

View File

@ -67,7 +67,7 @@ static void process_blocks_data(
std::shared_ptr<ContentReport> ContentReport::create(
const std::shared_ptr<WorldFiles>& worldFiles,
const fs::path& filename,
const io::path& filename,
const Content* content
) {
auto worldInfo = worldFiles->readWorldInfo();

View File

@ -1,6 +1,5 @@
#pragma once
#include <filesystem>
#include <string>
#include <utility>
#include <vector>
@ -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<ContentReport> create(
const std::shared_ptr<WorldFiles>& worldFiles,
const fs::path& filename,
const io::path& filename,
const Content* content
);

View File

@ -7,7 +7,7 @@
PacksManager::PacksManager() = default;
void PacksManager::setSources(std::vector<std::pair<std::string, fs::path>> sources) {
void PacksManager::setSources(std::vector<std::pair<std::string, io::path>> sources) {
this->sources = std::move(sources);
}
@ -42,7 +42,7 @@ std::vector<ContentPack> 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<std::string> 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);
}

View File

@ -1,21 +1,19 @@
#pragma once
#include <filesystem>
#include <unordered_map>
#include <vector>
#include "io/io.hpp"
#include "ContentPack.hpp"
namespace fs = std::filesystem;
class PacksManager {
std::unordered_map<std::string, ContentPack> packs;
std::vector<std::pair<std::string, fs::path>> sources;
std::vector<std::pair<std::string, io::path>> sources;
public:
PacksManager();
/// @brief Set content packs sources (search folders)
void setSources(std::vector<std::pair<std::string, fs::path>> sources);
void setSources(std::vector<std::pair<std::string, io::path>> sources);
/// @brief Scan sources and collect all found packs excluding duplication.
/// Scanning order depends on sources order

View File

@ -132,18 +132,18 @@ static VoxelStructureMeta load_structure_meta(
}
static std::vector<std::unique_ptr<VoxelStructure>> 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<std::unique_ptr<VoxelStructure>> 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<VoxelFragment>();
fragment->deserialize(io::read_binary_json(structFile));
@ -162,7 +162,7 @@ static std::vector<std::unique_ptr<VoxelStructure>> 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) +

View File

@ -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
);
}

View File

@ -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);
}

View File

@ -52,10 +52,10 @@ static debug::Logger logger("engine");
namespace fs = std::filesystem;
static std::unique_ptr<ImageData> load_icon(const fs::path& resdir) {
static std::unique_ptr<ImageData> 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<std::string> 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<ResPaths>(resdir, resRoots);
resPaths = std::make_unique<ResPaths>("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<PathsRoot> 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<ResPaths>(resdir, resRoots);
resPaths = std::make_unique<ResPaths>("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> 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> level, int64_t localPlayer) {

View File

@ -14,7 +14,6 @@
#include "PostRunnables.hpp"
#include "Time.hpp"
#include <filesystem>
#include <memory>
#include <stdexcept>
#include <string>
@ -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);

View File

@ -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<double>(TPS);
double delta = targetDelta;
@ -76,7 +78,7 @@ void ServerMainloop::run() {
void ServerMainloop::setLevel(std::unique_ptr<Level> level) {
if (level == nullptr) {
controller->onWorldQuit();
engine.getPaths().setCurrentWorldFolder(fs::path());
engine.getPaths().setCurrentWorldFolder("");
controller = nullptr;
} else {
controller = std::make_unique<LevelController>(

View File

@ -56,22 +56,22 @@ scriptenv UiDocument::getEnvironment() const {
std::unique_ptr<UiDocument> 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> UiDocument::read(
}
std::shared_ptr<gui::UINode> 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();
}

View File

@ -4,10 +4,9 @@
#include <string>
#include <memory>
#include <filesystem>
#include <unordered_map>
namespace fs = std::filesystem;
#include "io/fwd.hpp"
namespace gui {
class UINode;
@ -48,10 +47,10 @@ public:
static std::unique_ptr<UiDocument> 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<gui::UINode> readElement(
const fs::path& file, const std::string& fileName
const io::path& file, const std::string& fileName
);
};

View File

@ -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<ContentPack>& 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<ContentPack>& 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<ContentPack>& packs) {
std::string fallback = langs::FALLBACK_DEFAULT;

View File

@ -3,9 +3,10 @@
#include <string>
#include <vector>
#include <memory>
#include <filesystem>
#include <unordered_map>
#include "io/fwd.hpp"
struct ContentPack;
namespace langs {
@ -44,17 +45,17 @@ namespace langs {
extern std::unordered_map<std::string, LocaleInfo> 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<ContentPack>& 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<ContentPack>& 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<ContentPack>& packs);
}

View File

@ -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();
}

76
src/io/devices/Device.hpp Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <string>
#include <filesystem>
#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<Device> 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<Device> parent;
path root;
};
}

View File

@ -0,0 +1,63 @@
#include "StdfsDevice.hpp"
#include <fstream>
#include <filesystem>
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);
}

View File

@ -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;
};
}

View File

@ -9,9 +9,12 @@
#include "util/stringutil.hpp"
#include <utility>
#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<std::string> 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<io::StdfsDevice>(resourcesFolder));
io::set_device("user", std::make_shared<io::StdfsDevice>(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<std::filesystem::path> EnginePaths::scanForWorlds() const {
std::vector<std::filesystem::path> folders;
std::vector<io::path> EnginePaths::scanForWorlds() const {
std::vector<io::path> 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<std::filesystem::path> 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<io::StdfsDevice>(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<ContentPack>* contentPacks) {
@ -191,65 +201,64 @@ std::tuple<std::string, std::string> 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<PathsRoot> roots)
ResPaths::ResPaths(io::path mainRoot, std::vector<PathsRoot> 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<std::string> 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<std::string> ResPaths::listdirRaw(const std::string& folderName) con
return entries;
}
std::vector<std::filesystem::path> ResPaths::listdir(
std::vector<io::path> ResPaths::listdir(
const std::string& folderName
) const {
std::vector<std::filesystem::path> entries;
std::vector<io::path> 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<std::filesystem::path> 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;
}

View File

@ -1,16 +1,15 @@
#pragma once
#include <filesystem>
#include <stdexcept>
#include <optional>
#include <string>
#include <vector>
#include <tuple>
#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<ContentPack>* contentPacks);
std::vector<std::filesystem::path> scanForWorlds() const;
std::vector<io::path> 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<std::string, std::string> 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<std::filesystem::path> scriptFolder;
std::vector<ContentPack>* contentPacks = nullptr;
};
struct PathsRoot {
std::string name;
std::filesystem::path path;
io::path path;
};
class ResPaths {
public:
ResPaths(std::filesystem::path mainRoot, std::vector<PathsRoot> roots);
ResPaths(io::path mainRoot, std::vector<PathsRoot> 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<std::filesystem::path> listdir(const std::string& folder) const;
std::vector<io::path> listdir(const std::string& folder) const;
std::vector<std::string> 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<PathsRoot> roots;
};

5
src/io/fwd.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
namespace io {
class path;
}

View File

@ -1,7 +1,7 @@
#include "io.hpp"
#include <map>
#include <stdint.h>
#include <fstream>
#include <iostream>
#include <memory>
@ -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<std::string, std::shared_ptr<io::Device>> devices;
void io::set_device(const std::string& name, std::shared_ptr<io::Device> device) {
devices[name] = device;
}
std::shared_ptr<io::Device> 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<io::SubDevice>(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<ubyte> io::read_bytes_buffer(const fs::path& path) {
util::Buffer<ubyte> 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<ubyte>(std::move(bytes), size);
}
std::unique_ptr<ubyte[]> 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<ubyte[]>(length);
input.read((char*)data.get(), length);
input.close();
device.read(filename.pathPart(), data.get(), length);
return data;
}
std::vector<ubyte> 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<ubyte> io::read_bytes(const path& filename) {
auto& device = io::require_device(filename.entryPoint());
size_t length = device.size(filename.pathPart());
std::vector<ubyte> 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<std::string> io::read_list(const fs::path& filename) {
std::ifstream file(filename);
std::vector<std::string> 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<std::string> lines;
@ -165,6 +170,71 @@ std::vector<std::string> 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 <map>
#include "coders/json.hpp"
@ -177,22 +247,22 @@ static std::map<fs::path, DecodeFunc> 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());
}

View File

@ -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> device);
std::shared_ptr<Device> 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<ubyte> read_bytes_buffer(const fs::path&);
std::unique_ptr<ubyte[]> read_bytes(const fs::path&, size_t& length);
std::vector<ubyte> 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<ubyte> read_bytes_buffer(const path& file);
std::unique_ptr<ubyte[]> read_bytes(const path& file, size_t& length);
std::vector<ubyte> 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<std::string> read_list(const fs::path& file);
std::vector<std::string> 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);
}

11
src/io/path.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "path.hpp"
#include <stdexcept>
using namespace io;
void path::checkValid() const {
if (colonPos == std::string::npos) {
throw std::runtime_error("path entry point is not specified: " + str);
}
}

138
src/io/path.hpp Normal file
View File

@ -0,0 +1,138 @@
#pragma once
#include <string>
#include <filesystem>
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;
};
}

View File

@ -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<ContentReport>& 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) {

View File

@ -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;
}

View File

@ -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<std::string> 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<size_t>(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<size_t>(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<lua::LuaBytearray>(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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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<string>
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();
}

View File

@ -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) {

View File

@ -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;

View File

@ -1,4 +1,5 @@
#include <iostream>
#include <iomanip>
#include "libs/api_lua.hpp"
#include "debug/Logger.hpp"

View File

@ -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;
}

View File

@ -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<Process> 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
) {

View File

@ -1,11 +1,11 @@
#pragma once
#include <filesystem>
#include <glm/glm.hpp>
#include <memory>
#include <string>
#include <vector>
#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<Process> 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<GeneratorScript> 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
);

View File

@ -1,15 +1,16 @@
#pragma once
#include <string>
#include <filesystem>
#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
);
}

View File

@ -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);

View File

@ -1,13 +1,11 @@
#pragma once
#include <filesystem>
#include <functional>
#include <memory>
#include <string>
#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
);

View File

@ -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, "", "<empty>"));
@ -252,7 +257,7 @@ public:
std::unique_ptr<GeneratorScript> 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);

View File

@ -1,6 +1,5 @@
#include "command_line.hpp"
#include <filesystem>
#include <iostream>
#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);
}

View File

@ -78,7 +78,7 @@ void World::write(Level* level) {
std::unique_ptr<Level> 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<Level> 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<Level>(std::move(world), content, settings);
@ -116,7 +116,7 @@ std::unique_ptr<Level> 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<Level> World::load(
auto level = std::make_unique<Level>(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<Level> World::load(
std::shared_ptr<ContentReport> World::checkIndices(
const std::shared_ptr<WorldFiles>& 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;

View File

@ -1,10 +1,10 @@
#pragma once
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
#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<Level> 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,

View File

@ -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<ubyte>(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;

View File

@ -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<Task> 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<ubyte[]> 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:

View File

@ -1,16 +1,14 @@
#pragma once
#include <filesystem>
#include <memory>
#include <queue>
#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(

View File

@ -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<WorldInfo> 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<std::string>& packs) {
io::write_json(getIndicesFile(), root);
}
fs::path WorldFiles::getFolder() const {
io::path WorldFiles::getFolder() const {
return directory;
}

View File

@ -1,6 +1,5 @@
#pragma once
#include <filesystem>
#include <glm/glm.hpp>
#include <optional>
#include <memory>
@ -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<WorldInfo> readWorldInfo();
@ -70,7 +67,7 @@ public:
void removeIndices(const std::vector<std::string>& packs);
/// @return world folder
fs::path getFolder() const;
io::path getFolder() const;
WorldRegions& getRegions() {
return regions;

View File

@ -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<RegionLayerIndex>(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);
}
}

View File

@ -1,7 +1,6 @@
#pragma once
#include <condition_variable>
#include <filesystem>
#include <functional>
#include <glm/glm.hpp>
#include <memory>
@ -19,8 +18,6 @@
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>
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<ubyte[]> 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();

View File

@ -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) {

View File

@ -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);
}

14
test/io/path.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <gtest/gtest.h>
#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");
}