migrate from std::filesystem::path to io::path (WIP)
This commit is contained in:
parent
1e22882284
commit
e0314803c0
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@ -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()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) +
|
||||
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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>(
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
76
src/io/devices/Device.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
63
src/io/devices/StdfsDevice.cpp
Normal file
63
src/io/devices/StdfsDevice.cpp
Normal 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);
|
||||
}
|
||||
21
src/io/devices/StdfsDevice.hpp
Normal file
21
src/io/devices/StdfsDevice.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
5
src/io/fwd.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace io {
|
||||
class path;
|
||||
}
|
||||
214
src/io/io.cpp
214
src/io/io.cpp
@ -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());
|
||||
}
|
||||
|
||||
@ -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
11
src/io/path.cpp
Normal 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
138
src/io/path.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "libs/api_lua.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
) {
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
14
test/io/path.cpp
Normal 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");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user