format: reformat project
Signed-off-by: Vyacheslav Ivanov <islavaivanov76@gmail.com>
This commit is contained in:
parent
736cd175d5
commit
bbf33e8e4d
@ -1,29 +1,21 @@
|
|||||||
#ifndef ASSETS_ASSETS_HPP_
|
#ifndef ASSETS_ASSETS_HPP_
|
||||||
#define ASSETS_ASSETS_HPP_
|
#define ASSETS_ASSETS_HPP_
|
||||||
|
|
||||||
#include "../graphics/core/TextureAnimation.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <optional>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../graphics/core/TextureAnimation.hpp"
|
||||||
|
|
||||||
class Assets;
|
class Assets;
|
||||||
|
|
||||||
enum class AssetType {
|
enum class AssetType { TEXTURE, SHADER, FONT, ATLAS, LAYOUT, SOUND, MODEL };
|
||||||
TEXTURE,
|
|
||||||
SHADER,
|
|
||||||
FONT,
|
|
||||||
ATLAS,
|
|
||||||
LAYOUT,
|
|
||||||
SOUND,
|
|
||||||
MODEL
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace assetload {
|
namespace assetload {
|
||||||
/// @brief final work to do in the main thread
|
/// @brief final work to do in the main thread
|
||||||
@ -31,7 +23,7 @@ namespace assetload {
|
|||||||
|
|
||||||
using setupfunc = std::function<void(const Assets*)>;
|
using setupfunc = std::function<void(const Assets*)>;
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
void assets_setup(const Assets*);
|
void assets_setup(const Assets*);
|
||||||
|
|
||||||
class error : public std::runtime_error {
|
class error : public std::runtime_error {
|
||||||
@ -39,12 +31,11 @@ namespace assetload {
|
|||||||
std::string filename;
|
std::string filename;
|
||||||
std::string reason;
|
std::string reason;
|
||||||
public:
|
public:
|
||||||
error(
|
error(AssetType type, std::string filename, std::string reason)
|
||||||
AssetType type, std::string filename, std::string reason
|
: std::runtime_error(filename + ": " + reason),
|
||||||
) : std::runtime_error(filename + ": " + reason),
|
type(type),
|
||||||
type(type),
|
filename(std::move(filename)),
|
||||||
filename(std::move(filename)),
|
reason(std::move(reason)) {
|
||||||
reason(std::move(reason)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetType getAssetType() const {
|
AssetType getAssetType() const {
|
||||||
@ -75,12 +66,12 @@ public:
|
|||||||
const std::vector<TextureAnimation>& getAnimations();
|
const std::vector<TextureAnimation>& getAnimations();
|
||||||
void store(const TextureAnimation& animation);
|
void store(const TextureAnimation& animation);
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
void store(std::unique_ptr<T> asset, const std::string& name) {
|
void store(std::unique_ptr<T> asset, const std::string& name) {
|
||||||
assets[typeid(T)][name].reset(asset.release());
|
assets[typeid(T)][name].reset(asset.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
T* get(const std::string& name) const {
|
T* get(const std::string& name) const {
|
||||||
const auto& mapIter = assets.find(typeid(T));
|
const auto& mapIter = assets.find(typeid(T));
|
||||||
if (mapIter == assets.end()) {
|
if (mapIter == assets.end()) {
|
||||||
@ -94,7 +85,7 @@ public:
|
|||||||
return static_cast<T*>(found->second.get());
|
return static_cast<T*>(found->second.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
std::optional<const assets_map*> getMap() const {
|
std::optional<const assets_map*> getMap() const {
|
||||||
const auto& mapIter = assets.find(typeid(T));
|
const auto& mapIter = assets.find(typeid(T));
|
||||||
if (mapIter == assets.end()) {
|
if (mapIter == assets.end()) {
|
||||||
@ -114,7 +105,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
void assetload::assets_setup(const Assets* assets) {
|
void assetload::assets_setup(const Assets* assets) {
|
||||||
if (auto mapPtr = assets->getMap<T>()) {
|
if (auto mapPtr = assets->getMap<T>()) {
|
||||||
for (const auto& entry : **mapPtr) {
|
for (const auto& entry : **mapPtr) {
|
||||||
@ -123,4 +114,4 @@ void assetload::assets_setup(const Assets* assets) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASSETS_ASSETS_HPP_
|
#endif // ASSETS_ASSETS_HPP_
|
||||||
|
|||||||
@ -1,30 +1,29 @@
|
|||||||
#include "AssetsLoader.hpp"
|
#include "AssetsLoader.hpp"
|
||||||
|
|
||||||
#include "Assets.hpp"
|
|
||||||
#include "assetload_funcs.hpp"
|
|
||||||
#include "../util/ThreadPool.hpp"
|
|
||||||
#include "../constants.hpp"
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
#include "../debug/Logger.hpp"
|
|
||||||
#include "../coders/imageio.hpp"
|
|
||||||
#include "../files/files.hpp"
|
|
||||||
#include "../files/engine_paths.hpp"
|
|
||||||
#include "../content/Content.hpp"
|
|
||||||
#include "../content/ContentPack.hpp"
|
|
||||||
#include "../voxels/Block.hpp"
|
|
||||||
#include "../objects/rigging.hpp"
|
|
||||||
#include "../graphics/core/Texture.hpp"
|
|
||||||
#include "../logic/scripting/scripting.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../coders/imageio.hpp"
|
||||||
|
#include "../constants.hpp"
|
||||||
|
#include "../content/Content.hpp"
|
||||||
|
#include "../content/ContentPack.hpp"
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
#include "../debug/Logger.hpp"
|
||||||
|
#include "../files/engine_paths.hpp"
|
||||||
|
#include "../files/files.hpp"
|
||||||
|
#include "../graphics/core/Texture.hpp"
|
||||||
|
#include "../logic/scripting/scripting.hpp"
|
||||||
|
#include "../objects/rigging.hpp"
|
||||||
|
#include "../util/ThreadPool.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
|
#include "Assets.hpp"
|
||||||
|
#include "assetload_funcs.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("assets-loader");
|
static debug::Logger logger("assets-loader");
|
||||||
|
|
||||||
AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths)
|
AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths)
|
||||||
: assets(assets), paths(paths)
|
: assets(assets), paths(paths) {
|
||||||
{
|
|
||||||
addLoader(AssetType::SHADER, assetload::shader);
|
addLoader(AssetType::SHADER, assetload::shader);
|
||||||
addLoader(AssetType::TEXTURE, assetload::texture);
|
addLoader(AssetType::TEXTURE, assetload::texture);
|
||||||
addLoader(AssetType::FONT, assetload::font);
|
addLoader(AssetType::FONT, assetload::font);
|
||||||
@ -38,8 +37,13 @@ void AssetsLoader::addLoader(AssetType tag, aloader_func func) {
|
|||||||
loaders[tag] = std::move(func);
|
loaders[tag] = std::move(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLoader::add(AssetType tag, const std::string& filename, const std::string& alias, std::shared_ptr<AssetCfg> settings) {
|
void AssetsLoader::add(
|
||||||
entries.push(aloader_entry{tag, filename, alias, std::move(settings)});
|
AssetType tag,
|
||||||
|
const std::string& filename,
|
||||||
|
const std::string& alias,
|
||||||
|
std::shared_ptr<AssetCfg> settings
|
||||||
|
) {
|
||||||
|
entries.push(aloader_entry {tag, filename, alias, std::move(settings)});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetsLoader::hasNext() const {
|
bool AssetsLoader::hasNext() const {
|
||||||
@ -50,7 +54,7 @@ aloader_func AssetsLoader::getLoader(AssetType tag) {
|
|||||||
auto found = loaders.find(tag);
|
auto found = loaders.find(tag);
|
||||||
if (found == loaders.end()) {
|
if (found == loaders.end()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"unknown asset tag "+std::to_string(static_cast<int>(tag))
|
"unknown asset tag " + std::to_string(static_cast<int>(tag))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
@ -61,7 +65,8 @@ void AssetsLoader::loadNext() {
|
|||||||
logger.info() << "loading " << entry.filename << " as " << entry.alias;
|
logger.info() << "loading " << entry.filename << " as " << entry.alias;
|
||||||
try {
|
try {
|
||||||
aloader_func loader = getLoader(entry.tag);
|
aloader_func loader = getLoader(entry.tag);
|
||||||
auto postfunc = loader(this, paths, entry.filename, entry.alias, entry.config);
|
auto postfunc =
|
||||||
|
loader(this, paths, entry.filename, entry.alias, entry.config);
|
||||||
postfunc(assets);
|
postfunc(assets);
|
||||||
entries.pop();
|
entries.pop();
|
||||||
} catch (std::runtime_error& err) {
|
} catch (std::runtime_error& err) {
|
||||||
@ -74,16 +79,25 @@ void AssetsLoader::loadNext() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLayouts(const scriptenv& env, const std::string& prefix, const fs::path& folder, AssetsLoader& loader) {
|
void addLayouts(
|
||||||
|
const scriptenv& env,
|
||||||
|
const std::string& prefix,
|
||||||
|
const fs::path& folder,
|
||||||
|
AssetsLoader& loader
|
||||||
|
) {
|
||||||
if (!fs::is_directory(folder)) {
|
if (!fs::is_directory(folder)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (auto& entry : fs::directory_iterator(folder)) {
|
for (auto& entry : fs::directory_iterator(folder)) {
|
||||||
const fs::path& file = entry.path();
|
const fs::path& file = entry.path();
|
||||||
if (file.extension().u8string() != ".xml")
|
if (file.extension().u8string() != ".xml") continue;
|
||||||
continue;
|
std::string name = prefix + ":" + file.stem().u8string();
|
||||||
std::string name = prefix+":"+file.stem().u8string();
|
loader.add(
|
||||||
loader.add(AssetType::LAYOUT, file.u8string(), name, std::make_shared<LayoutCfg>(env));
|
AssetType::LAYOUT,
|
||||||
|
file.u8string(),
|
||||||
|
name,
|
||||||
|
std::make_shared<LayoutCfg>(env)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,30 +105,35 @@ void AssetsLoader::tryAddSound(const std::string& name) {
|
|||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string file = SOUNDS_FOLDER+"/"+name;
|
std::string file = SOUNDS_FOLDER + "/" + name;
|
||||||
add(AssetType::SOUND, file, name);
|
add(AssetType::SOUND, file, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string assets_def_folder(AssetType tag) {
|
static std::string assets_def_folder(AssetType tag) {
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case AssetType::FONT: return FONTS_FOLDER;
|
case AssetType::FONT:
|
||||||
case AssetType::SHADER: return SHADERS_FOLDER;
|
return FONTS_FOLDER;
|
||||||
case AssetType::TEXTURE: return TEXTURES_FOLDER;
|
case AssetType::SHADER:
|
||||||
case AssetType::ATLAS: return TEXTURES_FOLDER;
|
return SHADERS_FOLDER;
|
||||||
case AssetType::LAYOUT: return LAYOUTS_FOLDER;
|
case AssetType::TEXTURE:
|
||||||
case AssetType::SOUND: return SOUNDS_FOLDER;
|
return TEXTURES_FOLDER;
|
||||||
case AssetType::MODEL: return MODELS_FOLDER;
|
case AssetType::ATLAS:
|
||||||
|
return TEXTURES_FOLDER;
|
||||||
|
case AssetType::LAYOUT:
|
||||||
|
return LAYOUTS_FOLDER;
|
||||||
|
case AssetType::SOUND:
|
||||||
|
return SOUNDS_FOLDER;
|
||||||
|
case AssetType::MODEL:
|
||||||
|
return MODELS_FOLDER;
|
||||||
}
|
}
|
||||||
return "<error>";
|
return "<error>";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLoader::processPreload(
|
void AssetsLoader::processPreload(
|
||||||
AssetType tag,
|
AssetType tag, const std::string& name, dynamic::Map* map
|
||||||
const std::string& name,
|
|
||||||
dynamic::Map* map
|
|
||||||
) {
|
) {
|
||||||
std::string defFolder = assets_def_folder(tag);
|
std::string defFolder = assets_def_folder(tag);
|
||||||
std::string path = defFolder+"/"+name;
|
std::string path = defFolder + "/" + name;
|
||||||
if (map == nullptr) {
|
if (map == nullptr) {
|
||||||
add(tag, path, name);
|
add(tag, path, name);
|
||||||
return;
|
return;
|
||||||
@ -122,9 +141,10 @@ void AssetsLoader::processPreload(
|
|||||||
map->str("path", path);
|
map->str("path", path);
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case AssetType::SOUND:
|
case AssetType::SOUND:
|
||||||
add(tag, path, name, std::make_shared<SoundCfg>(
|
add(tag,
|
||||||
map->get("keep-pcm", false)
|
path,
|
||||||
));
|
name,
|
||||||
|
std::make_shared<SoundCfg>(map->get("keep-pcm", false)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
add(tag, path, name);
|
add(tag, path, name);
|
||||||
@ -166,7 +186,7 @@ void AssetsLoader::processPreloadConfig(const fs::path& file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLoader::processPreloadConfigs(const Content* content) {
|
void AssetsLoader::processPreloadConfigs(const Content* content) {
|
||||||
auto preloadFile = paths->getMainRoot()/fs::path("preload.json");
|
auto preloadFile = paths->getMainRoot() / fs::path("preload.json");
|
||||||
if (fs::exists(preloadFile)) {
|
if (fs::exists(preloadFile)) {
|
||||||
processPreloadConfig(preloadFile);
|
processPreloadConfig(preloadFile);
|
||||||
}
|
}
|
||||||
@ -192,7 +212,12 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
|||||||
loader.tryAddSound(material.breakSound);
|
loader.tryAddSound(material.breakSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
addLayouts(0, "core", loader.getPaths()->getMainRoot()/fs::path("layouts"), loader);
|
addLayouts(
|
||||||
|
0,
|
||||||
|
"core",
|
||||||
|
loader.getPaths()->getMainRoot() / fs::path("layouts"),
|
||||||
|
loader
|
||||||
|
);
|
||||||
for (auto& entry : content->getPacks()) {
|
for (auto& entry : content->getPacks()) {
|
||||||
auto pack = entry.second.get();
|
auto pack = entry.second.get();
|
||||||
auto& info = pack->getInfo();
|
auto& info = pack->getInfo();
|
||||||
@ -205,7 +230,9 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
|||||||
for (auto& bone : skeleton.getBones()) {
|
for (auto& bone : skeleton.getBones()) {
|
||||||
auto& model = bone->model.name;
|
auto& model = bone->model.name;
|
||||||
if (!model.empty()) {
|
if (!model.empty()) {
|
||||||
loader.add(AssetType::MODEL, MODELS_FOLDER+"/"+model, model);
|
loader.add(
|
||||||
|
AssetType::MODEL, MODELS_FOLDER + "/" + model, model
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +255,7 @@ bool AssetsLoader::loadExternalTexture(
|
|||||||
return true;
|
return true;
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
logger.error() << "error while loading external "
|
logger.error() << "error while loading external "
|
||||||
<< path.u8string() << ": " << err.what();
|
<< path.u8string() << ": " << err.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,22 +272,26 @@ public:
|
|||||||
LoaderWorker(AssetsLoader* loader) : loader(loader) {
|
LoaderWorker(AssetsLoader* loader) : loader(loader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assetload::postfunc operator()(const std::shared_ptr<aloader_entry>& entry) override {
|
assetload::postfunc operator()(const std::shared_ptr<aloader_entry>& entry
|
||||||
|
) override {
|
||||||
aloader_func loadfunc = loader->getLoader(entry->tag);
|
aloader_func loadfunc = loader->getLoader(entry->tag);
|
||||||
return loadfunc(loader, loader->getPaths(), entry->filename, entry->alias, entry->config);
|
return loadfunc(
|
||||||
|
loader,
|
||||||
|
loader->getPaths(),
|
||||||
|
entry->filename,
|
||||||
|
entry->alias,
|
||||||
|
entry->config
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
|
std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
|
||||||
auto pool = std::make_shared<
|
auto pool =
|
||||||
util::ThreadPool<aloader_entry, assetload::postfunc>
|
std::make_shared<util::ThreadPool<aloader_entry, assetload::postfunc>>(
|
||||||
>(
|
"assets-loader-pool",
|
||||||
"assets-loader-pool",
|
[=]() { return std::make_shared<LoaderWorker>(this); },
|
||||||
[=](){return std::make_shared<LoaderWorker>(this);},
|
[=](assetload::postfunc& func) { func(assets); }
|
||||||
[=](assetload::postfunc& func) {
|
);
|
||||||
func(assets);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
pool->setOnComplete(std::move(onDone));
|
pool->setOnComplete(std::move(onDone));
|
||||||
while (!entries.empty()) {
|
while (!entries.empty()) {
|
||||||
const aloader_entry& entry = entries.front();
|
const aloader_entry& entry = entries.front();
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
#ifndef ASSETS_ASSETS_LOADER_HPP_
|
#ifndef ASSETS_ASSETS_LOADER_HPP_
|
||||||
#define ASSETS_ASSETS_LOADER_HPP_
|
#define ASSETS_ASSETS_LOADER_HPP_
|
||||||
|
|
||||||
#include "Assets.hpp"
|
|
||||||
#include "../interfaces/Task.hpp"
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../delegates.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../delegates.hpp"
|
||||||
|
#include "../interfaces/Task.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
#include "Assets.hpp"
|
||||||
|
|
||||||
namespace dynamic {
|
namespace dynamic {
|
||||||
class Map;
|
class Map;
|
||||||
class List;
|
class List;
|
||||||
@ -24,28 +24,27 @@ class AssetsLoader;
|
|||||||
class Content;
|
class Content;
|
||||||
|
|
||||||
struct AssetCfg {
|
struct AssetCfg {
|
||||||
virtual ~AssetCfg() {}
|
virtual ~AssetCfg() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LayoutCfg : AssetCfg {
|
struct LayoutCfg : AssetCfg {
|
||||||
scriptenv env;
|
scriptenv env;
|
||||||
|
|
||||||
LayoutCfg(scriptenv env) : env(std::move(env)) {}
|
LayoutCfg(scriptenv env) : env(std::move(env)) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundCfg : AssetCfg {
|
struct SoundCfg : AssetCfg {
|
||||||
bool keepPCM;
|
bool keepPCM;
|
||||||
|
|
||||||
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
|
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using aloader_func = std::function<assetload::postfunc(
|
using aloader_func = std::function<
|
||||||
AssetsLoader*,
|
assetload::
|
||||||
const ResPaths*,
|
postfunc(AssetsLoader*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
|
||||||
const std::string&,
|
|
||||||
const std::string&,
|
|
||||||
std::shared_ptr<AssetCfg>)
|
|
||||||
>;
|
|
||||||
|
|
||||||
struct aloader_entry {
|
struct aloader_entry {
|
||||||
AssetType tag;
|
AssetType tag;
|
||||||
@ -62,7 +61,9 @@ class AssetsLoader {
|
|||||||
|
|
||||||
void tryAddSound(const std::string& name);
|
void tryAddSound(const std::string& name);
|
||||||
|
|
||||||
void processPreload(AssetType tag, const std::string& name, dynamic::Map* map);
|
void processPreload(
|
||||||
|
AssetType tag, const std::string& name, dynamic::Map* map
|
||||||
|
);
|
||||||
void processPreloadList(AssetType tag, dynamic::List* list);
|
void processPreloadList(AssetType tag, dynamic::List* list);
|
||||||
void processPreloadConfig(const std::filesystem::path& file);
|
void processPreloadConfig(const std::filesystem::path& file);
|
||||||
void processPreloadConfigs(const Content* content);
|
void processPreloadConfigs(const Content* content);
|
||||||
@ -79,7 +80,7 @@ public:
|
|||||||
AssetType tag,
|
AssetType tag,
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
const std::string& alias,
|
const std::string& alias,
|
||||||
std::shared_ptr<AssetCfg> settings=nullptr
|
std::shared_ptr<AssetCfg> settings = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
bool hasNext() const;
|
bool hasNext() const;
|
||||||
@ -104,4 +105,4 @@ public:
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ASSETS_ASSETS_LOADER_HPP_
|
#endif // ASSETS_ASSETS_LOADER_HPP_
|
||||||
|
|||||||
@ -1,30 +1,30 @@
|
|||||||
#include "assetload_funcs.hpp"
|
#include "assetload_funcs.hpp"
|
||||||
|
|
||||||
#include "Assets.hpp"
|
#include <filesystem>
|
||||||
#include "AssetsLoader.hpp"
|
#include <iostream>
|
||||||
#include "../data/dynamic.hpp"
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "../audio/audio.hpp"
|
#include "../audio/audio.hpp"
|
||||||
#include "../files/files.hpp"
|
#include "../coders/GLSLExtension.hpp"
|
||||||
#include "../files/engine_paths.hpp"
|
|
||||||
#include "../coders/commons.hpp"
|
#include "../coders/commons.hpp"
|
||||||
#include "../coders/imageio.hpp"
|
#include "../coders/imageio.hpp"
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
#include "../coders/obj.hpp"
|
#include "../coders/obj.hpp"
|
||||||
#include "../coders/GLSLExtension.hpp"
|
#include "../constants.hpp"
|
||||||
#include "../graphics/core/Shader.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../graphics/core/Texture.hpp"
|
#include "../files/engine_paths.hpp"
|
||||||
#include "../graphics/core/ImageData.hpp"
|
#include "../files/files.hpp"
|
||||||
|
#include "../frontend/UiDocument.hpp"
|
||||||
#include "../graphics/core/Atlas.hpp"
|
#include "../graphics/core/Atlas.hpp"
|
||||||
#include "../graphics/core/Font.hpp"
|
#include "../graphics/core/Font.hpp"
|
||||||
|
#include "../graphics/core/ImageData.hpp"
|
||||||
#include "../graphics/core/Model.hpp"
|
#include "../graphics/core/Model.hpp"
|
||||||
|
#include "../graphics/core/Shader.hpp"
|
||||||
|
#include "../graphics/core/Texture.hpp"
|
||||||
#include "../graphics/core/TextureAnimation.hpp"
|
#include "../graphics/core/TextureAnimation.hpp"
|
||||||
#include "../objects/rigging.hpp"
|
#include "../objects/rigging.hpp"
|
||||||
#include "../frontend/UiDocument.hpp"
|
#include "Assets.hpp"
|
||||||
#include "../constants.hpp"
|
#include "AssetsLoader.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -37,43 +37,38 @@ static bool animation(
|
|||||||
Atlas* dstAtlas
|
Atlas* dstAtlas
|
||||||
);
|
);
|
||||||
|
|
||||||
assetload::postfunc assetload::texture(
|
assetload::postfunc assetload::
|
||||||
AssetsLoader*,
|
texture(AssetsLoader*, const ResPaths* paths, const std::string& filename, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||||
const ResPaths* paths,
|
std::shared_ptr<ImageData> image(
|
||||||
const std::string& filename,
|
imageio::read(paths->find(filename + ".png").u8string()).release()
|
||||||
const std::string& name,
|
|
||||||
const std::shared_ptr<AssetCfg>&
|
|
||||||
) {
|
|
||||||
std::shared_ptr<ImageData> image (
|
|
||||||
imageio::read(paths->find(filename+".png").u8string()).release()
|
|
||||||
);
|
);
|
||||||
return [name, image](auto assets) {
|
return [name, image](auto assets) {
|
||||||
assets->store(Texture::from(image.get()), name);
|
assets->store(Texture::from(image.get()), name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
assetload::postfunc assetload::shader(
|
assetload::postfunc assetload::
|
||||||
AssetsLoader*,
|
shader(AssetsLoader*, const ResPaths* paths, const std::string& filename, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||||
const ResPaths* paths,
|
fs::path vertexFile = paths->find(filename + ".glslv");
|
||||||
const std::string& filename,
|
fs::path fragmentFile = paths->find(filename + ".glslf");
|
||||||
const std::string& name,
|
|
||||||
const std::shared_ptr<AssetCfg>&
|
|
||||||
) {
|
|
||||||
fs::path vertexFile = paths->find(filename+".glslv");
|
|
||||||
fs::path fragmentFile = paths->find(filename+".glslf");
|
|
||||||
|
|
||||||
std::string vertexSource = files::read_string(vertexFile);
|
std::string vertexSource = files::read_string(vertexFile);
|
||||||
std::string fragmentSource = files::read_string(fragmentFile);
|
std::string fragmentSource = files::read_string(fragmentFile);
|
||||||
|
|
||||||
vertexSource = Shader::preprocessor->process(vertexFile, vertexSource);
|
vertexSource = Shader::preprocessor->process(vertexFile, vertexSource);
|
||||||
fragmentSource = Shader::preprocessor->process(fragmentFile, fragmentSource);
|
fragmentSource =
|
||||||
|
Shader::preprocessor->process(fragmentFile, fragmentSource);
|
||||||
|
|
||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
assets->store(Shader::create(
|
assets->store(
|
||||||
vertexFile.u8string(),
|
Shader::create(
|
||||||
fragmentFile.u8string(),
|
vertexFile.u8string(),
|
||||||
vertexSource, fragmentSource
|
fragmentFile.u8string(),
|
||||||
), name);
|
vertexSource,
|
||||||
|
fragmentSource
|
||||||
|
),
|
||||||
|
name
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,19 +84,12 @@ static bool append_atlas(AtlasBuilder& atlas, const fs::path& file) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
assetload::postfunc assetload::atlas(
|
assetload::postfunc assetload::
|
||||||
AssetsLoader*,
|
atlas(AssetsLoader*, const ResPaths* paths, const std::string& directory, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||||
const ResPaths* paths,
|
|
||||||
const std::string& directory,
|
|
||||||
const std::string& name,
|
|
||||||
const std::shared_ptr<AssetCfg>&
|
|
||||||
) {
|
|
||||||
AtlasBuilder builder;
|
AtlasBuilder builder;
|
||||||
for (const auto& file : paths->listdir(directory)) {
|
for (const auto& file : paths->listdir(directory)) {
|
||||||
if (!imageio::is_read_supported(file.extension().u8string()))
|
if (!imageio::is_read_supported(file.extension().u8string())) continue;
|
||||||
continue;
|
if (!append_atlas(builder, file)) continue;
|
||||||
if (!append_atlas(builder, file))
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
std::set<std::string> names = builder.getNames();
|
std::set<std::string> names = builder.getNames();
|
||||||
Atlas* atlas = builder.build(2, false).release();
|
Atlas* atlas = builder.build(2, false).release();
|
||||||
@ -114,13 +102,8 @@ assetload::postfunc assetload::atlas(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
assetload::postfunc assetload::font(
|
assetload::postfunc assetload::
|
||||||
AssetsLoader*,
|
font(AssetsLoader*, const ResPaths* paths, const std::string& filename, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||||
const ResPaths* paths,
|
|
||||||
const std::string& filename,
|
|
||||||
const std::string& name,
|
|
||||||
const std::shared_ptr<AssetCfg>&
|
|
||||||
) {
|
|
||||||
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
|
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
|
||||||
for (size_t i = 0; i <= 4; i++) {
|
for (size_t i = 0; i <= 4; i++) {
|
||||||
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
|
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
|
||||||
@ -133,7 +116,9 @@ assetload::postfunc assetload::font(
|
|||||||
for (auto& page : *pages) {
|
for (auto& page : *pages) {
|
||||||
textures.emplace_back(Texture::from(page.get()));
|
textures.emplace_back(Texture::from(page.get()));
|
||||||
}
|
}
|
||||||
assets->store(std::make_unique<Font>(std::move(textures), res, 4), name);
|
assets->store(
|
||||||
|
std::make_unique<Font>(std::move(textures), res, 4), name
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +135,7 @@ assetload::postfunc assetload::layout(
|
|||||||
assets->store(UiDocument::read(cfg->env, name, file), name);
|
assets->store(UiDocument::read(cfg->env, name, file), name);
|
||||||
} catch (const parsing_error& err) {
|
} catch (const parsing_error& err) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"failed to parse layout XML '"+file+"':\n"+err.errorLog()
|
"failed to parse layout XML '" + file + "':\n" + err.errorLog()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -171,13 +156,13 @@ assetload::postfunc assetload::sound(
|
|||||||
for (size_t i = 0; i < extensions.size(); i++) {
|
for (size_t i = 0; i < extensions.size(); i++) {
|
||||||
extension = extensions[i];
|
extension = extensions[i];
|
||||||
// looking for 'sound_name' as base sound
|
// looking for 'sound_name' as base sound
|
||||||
auto soundFile = paths->find(file+extension);
|
auto soundFile = paths->find(file + extension);
|
||||||
if (fs::exists(soundFile)) {
|
if (fs::exists(soundFile)) {
|
||||||
baseSound = audio::load_sound(soundFile, keepPCM);
|
baseSound = audio::load_sound(soundFile, keepPCM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// looking for 'sound_name_0' as base sound
|
// looking for 'sound_name_0' as base sound
|
||||||
auto variantFile = paths->find(file+"_0"+extension);
|
auto variantFile = paths->find(file + "_0" + extension);
|
||||||
if (fs::exists(variantFile)) {
|
if (fs::exists(variantFile)) {
|
||||||
baseSound = audio::load_sound(variantFile, keepPCM);
|
baseSound = audio::load_sound(variantFile, keepPCM);
|
||||||
break;
|
break;
|
||||||
@ -188,12 +173,14 @@ assetload::postfunc assetload::sound(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loading sound variants
|
// loading sound variants
|
||||||
for (uint i = 1; ; i++) {
|
for (uint i = 1;; i++) {
|
||||||
auto variantFile = paths->find(file+"_"+std::to_string(i)+extension);
|
auto variantFile =
|
||||||
|
paths->find(file + "_" + std::to_string(i) + extension);
|
||||||
if (!fs::exists(variantFile)) {
|
if (!fs::exists(variantFile)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM));
|
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sound = baseSound.release();
|
auto sound = baseSound.release();
|
||||||
@ -202,22 +189,19 @@ assetload::postfunc assetload::sound(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
assetload::postfunc assetload::model(
|
assetload::postfunc assetload::
|
||||||
AssetsLoader* loader,
|
model(AssetsLoader* loader, const ResPaths* paths, const std::string& file, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||||
const ResPaths* paths,
|
auto path = paths->find(file + ".obj");
|
||||||
const std::string& file,
|
|
||||||
const std::string& name,
|
|
||||||
const std::shared_ptr<AssetCfg>&
|
|
||||||
) {
|
|
||||||
auto path = paths->find(file+".obj");
|
|
||||||
auto text = files::read_string(path);
|
auto text = files::read_string(path);
|
||||||
try {
|
try {
|
||||||
auto model = obj::parse(path.u8string(), text).release();
|
auto model = obj::parse(path.u8string(), text).release();
|
||||||
return [=](Assets* assets) {
|
return [=](Assets* assets) {
|
||||||
for (auto& mesh : model->meshes) {
|
for (auto& mesh : model->meshes) {
|
||||||
if (mesh.texture.find('$') == std::string::npos) {
|
if (mesh.texture.find('$') == std::string::npos) {
|
||||||
auto filename = TEXTURES_FOLDER+"/"+mesh.texture;
|
auto filename = TEXTURES_FOLDER + "/" + mesh.texture;
|
||||||
loader->add(AssetType::TEXTURE, filename, mesh.texture, nullptr);
|
loader->add(
|
||||||
|
AssetType::TEXTURE, filename, mesh.texture, nullptr
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assets->store(std::unique_ptr<model::Model>(model), name);
|
assets->store(std::unique_ptr<model::Model>(model), name);
|
||||||
@ -272,8 +256,10 @@ static TextureAnimation create_animation(
|
|||||||
|
|
||||||
const int extension = 2;
|
const int extension = 2;
|
||||||
|
|
||||||
frame.dstPos = glm::ivec2(region.u1 * dstWidth, region.v1 * dstHeight) - extension;
|
frame.dstPos =
|
||||||
frame.size = glm::ivec2(region.u2 * dstWidth, region.v2 * dstHeight) - frame.dstPos + extension;
|
glm::ivec2(region.u1 * dstWidth, region.v1 * dstHeight) - extension;
|
||||||
|
frame.size = glm::ivec2(region.u2 * dstWidth, region.v2 * dstHeight) -
|
||||||
|
frame.dstPos + extension;
|
||||||
|
|
||||||
for (const auto& elem : frameList) {
|
for (const auto& elem : frameList) {
|
||||||
if (!srcAtlas->has(elem.first)) {
|
if (!srcAtlas->has(elem.first)) {
|
||||||
@ -284,7 +270,11 @@ static TextureAnimation create_animation(
|
|||||||
if (elem.second > 0) {
|
if (elem.second > 0) {
|
||||||
frame.duration = static_cast<float>(elem.second) / 1000.0f;
|
frame.duration = static_cast<float>(elem.second) / 1000.0f;
|
||||||
}
|
}
|
||||||
frame.srcPos = glm::ivec2(region.u1 * srcWidth, srcHeight - region.v2 * srcHeight) - extension;
|
frame.srcPos =
|
||||||
|
glm::ivec2(
|
||||||
|
region.u1 * srcWidth, srcHeight - region.v2 * srcHeight
|
||||||
|
) -
|
||||||
|
extension;
|
||||||
animation.addFrame(frame);
|
animation.addFrame(frame);
|
||||||
}
|
}
|
||||||
return animation;
|
return animation;
|
||||||
@ -326,11 +316,11 @@ static bool animation(
|
|||||||
read_anim_file(animFile, frameList);
|
read_anim_file(animFile, frameList);
|
||||||
}
|
}
|
||||||
for (const auto& file : paths->listdir(animsDir + "/" + name)) {
|
for (const auto& file : paths->listdir(animsDir + "/" + name)) {
|
||||||
if (!frameList.empty() && !contains(frameList, file.stem().u8string())) {
|
if (!frameList.empty() &&
|
||||||
|
!contains(frameList, file.stem().u8string())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!append_atlas(builder, file))
|
if (!append_atlas(builder, file)) continue;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
auto srcAtlas = builder.build(2, true);
|
auto srcAtlas = builder.build(2, true);
|
||||||
if (frameList.empty()) {
|
if (frameList.empty()) {
|
||||||
@ -341,7 +331,9 @@ static bool animation(
|
|||||||
auto animation = create_animation(
|
auto animation = create_animation(
|
||||||
srcAtlas.get(), dstAtlas, name, builder.getNames(), frameList
|
srcAtlas.get(), dstAtlas, name, builder.getNames(), frameList
|
||||||
);
|
);
|
||||||
assets->store(std::move(srcAtlas), atlasName + "/" + name + "_animation");
|
assets->store(
|
||||||
|
std::move(srcAtlas), atlasName + "/" + name + "_animation"
|
||||||
|
);
|
||||||
assets->store(animation);
|
assets->store(animation);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#ifndef ASSETS_ASSET_LOADERS_HPP_
|
#ifndef ASSETS_ASSET_LOADERS_HPP_
|
||||||
#define ASSETS_ASSET_LOADERS_HPP_
|
#define ASSETS_ASSET_LOADERS_HPP_
|
||||||
|
|
||||||
#include "Assets.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Assets.hpp"
|
||||||
|
|
||||||
class ResPaths;
|
class ResPaths;
|
||||||
class Assets;
|
class Assets;
|
||||||
@ -65,4 +65,4 @@ namespace assetload {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASSETS_ASSET_LOADERS_HPP_
|
#endif // ASSETS_ASSET_LOADERS_HPP_
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
#include "ALAudio.hpp"
|
#include "ALAudio.hpp"
|
||||||
|
|
||||||
#include "alutil.hpp"
|
|
||||||
#include "../../debug/Logger.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../../debug/Logger.hpp"
|
||||||
|
#include "alutil.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("al-audio");
|
static debug::Logger logger("al-audio");
|
||||||
|
|
||||||
using namespace audio;
|
using namespace audio;
|
||||||
|
|
||||||
ALSound::ALSound(ALAudio* al, uint buffer, const std::shared_ptr<PCM>& pcm, bool keepPCM)
|
ALSound::ALSound(
|
||||||
: al(al), buffer(buffer)
|
ALAudio* al, uint buffer, const std::shared_ptr<PCM>& pcm, bool keepPCM
|
||||||
{
|
)
|
||||||
|
: al(al), buffer(buffer) {
|
||||||
duration = pcm->getDuration();
|
duration = pcm->getDuration();
|
||||||
if (keepPCM) {
|
if (keepPCM) {
|
||||||
this->pcm = pcm;
|
this->pcm = pcm;
|
||||||
@ -36,8 +37,10 @@ std::unique_ptr<Speaker> ALSound::newInstance(int priority, int channel) const {
|
|||||||
return speaker;
|
return speaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALStream::ALStream(ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSource)
|
ALStream::ALStream(
|
||||||
: al(al), source(std::move(source)), keepSource(keepSource) {
|
ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSource
|
||||||
|
)
|
||||||
|
: al(al), source(std::move(source)), keepSource(keepSource) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ALStream::~ALStream() {
|
ALStream::~ALStream() {
|
||||||
@ -60,10 +63,12 @@ std::shared_ptr<PCMStream> ALStream::getSource() const {
|
|||||||
|
|
||||||
bool ALStream::preloadBuffer(uint buffer, bool loop) {
|
bool ALStream::preloadBuffer(uint buffer, bool loop) {
|
||||||
size_t read = source->readFully(this->buffer, BUFFER_SIZE, loop);
|
size_t read = source->readFully(this->buffer, BUFFER_SIZE, loop);
|
||||||
if (!read)
|
if (!read) return false;
|
||||||
return false;
|
ALenum format =
|
||||||
ALenum format = AL::to_al_format(source->getChannels(), source->getBitsPerSample());
|
AL::to_al_format(source->getChannels(), source->getBitsPerSample());
|
||||||
AL_CHECK(alBufferData(buffer, format, this->buffer, read, source->getSampleRate()));
|
AL_CHECK(alBufferData(
|
||||||
|
buffer, format, this->buffer, read, source->getSampleRate()
|
||||||
|
));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +88,6 @@ std::unique_ptr<Speaker> ALStream::createSpeaker(bool loop, int channel) {
|
|||||||
return std::make_unique<ALSpeaker>(al, source, PRIORITY_HIGH, channel);
|
return std::make_unique<ALSpeaker>(al, source, PRIORITY_HIGH, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ALStream::bindSpeaker(speakerid_t speaker) {
|
void ALStream::bindSpeaker(speakerid_t speaker) {
|
||||||
auto sp = audio::get_speaker(this->speaker);
|
auto sp = audio::get_speaker(this->speaker);
|
||||||
if (sp) {
|
if (sp) {
|
||||||
@ -110,7 +114,7 @@ void ALStream::unqueueBuffers(uint alsource) {
|
|||||||
AL_CHECK(alSourceUnqueueBuffers(alsource, 1, &buffer));
|
AL_CHECK(alSourceUnqueueBuffers(alsource, 1, &buffer));
|
||||||
unusedBuffers.push(buffer);
|
unusedBuffers.push(buffer);
|
||||||
|
|
||||||
uint bps = source->getBitsPerSample()/8;
|
uint bps = source->getBitsPerSample() / 8;
|
||||||
uint channels = source->getChannels();
|
uint channels = source->getChannels();
|
||||||
|
|
||||||
ALint bufferSize;
|
ALint bufferSize;
|
||||||
@ -166,10 +170,12 @@ void ALStream::update(double delta) {
|
|||||||
|
|
||||||
duration_t ALStream::getTime() const {
|
duration_t ALStream::getTime() const {
|
||||||
uint total = totalPlayedSamples;
|
uint total = totalPlayedSamples;
|
||||||
auto alspeaker = dynamic_cast<ALSpeaker*>(audio::get_speaker(this->speaker));
|
auto alspeaker =
|
||||||
|
dynamic_cast<ALSpeaker*>(audio::get_speaker(this->speaker));
|
||||||
if (alspeaker) {
|
if (alspeaker) {
|
||||||
uint alsource = alspeaker->source;
|
uint alsource = alspeaker->source;
|
||||||
total += static_cast<duration_t>(AL::getSourcef(alsource, AL_SAMPLE_OFFSET));
|
total +=
|
||||||
|
static_cast<duration_t>(AL::getSourcef(alsource, AL_SAMPLE_OFFSET));
|
||||||
if (source->isSeekable()) {
|
if (source->isSeekable()) {
|
||||||
total %= source->getTotalSamples();
|
total %= source->getTotalSamples();
|
||||||
}
|
}
|
||||||
@ -178,11 +184,11 @@ duration_t ALStream::getTime() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ALStream::setTime(duration_t time) {
|
void ALStream::setTime(duration_t time) {
|
||||||
if (!source->isSeekable())
|
if (!source->isSeekable()) return;
|
||||||
return;
|
|
||||||
uint sample = time * source->getSampleRate();
|
uint sample = time * source->getSampleRate();
|
||||||
source->seek(sample);
|
source->seek(sample);
|
||||||
auto alspeaker = dynamic_cast<ALSpeaker*>(audio::get_speaker(this->speaker));
|
auto alspeaker =
|
||||||
|
dynamic_cast<ALSpeaker*>(audio::get_speaker(this->speaker));
|
||||||
if (alspeaker) {
|
if (alspeaker) {
|
||||||
bool paused = alspeaker->isPaused();
|
bool paused = alspeaker->isPaused();
|
||||||
AL_CHECK(alSourceStop(alspeaker->source));
|
AL_CHECK(alSourceStop(alspeaker->source));
|
||||||
@ -199,7 +205,7 @@ void ALStream::setTime(duration_t time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALSpeaker::ALSpeaker(ALAudio* al, uint source, int priority, int channel)
|
ALSpeaker::ALSpeaker(ALAudio* al, uint source, int priority, int channel)
|
||||||
: al(al), priority(priority), channel(channel), source(source) {
|
: al(al), priority(priority), channel(channel), source(source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ALSpeaker::~ALSpeaker() {
|
ALSpeaker::~ALSpeaker() {
|
||||||
@ -209,8 +215,7 @@ ALSpeaker::~ALSpeaker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ALSpeaker::update(const Channel* channel) {
|
void ALSpeaker::update(const Channel* channel) {
|
||||||
if (source == 0)
|
if (source == 0) return;
|
||||||
return;
|
|
||||||
float gain = this->volume * channel->getVolume();
|
float gain = this->volume * channel->getVolume();
|
||||||
AL_CHECK(alSourcef(source, AL_GAIN, gain));
|
AL_CHECK(alSourcef(source, AL_GAIN, gain));
|
||||||
|
|
||||||
@ -230,9 +235,12 @@ int ALSpeaker::getChannel() const {
|
|||||||
State ALSpeaker::getState() const {
|
State ALSpeaker::getState() const {
|
||||||
int state = AL::getSourcei(source, AL_SOURCE_STATE, AL_STOPPED);
|
int state = AL::getSourcei(source, AL_SOURCE_STATE, AL_STOPPED);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AL_PLAYING: return State::playing;
|
case AL_PLAYING:
|
||||||
case AL_PAUSED: return State::paused;
|
return State::playing;
|
||||||
default: return State::stopped;
|
case AL_PAUSED:
|
||||||
|
return State::paused;
|
||||||
|
default:
|
||||||
|
return State::stopped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +272,11 @@ void ALSpeaker::play() {
|
|||||||
paused = false;
|
paused = false;
|
||||||
stopped = false;
|
stopped = false;
|
||||||
auto channel = get_channel(this->channel);
|
auto channel = get_channel(this->channel);
|
||||||
AL_CHECK(alSourcef(source, AL_GAIN, volume * channel->getVolume() * get_channel(0)->getVolume()));
|
AL_CHECK(alSourcef(
|
||||||
|
source,
|
||||||
|
AL_GAIN,
|
||||||
|
volume * channel->getVolume() * get_channel(0)->getVolume()
|
||||||
|
));
|
||||||
AL_CHECK(alSourcePlay(source));
|
AL_CHECK(alSourcePlay(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +337,9 @@ glm::vec3 ALSpeaker::getVelocity() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ALSpeaker::setRelative(bool relative) {
|
void ALSpeaker::setRelative(bool relative) {
|
||||||
AL_CHECK(alSourcei(source, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE));
|
AL_CHECK(
|
||||||
|
alSourcei(source, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ALSpeaker::isRelative() const {
|
bool ALSpeaker::isRelative() const {
|
||||||
@ -336,19 +350,17 @@ int ALSpeaker::getPriority() const {
|
|||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
|
ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
|
||||||
: device(device), context(context)
|
: device(device), context(context) {
|
||||||
{
|
|
||||||
ALCint size;
|
ALCint size;
|
||||||
alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &size);
|
alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &size);
|
||||||
std::vector<ALCint> attrs(size);
|
std::vector<ALCint> attrs(size);
|
||||||
alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]);
|
alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]);
|
||||||
for (size_t i = 0; i < attrs.size(); ++i){
|
for (size_t i = 0; i < attrs.size(); ++i) {
|
||||||
if (attrs[i] == ALC_MONO_SOURCES) {
|
if (attrs[i] == ALC_MONO_SOURCES) {
|
||||||
logger.info() << "max mono sources: " << attrs[i+1];
|
logger.info() << "max mono sources: " << attrs[i + 1];
|
||||||
maxSources = attrs[i+1];
|
maxSources = attrs[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto devices = getAvailableDevices();
|
auto devices = getAvailableDevices();
|
||||||
logger.info() << "devices:";
|
logger.info() << "devices:";
|
||||||
@ -366,7 +378,7 @@ ALAudio::~ALAudio() {
|
|||||||
AL_CHECK(alDeleteSources(1, &source));
|
AL_CHECK(alDeleteSources(1, &source));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint buffer : allbuffers){
|
for (uint buffer : allbuffers) {
|
||||||
AL_CHECK(alDeleteBuffers(1, &buffer));
|
AL_CHECK(alDeleteBuffers(1, &buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,23 +391,28 @@ ALAudio::~ALAudio() {
|
|||||||
context = nullptr;
|
context = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sound> ALAudio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
std::unique_ptr<Sound> ALAudio::createSound(
|
||||||
|
std::shared_ptr<PCM> pcm, bool keepPCM
|
||||||
|
) {
|
||||||
auto format = AL::to_al_format(pcm->channels, pcm->bitsPerSample);
|
auto format = AL::to_al_format(pcm->channels, pcm->bitsPerSample);
|
||||||
uint buffer = getFreeBuffer();
|
uint buffer = getFreeBuffer();
|
||||||
AL_CHECK(alBufferData(buffer, format, pcm->data.data(), pcm->data.size(), pcm->sampleRate));
|
AL_CHECK(alBufferData(
|
||||||
|
buffer, format, pcm->data.data(), pcm->data.size(), pcm->sampleRate
|
||||||
|
));
|
||||||
return std::make_unique<ALSound>(this, buffer, pcm, keepPCM);
|
return std::make_unique<ALSound>(this, buffer, pcm, keepPCM);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Stream> ALAudio::openStream(std::shared_ptr<PCMStream> stream, bool keepSource) {
|
std::unique_ptr<Stream> ALAudio::openStream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
) {
|
||||||
return std::make_unique<ALStream>(this, stream, keepSource);
|
return std::make_unique<ALStream>(this, stream, keepSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ALAudio> ALAudio::create() {
|
std::unique_ptr<ALAudio> ALAudio::create() {
|
||||||
ALCdevice* device = alcOpenDevice(nullptr);
|
ALCdevice* device = alcOpenDevice(nullptr);
|
||||||
if (device == nullptr)
|
if (device == nullptr) return nullptr;
|
||||||
return nullptr;
|
|
||||||
ALCcontext* context = alcCreateContext(device, nullptr);
|
ALCcontext* context = alcCreateContext(device, nullptr);
|
||||||
if (!alcMakeContextCurrent(context)){
|
if (!alcMakeContextCurrent(context)) {
|
||||||
alcCloseDevice(device);
|
alcCloseDevice(device);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -404,14 +421,15 @@ std::unique_ptr<ALAudio> ALAudio::create() {
|
|||||||
return std::make_unique<ALAudio>(device, context);
|
return std::make_unique<ALAudio>(device, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint ALAudio::getFreeSource(){
|
uint ALAudio::getFreeSource() {
|
||||||
if (!freesources.empty()){
|
if (!freesources.empty()) {
|
||||||
uint source = freesources.back();
|
uint source = freesources.back();
|
||||||
freesources.pop_back();
|
freesources.pop_back();
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
if (allsources.size() == maxSources){
|
if (allsources.size() == maxSources) {
|
||||||
logger.error() << "attempted to create new source, but limit is " << maxSources;
|
logger.error() << "attempted to create new source, but limit is "
|
||||||
|
<< maxSources;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ALuint id;
|
ALuint id;
|
||||||
@ -423,8 +441,8 @@ uint ALAudio::getFreeSource(){
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint ALAudio::getFreeBuffer(){
|
uint ALAudio::getFreeBuffer() {
|
||||||
if (!freebuffers.empty()){
|
if (!freebuffers.empty()) {
|
||||||
uint buffer = freebuffers.back();
|
uint buffer = freebuffers.back();
|
||||||
freebuffers.pop_back();
|
freebuffers.pop_back();
|
||||||
return buffer;
|
return buffer;
|
||||||
@ -439,11 +457,11 @@ uint ALAudio::getFreeBuffer(){
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALAudio::freeSource(uint source){
|
void ALAudio::freeSource(uint source) {
|
||||||
freesources.push_back(source);
|
freesources.push_back(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALAudio::freeBuffer(uint buffer){
|
void ALAudio::freeBuffer(uint buffer) {
|
||||||
freebuffers.push_back(buffer);
|
freebuffers.push_back(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,14 +478,15 @@ std::vector<std::string> ALAudio::getAvailableDevices() const {
|
|||||||
do {
|
do {
|
||||||
devicesVec.emplace_back(ptr);
|
devicesVec.emplace_back(ptr);
|
||||||
ptr += devicesVec.back().size() + 1;
|
ptr += devicesVec.back().size() + 1;
|
||||||
}
|
} while (ptr[0]);
|
||||||
while (ptr[0]);
|
|
||||||
|
|
||||||
return devicesVec;
|
return devicesVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALAudio::setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up){
|
void ALAudio::setListener(
|
||||||
ALfloat listenerOri[] = { at.x, at.y, at.z, up.x, up.y, up.z };
|
glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up
|
||||||
|
) {
|
||||||
|
ALfloat listenerOri[] = {at.x, at.y, at.z, up.x, up.y, up.z};
|
||||||
|
|
||||||
AL_CHECK(alListener3f(AL_POSITION, position.x, position.y, position.z));
|
AL_CHECK(alListener3f(AL_POSITION, position.x, position.y, position.z));
|
||||||
AL_CHECK(alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z));
|
AL_CHECK(alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z));
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
#ifndef SRC_AUDIO_AUDIO_HPP_
|
#ifndef SRC_AUDIO_AUDIO_HPP_
|
||||||
#define SRC_AUDIO_AUDIO_HPP_
|
#define SRC_AUDIO_AUDIO_HPP_
|
||||||
|
|
||||||
#include "../audio.hpp"
|
|
||||||
#include "../../typedefs.hpp"
|
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../../typedefs.hpp"
|
||||||
|
#include "../audio.hpp"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
@ -29,7 +29,12 @@ namespace audio {
|
|||||||
std::shared_ptr<PCM> pcm;
|
std::shared_ptr<PCM> pcm;
|
||||||
duration_t duration;
|
duration_t duration;
|
||||||
public:
|
public:
|
||||||
ALSound(ALAudio* al, uint buffer, const std::shared_ptr<PCM>& pcm, bool keepPCM);
|
ALSound(
|
||||||
|
ALAudio* al,
|
||||||
|
uint buffer,
|
||||||
|
const std::shared_ptr<PCM>& pcm,
|
||||||
|
bool keepPCM
|
||||||
|
);
|
||||||
~ALSound();
|
~ALSound();
|
||||||
|
|
||||||
duration_t getDuration() const override {
|
duration_t getDuration() const override {
|
||||||
@ -40,7 +45,8 @@ namespace audio {
|
|||||||
return pcm;
|
return pcm;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Speaker> newInstance(int priority, int channel) const override;
|
std::unique_ptr<Speaker> newInstance(int priority, int channel)
|
||||||
|
const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ALStream : public Stream {
|
class ALStream : public Stream {
|
||||||
@ -60,7 +66,9 @@ namespace audio {
|
|||||||
public:
|
public:
|
||||||
size_t totalPlayedSamples = 0;
|
size_t totalPlayedSamples = 0;
|
||||||
|
|
||||||
ALStream(ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSource);
|
ALStream(
|
||||||
|
ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSource
|
||||||
|
);
|
||||||
~ALStream();
|
~ALStream();
|
||||||
|
|
||||||
std::shared_ptr<PCMStream> getSource() const override;
|
std::shared_ptr<PCMStream> getSource() const override;
|
||||||
@ -147,8 +155,12 @@ namespace audio {
|
|||||||
|
|
||||||
std::vector<std::string> getAvailableDevices() const;
|
std::vector<std::string> getAvailableDevices() const;
|
||||||
|
|
||||||
std::unique_ptr<Sound> createSound(std::shared_ptr<PCM> pcm, bool keepPCM) override;
|
std::unique_ptr<Sound> createSound(
|
||||||
std::unique_ptr<Stream> openStream(std::shared_ptr<PCMStream> stream, bool keepSource) override;
|
std::shared_ptr<PCM> pcm, bool keepPCM
|
||||||
|
) override;
|
||||||
|
std::unique_ptr<Stream> openStream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
) override;
|
||||||
|
|
||||||
void setListener(
|
void setListener(
|
||||||
glm::vec3 position,
|
glm::vec3 position,
|
||||||
@ -167,4 +179,4 @@ namespace audio {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SRC_AUDIO_AUDIO_HPP_
|
#endif // SRC_AUDIO_AUDIO_HPP_
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#include "alutil.hpp"
|
#include "alutil.hpp"
|
||||||
|
|
||||||
#include "../../debug/Logger.hpp"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "../../debug/Logger.hpp"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
#include <OpenAL/alc.h>
|
#include <OpenAL/alc.h>
|
||||||
@ -17,28 +17,34 @@
|
|||||||
|
|
||||||
static debug::Logger logger("open-al");
|
static debug::Logger logger("open-al");
|
||||||
|
|
||||||
bool AL::check_errors(const std::string& filename, const std::uint_fast32_t line){
|
bool AL::check_errors(
|
||||||
|
const std::string& filename, const std::uint_fast32_t line
|
||||||
|
) {
|
||||||
ALenum error = alGetError();
|
ALenum error = alGetError();
|
||||||
if(error != AL_NO_ERROR){
|
if (error != AL_NO_ERROR) {
|
||||||
logger.error() << filename << ": " << line;
|
logger.error() << filename << ": " << line;
|
||||||
switch(error){
|
switch (error) {
|
||||||
case AL_INVALID_NAME:
|
case AL_INVALID_NAME:
|
||||||
logger.error() << "a bad name (ID) was passed to an OpenAL function";
|
logger.error()
|
||||||
break;
|
<< "a bad name (ID) was passed to an OpenAL function";
|
||||||
case AL_INVALID_ENUM:
|
break;
|
||||||
logger.error() << "an invalid enum value was passed to an OpenAL function";
|
case AL_INVALID_ENUM:
|
||||||
break;
|
logger.error()
|
||||||
case AL_INVALID_VALUE:
|
<< "an invalid enum value was passed to an OpenAL function";
|
||||||
logger.error() << "an invalid value was passed to an OpenAL function";
|
break;
|
||||||
break;
|
case AL_INVALID_VALUE:
|
||||||
case AL_INVALID_OPERATION:
|
logger.error()
|
||||||
logger.error() << "the requested operation is not valid";
|
<< "an invalid value was passed to an OpenAL function";
|
||||||
break;
|
break;
|
||||||
case AL_OUT_OF_MEMORY:
|
case AL_INVALID_OPERATION:
|
||||||
logger.error() << "the requested operation resulted in OpenAL running out of memory";
|
logger.error() << "the requested operation is not valid";
|
||||||
break;
|
break;
|
||||||
default:
|
case AL_OUT_OF_MEMORY:
|
||||||
logger.error() << "UNKNOWN AL ERROR: " << error;
|
logger.error() << "the requested operation resulted in OpenAL "
|
||||||
|
"running out of memory";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.error() << "UNKNOWN AL ERROR: " << error;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#ifndef AUDIO_AUDIOUTIL_HPP_
|
#ifndef AUDIO_AUDIOUTIL_HPP_
|
||||||
#define AUDIO_AUDIOUTIL_HPP_
|
#define AUDIO_AUDIOUTIL_HPP_
|
||||||
|
|
||||||
#include "../../typedefs.hpp"
|
#include <cstdint>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cstdint>
|
|
||||||
|
#include "../../typedefs.hpp"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
@ -15,22 +15,25 @@
|
|||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__)
|
#define AL_CHECK(STATEMENT) \
|
||||||
|
STATEMENT; \
|
||||||
|
AL::check_errors(__FILE__, __LINE__)
|
||||||
#define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__)
|
#define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__)
|
||||||
|
|
||||||
namespace AL {
|
namespace AL {
|
||||||
/// @return true if no errors
|
/// @return true if no errors
|
||||||
bool check_errors(const std::string& filename, const std::uint_fast32_t line);
|
bool check_errors(
|
||||||
|
const std::string& filename, const std::uint_fast32_t line
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief alGetSourcef wrapper
|
/// @brief alGetSourcef wrapper
|
||||||
/// @param source target source
|
/// @param source target source
|
||||||
/// @param field enum value
|
/// @param field enum value
|
||||||
/// @param def default value will be returned in case of error
|
/// @param def default value will be returned in case of error
|
||||||
/// @return field value or default
|
/// @return field value or default
|
||||||
inline float getSourcef(uint source, ALenum field, float def=0.0f) {
|
inline float getSourcef(uint source, ALenum field, float def = 0.0f) {
|
||||||
float value = def;
|
float value = def;
|
||||||
if (source == 0)
|
if (source == 0) return def;
|
||||||
return def;
|
|
||||||
AL_CHECK(alGetSourcef(source, field, &value));
|
AL_CHECK(alGetSourcef(source, field, &value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -40,10 +43,11 @@ namespace AL {
|
|||||||
/// @param field enum value
|
/// @param field enum value
|
||||||
/// @param def default value will be returned in case of error
|
/// @param def default value will be returned in case of error
|
||||||
/// @return field value or default
|
/// @return field value or default
|
||||||
inline glm::vec3 getSource3f(uint source, ALenum field, glm::vec3 def={}) {
|
inline glm::vec3 getSource3f(
|
||||||
|
uint source, ALenum field, glm::vec3 def = {}
|
||||||
|
) {
|
||||||
glm::vec3 value = def;
|
glm::vec3 value = def;
|
||||||
if (source == 0)
|
if (source == 0) return def;
|
||||||
return def;
|
|
||||||
AL_CHECK(alGetSource3f(source, field, &value.x, &value.y, &value.z));
|
AL_CHECK(alGetSource3f(source, field, &value.x, &value.y, &value.z));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -53,32 +57,31 @@ namespace AL {
|
|||||||
/// @param field enum value
|
/// @param field enum value
|
||||||
/// @param def default value will be returned in case of error
|
/// @param def default value will be returned in case of error
|
||||||
/// @return field value or default
|
/// @return field value or default
|
||||||
inline float getSourcei(uint source, ALenum field, int def=0) {
|
inline float getSourcei(uint source, ALenum field, int def = 0) {
|
||||||
int value = def;
|
int value = def;
|
||||||
if (source == 0)
|
if (source == 0) return def;
|
||||||
return def;
|
|
||||||
AL_CHECK(alGetSourcei(source, field, &value));
|
AL_CHECK(alGetSourcei(source, field, &value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ALenum to_al_format(short channels, short bitsPerSample){
|
static inline ALenum to_al_format(short channels, short bitsPerSample) {
|
||||||
bool stereo = (channels > 1);
|
bool stereo = (channels > 1);
|
||||||
|
|
||||||
switch (bitsPerSample) {
|
switch (bitsPerSample) {
|
||||||
case 16:
|
case 16:
|
||||||
if (stereo)
|
if (stereo)
|
||||||
return AL_FORMAT_STEREO16;
|
return AL_FORMAT_STEREO16;
|
||||||
else
|
else
|
||||||
return AL_FORMAT_MONO16;
|
return AL_FORMAT_MONO16;
|
||||||
case 8:
|
case 8:
|
||||||
if (stereo)
|
if (stereo)
|
||||||
return AL_FORMAT_STEREO8;
|
return AL_FORMAT_STEREO8;
|
||||||
else
|
else
|
||||||
return AL_FORMAT_MONO8;
|
return AL_FORMAT_MONO8;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // AUDIO_AUDIOUTIL_HPP_
|
#endif // AUDIO_AUDIOUTIL_HPP_
|
||||||
|
|||||||
@ -9,11 +9,15 @@ NoSound::NoSound(const std::shared_ptr<PCM>& pcm, bool keepPCM) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sound> NoAudio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
std::unique_ptr<Sound> NoAudio::createSound(
|
||||||
|
std::shared_ptr<PCM> pcm, bool keepPCM
|
||||||
|
) {
|
||||||
return std::make_unique<NoSound>(pcm, keepPCM);
|
return std::make_unique<NoSound>(pcm, keepPCM);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Stream> NoAudio::openStream(std::shared_ptr<PCMStream> stream, bool keepSource) {
|
std::unique_ptr<Stream> NoAudio::openStream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
) {
|
||||||
return std::make_unique<NoStream>(stream, keepSource);
|
return std::make_unique<NoStream>(stream, keepSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,8 @@ namespace audio {
|
|||||||
duration_t duration;
|
duration_t duration;
|
||||||
public:
|
public:
|
||||||
NoSound(const std::shared_ptr<PCM>& pcm, bool keepPCM);
|
NoSound(const std::shared_ptr<PCM>& pcm, bool keepPCM);
|
||||||
~NoSound() {}
|
~NoSound() {
|
||||||
|
}
|
||||||
|
|
||||||
duration_t getDuration() const override {
|
duration_t getDuration() const override {
|
||||||
return duration;
|
return duration;
|
||||||
@ -19,7 +20,8 @@ namespace audio {
|
|||||||
return pcm;
|
return pcm;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Speaker> newInstance(int priority, int channel) const override {
|
std::unique_ptr<Speaker> newInstance(int priority, int channel)
|
||||||
|
const override {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -42,7 +44,8 @@ namespace audio {
|
|||||||
void bindSpeaker(speakerid_t speaker) override {
|
void bindSpeaker(speakerid_t speaker) override {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Speaker> createSpeaker(bool loop, int channel) override {
|
std::unique_ptr<Speaker> createSpeaker(bool loop, int channel)
|
||||||
|
override {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,19 +66,23 @@ namespace audio {
|
|||||||
|
|
||||||
class NoAudio : public Backend {
|
class NoAudio : public Backend {
|
||||||
public:
|
public:
|
||||||
~NoAudio() {}
|
~NoAudio() {
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sound> createSound(std::shared_ptr<PCM> pcm, bool keepPCM) override;
|
std::unique_ptr<Sound> createSound(
|
||||||
std::unique_ptr<Stream> openStream(std::shared_ptr<PCMStream> stream, bool keepSource) override;
|
std::shared_ptr<PCM> pcm, bool keepPCM
|
||||||
|
) override;
|
||||||
|
std::unique_ptr<Stream> openStream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
) override;
|
||||||
|
|
||||||
void setListener(
|
void setListener(
|
||||||
glm::vec3 position,
|
glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up
|
||||||
glm::vec3 velocity,
|
) override {
|
||||||
glm::vec3 at,
|
}
|
||||||
glm::vec3 up
|
|
||||||
) override {}
|
|
||||||
|
|
||||||
void update(double delta) override {}
|
void update(double delta) override {
|
||||||
|
}
|
||||||
|
|
||||||
bool isDummy() const override {
|
bool isDummy() const override {
|
||||||
return true;
|
return true;
|
||||||
@ -85,4 +92,4 @@ namespace audio {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // AUDIO_NOAUDIO_HPP_
|
#endif // AUDIO_NOAUDIO_HPP_
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
#include "audio.hpp"
|
#include "audio.hpp"
|
||||||
|
|
||||||
#include "NoAudio.hpp"
|
|
||||||
#include "AL/ALAudio.hpp"
|
|
||||||
|
|
||||||
#include "../coders/wav.hpp"
|
|
||||||
#include "../coders/ogg.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../coders/ogg.hpp"
|
||||||
|
#include "../coders/wav.hpp"
|
||||||
|
#include "AL/ALAudio.hpp"
|
||||||
|
#include "NoAudio.hpp"
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
static speakerid_t nextId = 1;
|
static speakerid_t nextId = 1;
|
||||||
static Backend* backend;
|
static Backend* backend;
|
||||||
@ -86,11 +85,11 @@ class PCMVoidSource : public PCMStream {
|
|||||||
bool closed = false;
|
bool closed = false;
|
||||||
public:
|
public:
|
||||||
PCMVoidSource(size_t totalSamples, uint sampleRate, bool seekable)
|
PCMVoidSource(size_t totalSamples, uint sampleRate, bool seekable)
|
||||||
: totalSamples(totalSamples),
|
: totalSamples(totalSamples),
|
||||||
remain(totalSamples),
|
remain(totalSamples),
|
||||||
sampleRate(sampleRate),
|
sampleRate(sampleRate),
|
||||||
seekable(seekable)
|
seekable(seekable) {
|
||||||
{}
|
}
|
||||||
|
|
||||||
size_t read(char*, size_t bufferSize) override {
|
size_t read(char*, size_t bufferSize) override {
|
||||||
if (closed) {
|
if (closed) {
|
||||||
@ -159,7 +158,7 @@ void audio::initialize(bool enabled) {
|
|||||||
|
|
||||||
std::unique_ptr<PCM> audio::load_PCM(const fs::path& file, bool headerOnly) {
|
std::unique_ptr<PCM> audio::load_PCM(const fs::path& file, bool headerOnly) {
|
||||||
if (!fs::exists(file)) {
|
if (!fs::exists(file)) {
|
||||||
throw std::runtime_error("file not found '"+file.u8string()+"'");
|
throw std::runtime_error("file not found '" + file.u8string() + "'");
|
||||||
}
|
}
|
||||||
std::string ext = file.extension().u8string();
|
std::string ext = file.extension().u8string();
|
||||||
if (ext == ".wav" || ext == ".WAV") {
|
if (ext == ".wav" || ext == ".WAV") {
|
||||||
@ -171,11 +170,15 @@ std::unique_ptr<PCM> audio::load_PCM(const fs::path& file, bool headerOnly) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sound> audio::load_sound(const fs::path& file, bool keepPCM) {
|
std::unique_ptr<Sound> audio::load_sound(const fs::path& file, bool keepPCM) {
|
||||||
std::shared_ptr<PCM> pcm(load_PCM(file, !keepPCM && backend->isDummy()).release());
|
std::shared_ptr<PCM> pcm(
|
||||||
|
load_PCM(file, !keepPCM && backend->isDummy()).release()
|
||||||
|
);
|
||||||
return create_sound(pcm, keepPCM);
|
return create_sound(pcm, keepPCM);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sound> audio::create_sound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
std::unique_ptr<Sound> audio::create_sound(
|
||||||
|
std::shared_ptr<PCM> pcm, bool keepPCM
|
||||||
|
) {
|
||||||
return backend->createSound(std::move(pcm), keepPCM);
|
return backend->createSound(std::move(pcm), keepPCM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,31 +192,32 @@ std::unique_ptr<PCMStream> audio::open_PCM_stream(const fs::path& file) {
|
|||||||
throw std::runtime_error("unsupported audio stream format");
|
throw std::runtime_error("unsupported audio stream format");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Stream> audio::open_stream(const fs::path& file, bool keepSource) {
|
std::unique_ptr<Stream> audio::open_stream(
|
||||||
|
const fs::path& file, bool keepSource
|
||||||
|
) {
|
||||||
if (!keepSource && backend->isDummy()) {
|
if (!keepSource && backend->isDummy()) {
|
||||||
auto header = load_PCM(file, true);
|
auto header = load_PCM(file, true);
|
||||||
// using void source sized as audio instead of actual audio file
|
// using void source sized as audio instead of actual audio file
|
||||||
return open_stream(
|
return open_stream(
|
||||||
std::make_shared<PCMVoidSource>(header->totalSamples, header->sampleRate, header->seekable),
|
std::make_shared<PCMVoidSource>(
|
||||||
|
header->totalSamples, header->sampleRate, header->seekable
|
||||||
|
),
|
||||||
keepSource
|
keepSource
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return open_stream(
|
return open_stream(
|
||||||
std::shared_ptr<PCMStream>(open_PCM_stream(file)),
|
std::shared_ptr<PCMStream>(open_PCM_stream(file)), keepSource
|
||||||
keepSource
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Stream> audio::open_stream(std::shared_ptr<PCMStream> stream, bool keepSource) {
|
std::unique_ptr<Stream> audio::open_stream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
) {
|
||||||
return backend->openStream(std::move(stream), keepSource);
|
return backend->openStream(std::move(stream), keepSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void audio::set_listener(
|
void audio::set_listener(
|
||||||
glm::vec3 position,
|
glm::vec3 position, glm::vec3 velocity, glm::vec3 lookAt, glm::vec3 up
|
||||||
glm::vec3 velocity,
|
|
||||||
glm::vec3 lookAt,
|
|
||||||
glm::vec3 up
|
|
||||||
) {
|
) {
|
||||||
backend->setListener(position, velocity, lookAt, up);
|
backend->setListener(position, velocity, lookAt, up);
|
||||||
}
|
}
|
||||||
@ -317,7 +321,7 @@ speakerid_t audio::play_stream(
|
|||||||
bool loop,
|
bool loop,
|
||||||
int channel
|
int channel
|
||||||
) {
|
) {
|
||||||
std::shared_ptr<Stream> stream (open_stream(file, false));
|
std::shared_ptr<Stream> stream(open_stream(file, false));
|
||||||
return play(stream, position, relative, volume, pitch, loop, channel);
|
return play(stream, position, relative, volume, pitch, loop, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +339,7 @@ int audio::create_channel(const std::string& name) {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
channels.emplace_back(std::make_unique<Channel>(name));
|
channels.emplace_back(std::make_unique<Channel>(name));
|
||||||
return channels.size()-1;
|
return channels.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int audio::get_channel_index(const std::string& name) {
|
int audio::get_channel_index(const std::string& name) {
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef AUDIO_AUDIO_HPP_
|
#ifndef AUDIO_AUDIO_HPP_
|
||||||
#define AUDIO_AUDIO_HPP_
|
#define AUDIO_AUDIO_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -29,14 +29,11 @@ namespace audio {
|
|||||||
class Speaker;
|
class Speaker;
|
||||||
|
|
||||||
/// @brief Audio speaker states
|
/// @brief Audio speaker states
|
||||||
enum class State {
|
enum class State { playing, paused, stopped };
|
||||||
playing,
|
|
||||||
paused,
|
|
||||||
stopped
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief Mixer channel controls speakers volume and effects
|
/// @brief Mixer channel controls speakers volume and effects
|
||||||
/// There is main channel 'master' and sub-channels like 'regular', 'music', 'ambient'...
|
/// There is main channel 'master' and sub-channels like 'regular', 'music',
|
||||||
|
/// 'ambient'...
|
||||||
class Channel {
|
class Channel {
|
||||||
/// @brief Channel name
|
/// @brief Channel name
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -57,8 +54,7 @@ namespace audio {
|
|||||||
const std::string& getName() const;
|
const std::string& getName() const;
|
||||||
|
|
||||||
inline void setPaused(bool flag) {
|
inline void setPaused(bool flag) {
|
||||||
if (flag == paused)
|
if (flag == paused) return;
|
||||||
return;
|
|
||||||
if (flag) {
|
if (flag) {
|
||||||
pause();
|
pause();
|
||||||
} else {
|
} else {
|
||||||
@ -92,19 +88,19 @@ namespace audio {
|
|||||||
/// @brief Audio source is seekable
|
/// @brief Audio source is seekable
|
||||||
bool seekable;
|
bool seekable;
|
||||||
|
|
||||||
PCM(
|
PCM(std::vector<char> data,
|
||||||
std::vector<char> data,
|
|
||||||
size_t totalSamples,
|
size_t totalSamples,
|
||||||
uint8_t channels,
|
uint8_t channels,
|
||||||
uint8_t bitsPerSample,
|
uint8_t bitsPerSample,
|
||||||
uint sampleRate,
|
uint sampleRate,
|
||||||
bool seekable
|
bool seekable)
|
||||||
) : data(std::move(data)),
|
: data(std::move(data)),
|
||||||
totalSamples(totalSamples),
|
totalSamples(totalSamples),
|
||||||
channels(channels),
|
channels(channels),
|
||||||
bitsPerSample(bitsPerSample),
|
bitsPerSample(bitsPerSample),
|
||||||
sampleRate(sampleRate),
|
sampleRate(sampleRate),
|
||||||
seekable(seekable) {}
|
seekable(seekable) {
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Get total audio duration
|
/// @brief Get total audio duration
|
||||||
/// @return duration in seconds
|
/// @return duration in seconds
|
||||||
@ -130,31 +126,31 @@ namespace audio {
|
|||||||
virtual size_t read(char* buffer, size_t bufferSize) = 0;
|
virtual size_t read(char* buffer, size_t bufferSize) = 0;
|
||||||
|
|
||||||
/// @brief Close stream
|
/// @brief Close stream
|
||||||
virtual void close()=0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
/// @brief Check if stream is open
|
/// @brief Check if stream is open
|
||||||
virtual bool isOpen() const=0;
|
virtual bool isOpen() const = 0;
|
||||||
|
|
||||||
/// @brief Get total samples number if seekable or 0
|
/// @brief Get total samples number if seekable or 0
|
||||||
virtual size_t getTotalSamples() const=0;
|
virtual size_t getTotalSamples() const = 0;
|
||||||
|
|
||||||
/// @brief Get total audio track duration if seekable or 0.0
|
/// @brief Get total audio track duration if seekable or 0.0
|
||||||
virtual duration_t getTotalDuration() const=0;
|
virtual duration_t getTotalDuration() const = 0;
|
||||||
|
|
||||||
/// @brief Get number of audio channels
|
/// @brief Get number of audio channels
|
||||||
/// @return 1 if mono, 2 if stereo
|
/// @return 1 if mono, 2 if stereo
|
||||||
virtual uint getChannels() const=0;
|
virtual uint getChannels() const = 0;
|
||||||
|
|
||||||
/// @brief Get audio sampling frequency
|
/// @brief Get audio sampling frequency
|
||||||
/// @return number of mono samples per second
|
/// @return number of mono samples per second
|
||||||
virtual uint getSampleRate() const=0;
|
virtual uint getSampleRate() const = 0;
|
||||||
|
|
||||||
/// @brief Get number of bits per mono sample
|
/// @brief Get number of bits per mono sample
|
||||||
/// @return 8 or 16
|
/// @return 8 or 16
|
||||||
virtual uint getBitsPerSample() const=0;
|
virtual uint getBitsPerSample() const = 0;
|
||||||
|
|
||||||
/// @brief Check if the stream does support seek feature
|
/// @brief Check if the stream does support seek feature
|
||||||
virtual bool isSeekable() const=0;
|
virtual bool isSeekable() const = 0;
|
||||||
|
|
||||||
/// @brief Move playhead to the selected sample number
|
/// @brief Move playhead to the selected sample number
|
||||||
/// @param position selected sample number
|
/// @param position selected sample number
|
||||||
@ -179,7 +175,9 @@ namespace audio {
|
|||||||
/// @param loop is stream looped (required for correct buffers preload)
|
/// @param loop is stream looped (required for correct buffers preload)
|
||||||
/// @param channel channel index
|
/// @param channel channel index
|
||||||
/// @return speaker id or 0
|
/// @return speaker id or 0
|
||||||
virtual std::unique_ptr<Speaker> createSpeaker(bool loop, int channel) = 0;
|
virtual std::unique_ptr<Speaker> createSpeaker(
|
||||||
|
bool loop, int channel
|
||||||
|
) = 0;
|
||||||
|
|
||||||
/// @brief Unbind previous speaker and bind new speaker to the stream
|
/// @brief Unbind previous speaker and bind new speaker to the stream
|
||||||
/// @param speaker speaker id or 0 if all you need is unbind speaker
|
/// @param speaker speaker id or 0 if all you need is unbind speaker
|
||||||
@ -209,7 +207,8 @@ namespace audio {
|
|||||||
/// @brief Sound variants will be chosen randomly to play
|
/// @brief Sound variants will be chosen randomly to play
|
||||||
std::vector<std::shared_ptr<Sound>> variants;
|
std::vector<std::shared_ptr<Sound>> variants;
|
||||||
|
|
||||||
virtual ~Sound() {}
|
virtual ~Sound() {
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Get sound duration
|
/// @brief Get sound duration
|
||||||
/// @return duration in seconds (>= 0.0)
|
/// @return duration in seconds (>= 0.0)
|
||||||
@ -225,14 +224,16 @@ namespace audio {
|
|||||||
/// @param channel channel index
|
/// @param channel channel index
|
||||||
/// @return new speaker with sound bound or nullptr
|
/// @return new speaker with sound bound or nullptr
|
||||||
/// if all speakers are in use
|
/// if all speakers are in use
|
||||||
virtual std::unique_ptr<Speaker> newInstance(int priority, int channel) const = 0;
|
virtual std::unique_ptr<Speaker> newInstance(int priority, int channel)
|
||||||
|
const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Audio source controller interface.
|
/// @brief Audio source controller interface.
|
||||||
/// @attention Speaker is not supposed to be reused
|
/// @attention Speaker is not supposed to be reused
|
||||||
class Speaker {
|
class Speaker {
|
||||||
public:
|
public:
|
||||||
virtual ~Speaker() {}
|
virtual ~Speaker() {
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Synchronize the speaker with channel settings
|
/// @brief Synchronize the speaker with channel settings
|
||||||
/// @param channel speaker channel
|
/// @param channel speaker channel
|
||||||
@ -336,8 +337,12 @@ namespace audio {
|
|||||||
public:
|
public:
|
||||||
virtual ~Backend() {};
|
virtual ~Backend() {};
|
||||||
|
|
||||||
virtual std::unique_ptr<Sound> createSound(std::shared_ptr<PCM> pcm, bool keepPCM) = 0;
|
virtual std::unique_ptr<Sound> createSound(
|
||||||
virtual std::unique_ptr<Stream> openStream(std::shared_ptr<PCMStream> stream, bool keepSource) = 0;
|
std::shared_ptr<PCM> pcm, bool keepPCM
|
||||||
|
) = 0;
|
||||||
|
virtual std::unique_ptr<Stream> openStream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
) = 0;
|
||||||
virtual void setListener(
|
virtual void setListener(
|
||||||
glm::vec3 position,
|
glm::vec3 position,
|
||||||
glm::vec3 velocity,
|
glm::vec3 velocity,
|
||||||
@ -364,14 +369,16 @@ namespace audio {
|
|||||||
|
|
||||||
/// @brief Load sound from file
|
/// @brief Load sound from file
|
||||||
/// @param file audio file path
|
/// @param file audio file path
|
||||||
/// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM
|
/// @param keepPCM store PCM data in sound to make it accessible with
|
||||||
|
/// Sound::getPCM
|
||||||
/// @throws std::runtime_error if I/O error ocurred or format is unknown
|
/// @throws std::runtime_error if I/O error ocurred or format is unknown
|
||||||
/// @return new Sound instance
|
/// @return new Sound instance
|
||||||
std::unique_ptr<Sound> load_sound(const fs::path& file, bool keepPCM);
|
std::unique_ptr<Sound> load_sound(const fs::path& file, bool keepPCM);
|
||||||
|
|
||||||
/// @brief Create new sound from PCM data
|
/// @brief Create new sound from PCM data
|
||||||
/// @param pcm PCM data
|
/// @param pcm PCM data
|
||||||
/// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM
|
/// @param keepPCM store PCM data in sound to make it accessible with
|
||||||
|
/// Sound::getPCM
|
||||||
/// @return new Sound instance
|
/// @return new Sound instance
|
||||||
std::unique_ptr<Sound> create_sound(std::shared_ptr<PCM> pcm, bool keepPCM);
|
std::unique_ptr<Sound> create_sound(std::shared_ptr<PCM> pcm, bool keepPCM);
|
||||||
|
|
||||||
@ -383,15 +390,19 @@ namespace audio {
|
|||||||
|
|
||||||
/// @brief Open new audio stream from file
|
/// @brief Open new audio stream from file
|
||||||
/// @param file audio file path
|
/// @param file audio file path
|
||||||
/// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource
|
/// @param keepSource store PCMStream in stream to make it accessible with
|
||||||
|
/// Stream::getSource
|
||||||
/// @return new Stream instance
|
/// @return new Stream instance
|
||||||
std::unique_ptr<Stream> open_stream(const fs::path& file, bool keepSource);
|
std::unique_ptr<Stream> open_stream(const fs::path& file, bool keepSource);
|
||||||
|
|
||||||
/// @brief Open new audio stream from source
|
/// @brief Open new audio stream from source
|
||||||
/// @param stream PCM data source
|
/// @param stream PCM data source
|
||||||
/// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource
|
/// @param keepSource store PCMStream in stream to make it accessible with
|
||||||
|
/// Stream::getSource
|
||||||
/// @return new Stream instance
|
/// @return new Stream instance
|
||||||
std::unique_ptr<Stream> open_stream(std::shared_ptr<PCMStream> stream, bool keepSource);
|
std::unique_ptr<Stream> open_stream(
|
||||||
|
std::shared_ptr<PCMStream> stream, bool keepSource
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Configure 3D listener
|
/// @brief Configure 3D listener
|
||||||
/// @param position listener position
|
/// @param position listener position
|
||||||
@ -399,10 +410,7 @@ namespace audio {
|
|||||||
/// @param lookAt point the listener look at
|
/// @param lookAt point the listener look at
|
||||||
/// @param up camera up vector
|
/// @param up camera up vector
|
||||||
void set_listener(
|
void set_listener(
|
||||||
glm::vec3 position,
|
glm::vec3 position, glm::vec3 velocity, glm::vec3 lookAt, glm::vec3 up
|
||||||
glm::vec3 velocity,
|
|
||||||
glm::vec3 lookAt,
|
|
||||||
glm::vec3 up
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// @brief Play 3D sound in the world
|
/// @brief Play 3D sound in the world
|
||||||
@ -513,4 +521,4 @@ namespace audio {
|
|||||||
void close();
|
void close();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIO_AUDIO_HPP_
|
#endif // AUDIO_AUDIO_HPP_
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
#include "GLSLExtension.hpp"
|
#include "GLSLExtension.hpp"
|
||||||
|
|
||||||
#include "../util/stringutil.hpp"
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../files/files.hpp"
|
|
||||||
#include "../files/engine_paths.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../files/engine_paths.hpp"
|
||||||
|
#include "../files/files.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
void GLSLExtension::setVersion(std::string version) {
|
void GLSLExtension::setVersion(std::string version) {
|
||||||
@ -21,7 +21,7 @@ void GLSLExtension::setPaths(const ResPaths* paths) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GLSLExtension::loadHeader(const std::string& name) {
|
void GLSLExtension::loadHeader(const std::string& name) {
|
||||||
fs::path file = paths->find("shaders/lib/"+name+".glsl");
|
fs::path file = paths->find("shaders/lib/" + name + ".glsl");
|
||||||
std::string source = files::read_string(file);
|
std::string source = files::read_string(file);
|
||||||
addHeader(name, "");
|
addHeader(name, "");
|
||||||
addHeader(name, process(file, source, true));
|
addHeader(name, process(file, source, true));
|
||||||
@ -38,7 +38,7 @@ void GLSLExtension::define(const std::string& name, std::string value) {
|
|||||||
const std::string& GLSLExtension::getHeader(const std::string& name) const {
|
const std::string& GLSLExtension::getHeader(const std::string& name) const {
|
||||||
auto found = headers.find(name);
|
auto found = headers.find(name);
|
||||||
if (found == headers.end()) {
|
if (found == headers.end()) {
|
||||||
throw std::runtime_error("no header '"+name+"' loaded");
|
throw std::runtime_error("no header '" + name + "' loaded");
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ const std::string& GLSLExtension::getHeader(const std::string& name) const {
|
|||||||
const std::string& GLSLExtension::getDefine(const std::string& name) const {
|
const std::string& GLSLExtension::getDefine(const std::string& name) const {
|
||||||
auto found = defines.find(name);
|
auto found = defines.find(name);
|
||||||
if (found == defines.end()) {
|
if (found == defines.end()) {
|
||||||
throw std::runtime_error("name '"+name+"' is not defined");
|
throw std::runtime_error("name '" + name + "' is not defined");
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
@ -66,26 +66,29 @@ void GLSLExtension::undefine(const std::string& name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline std::runtime_error parsing_error(
|
inline std::runtime_error parsing_error(
|
||||||
const fs::path& file,
|
const fs::path& file, uint linenum, const std::string& message
|
||||||
uint linenum,
|
) {
|
||||||
const std::string& message) {
|
return std::runtime_error(
|
||||||
return std::runtime_error("file "+file.string()+": "+message+
|
"file " + file.string() + ": " + message + " at line " +
|
||||||
" at line "+std::to_string(linenum));
|
std::to_string(linenum)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void parsing_warning(
|
inline void parsing_warning(
|
||||||
const fs::path& file,
|
const fs::path& file, uint linenum, const std::string& message
|
||||||
uint linenum, const
|
) {
|
||||||
std::string& message) {
|
std::cerr << "file " + file.string() + ": warning: " + message +
|
||||||
std::cerr << "file "+file.string()+": warning: "+message+
|
" at line " + std::to_string(linenum)
|
||||||
" at line "+std::to_string(linenum) << std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void source_line(std::stringstream& ss, uint linenum) {
|
inline void source_line(std::stringstream& ss, uint linenum) {
|
||||||
ss << "#line " << linenum << "\n";
|
ss << "#line " << linenum << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GLSLExtension::process(const fs::path& file, const std::string& source, bool header) {
|
std::string GLSLExtension::process(
|
||||||
|
const fs::path& file, const std::string& source, bool header
|
||||||
|
) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
uint linenum = 1;
|
uint linenum = 1;
|
||||||
@ -103,27 +106,29 @@ std::string GLSLExtension::process(const fs::path& file, const std::string& sour
|
|||||||
}
|
}
|
||||||
// parsing preprocessor directives
|
// parsing preprocessor directives
|
||||||
if (source[pos] == '#') {
|
if (source[pos] == '#') {
|
||||||
std::string line = source.substr(pos+1, endline-pos);
|
std::string line = source.substr(pos + 1, endline - pos);
|
||||||
util::trim(line);
|
util::trim(line);
|
||||||
// parsing 'include' directive
|
// parsing 'include' directive
|
||||||
if (line.find("include") != std::string::npos) {
|
if (line.find("include") != std::string::npos) {
|
||||||
line = line.substr(7);
|
line = line.substr(7);
|
||||||
util::trim(line);
|
util::trim(line);
|
||||||
if (line.length() < 3) {
|
if (line.length() < 3) {
|
||||||
throw parsing_error(file, linenum,
|
throw parsing_error(
|
||||||
"invalid 'include' syntax");
|
file, linenum, "invalid 'include' syntax"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (line[0] != '<' || line[line.length()-1] != '>') {
|
if (line[0] != '<' || line[line.length() - 1] != '>') {
|
||||||
throw parsing_error(file, linenum,
|
throw parsing_error(
|
||||||
"expected '#include <filename>' syntax");
|
file, linenum, "expected '#include <filename>' syntax"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
std::string name = line.substr(1, line.length()-2);
|
std::string name = line.substr(1, line.length() - 2);
|
||||||
if (!hasHeader(name)) {
|
if (!hasHeader(name)) {
|
||||||
loadHeader(name);
|
loadHeader(name);
|
||||||
}
|
}
|
||||||
source_line(ss, 1);
|
source_line(ss, 1);
|
||||||
ss << getHeader(name) << '\n';
|
ss << getHeader(name) << '\n';
|
||||||
pos = endline+1;
|
pos = endline + 1;
|
||||||
linenum++;
|
linenum++;
|
||||||
source_line(ss, linenum);
|
source_line(ss, linenum);
|
||||||
continue;
|
continue;
|
||||||
@ -131,15 +136,15 @@ std::string GLSLExtension::process(const fs::path& file, const std::string& sour
|
|||||||
// removing extra 'include' directives
|
// removing extra 'include' directives
|
||||||
else if (line.find("version") != std::string::npos) {
|
else if (line.find("version") != std::string::npos) {
|
||||||
parsing_warning(file, linenum, "removed #version directive");
|
parsing_warning(file, linenum, "removed #version directive");
|
||||||
pos = endline+1;
|
pos = endline + 1;
|
||||||
linenum++;
|
linenum++;
|
||||||
source_line(ss, linenum);
|
source_line(ss, linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
linenum++;
|
linenum++;
|
||||||
ss << source.substr(pos, endline+1-pos);
|
ss << source.substr(pos, endline + 1 - pos);
|
||||||
pos = endline+1;
|
pos = endline + 1;
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#ifndef CODERS_GLSL_EXTESION_HPP_
|
#ifndef CODERS_GLSL_EXTESION_HPP_
|
||||||
#define CODERS_GLSL_EXTESION_HPP_
|
#define CODERS_GLSL_EXTESION_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class ResPaths;
|
class ResPaths;
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ public:
|
|||||||
std::string process(
|
std::string process(
|
||||||
const std::filesystem::path& file,
|
const std::filesystem::path& file,
|
||||||
const std::string& source,
|
const std::string& source,
|
||||||
bool header=false
|
bool header = false
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CODERS_GLSL_EXTESION_HPP_
|
#endif // CODERS_GLSL_EXTESION_HPP_
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#include "binary_json.hpp"
|
#include "binary_json.hpp"
|
||||||
|
|
||||||
#include "gzip.hpp"
|
|
||||||
#include "byte_utils.hpp"
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
#include "byte_utils.hpp"
|
||||||
|
#include "gzip.hpp"
|
||||||
|
|
||||||
using namespace json;
|
using namespace json;
|
||||||
using namespace dynamic;
|
using namespace dynamic;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ static void to_binary(ByteBuilder& builder, const Value& value) {
|
|||||||
if (val >= 0 && val <= 255) {
|
if (val >= 0 && val <= 255) {
|
||||||
builder.put(BJSON_TYPE_BYTE);
|
builder.put(BJSON_TYPE_BYTE);
|
||||||
builder.put(val);
|
builder.put(val);
|
||||||
} else if (val >= INT16_MIN && val <= INT16_MAX){
|
} else if (val >= INT16_MIN && val <= INT16_MAX) {
|
||||||
builder.put(BJSON_TYPE_INT16);
|
builder.put(BJSON_TYPE_INT16);
|
||||||
builder.putInt16(val);
|
builder.putInt16(val);
|
||||||
} else if (val >= INT32_MIN && val <= INT32_MAX) {
|
} else if (val >= INT32_MIN && val <= INT32_MAX) {
|
||||||
@ -115,7 +115,7 @@ static Value value_from_binary(ByteReader& reader) {
|
|||||||
return reader.getString();
|
return reader.getString();
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"type "+std::to_string(typecode)+" is not supported"
|
"type " + std::to_string(typecode) + " is not supported"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#ifndef CODERS_BINARY_JSON_HPP_
|
#ifndef CODERS_BINARY_JSON_HPP_
|
||||||
#define CODERS_BINARY_JSON_HPP_
|
#define CODERS_BINARY_JSON_HPP_
|
||||||
|
|
||||||
#include "../data/dynamic_fwd.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../data/dynamic_fwd.hpp"
|
||||||
|
|
||||||
namespace dynamic {
|
namespace dynamic {
|
||||||
class Map;
|
class Map;
|
||||||
@ -26,9 +26,13 @@ namespace json {
|
|||||||
inline constexpr int BJSON_TYPE_NULL = 0xC;
|
inline constexpr int BJSON_TYPE_NULL = 0xC;
|
||||||
inline constexpr int BJSON_TYPE_CDOCUMENT = 0x1F;
|
inline constexpr int BJSON_TYPE_CDOCUMENT = 0x1F;
|
||||||
|
|
||||||
std::vector<ubyte> to_binary(const dynamic::Map* obj, bool compress=false);
|
std::vector<ubyte> to_binary(
|
||||||
std::vector<ubyte> to_binary(const dynamic::Value& obj, bool compress=false);
|
const dynamic::Map* obj, bool compress = false
|
||||||
|
);
|
||||||
|
std::vector<ubyte> to_binary(
|
||||||
|
const dynamic::Value& obj, bool compress = false
|
||||||
|
);
|
||||||
std::shared_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size);
|
std::shared_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_BINARY_JSON_HPP_
|
#endif // CODERS_BINARY_JSON_HPP_
|
||||||
|
|||||||
@ -9,7 +9,7 @@ void ByteBuilder::put(ubyte b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ByteBuilder::putCStr(const char* str) {
|
void ByteBuilder::putCStr(const char* str) {
|
||||||
size_t size = strlen(str)+1;
|
size_t size = strlen(str) + 1;
|
||||||
buffer.reserve(buffer.size() + size);
|
buffer.reserve(buffer.size() + size);
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
buffer.push_back(str[i]);
|
buffer.push_back(str[i]);
|
||||||
@ -37,21 +37,21 @@ void ByteBuilder::putInt16(int16_t val) {
|
|||||||
void ByteBuilder::putInt32(int32_t val) {
|
void ByteBuilder::putInt32(int32_t val) {
|
||||||
buffer.reserve(buffer.size() + 4);
|
buffer.reserve(buffer.size() + 4);
|
||||||
buffer.push_back(static_cast<ubyte>(val >> 0 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 0 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 8 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 8 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 16 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 16 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 24 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 24 & 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteBuilder::putInt64(int64_t val) {
|
void ByteBuilder::putInt64(int64_t val) {
|
||||||
buffer.reserve(buffer.size() + 8);
|
buffer.reserve(buffer.size() + 8);
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 0 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 0 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 8 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 8 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 16 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 16 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 24 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 24 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 32 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 32 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 40 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 40 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 48 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 48 & 255));
|
||||||
buffer.push_back(static_cast<ubyte> (val >> 56 & 255));
|
buffer.push_back(static_cast<ubyte>(val >> 56 & 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteBuilder::putFloat32(float val) {
|
void ByteBuilder::putFloat32(float val) {
|
||||||
@ -102,8 +102,7 @@ ByteReader::ByteReader(const ubyte* data, size_t size)
|
|||||||
: data(data), size(size), pos(0) {
|
: data(data), size(size), pos(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteReader::ByteReader(const ubyte* data)
|
ByteReader::ByteReader(const ubyte* data) : data(data), size(4), pos(0) {
|
||||||
: data(data), size(4), pos(0) {
|
|
||||||
size = getInt32();
|
size = getInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +111,7 @@ void ByteReader::checkMagic(const char* data, size_t size) {
|
|||||||
throw std::runtime_error("invalid magic number");
|
throw std::runtime_error("invalid magic number");
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
if (this->data[pos + i] != (ubyte)data[i]){
|
if (this->data[pos + i] != (ubyte)data[i]) {
|
||||||
throw std::runtime_error("invalid magic number");
|
throw std::runtime_error("invalid magic number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +133,7 @@ ubyte ByteReader::peek() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int16_t ByteReader::getInt16() {
|
int16_t ByteReader::getInt16() {
|
||||||
if (pos+2 > size) {
|
if (pos + 2 > size) {
|
||||||
throw std::runtime_error("buffer underflow");
|
throw std::runtime_error("buffer underflow");
|
||||||
}
|
}
|
||||||
pos += 2;
|
pos += 2;
|
||||||
@ -143,7 +142,7 @@ int16_t ByteReader::getInt16() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t ByteReader::getInt32() {
|
int32_t ByteReader::getInt32() {
|
||||||
if (pos+4 > size) {
|
if (pos + 4 > size) {
|
||||||
throw std::runtime_error("buffer underflow");
|
throw std::runtime_error("buffer underflow");
|
||||||
}
|
}
|
||||||
pos += 4;
|
pos += 4;
|
||||||
@ -154,7 +153,7 @@ int32_t ByteReader::getInt32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t ByteReader::getInt64() {
|
int64_t ByteReader::getInt64() {
|
||||||
if (pos+8 > size) {
|
if (pos + 8 > size) {
|
||||||
throw std::runtime_error("buffer underflow");
|
throw std::runtime_error("buffer underflow");
|
||||||
}
|
}
|
||||||
pos += 8;
|
pos += 8;
|
||||||
@ -183,18 +182,20 @@ double ByteReader::getFloat64() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* ByteReader::getCString() {
|
const char* ByteReader::getCString() {
|
||||||
const char* cstr = reinterpret_cast<const char*>(data+pos);
|
const char* cstr = reinterpret_cast<const char*>(data + pos);
|
||||||
pos += strlen(cstr) + 1;
|
pos += strlen(cstr) + 1;
|
||||||
return cstr;
|
return cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ByteReader::getString() {
|
std::string ByteReader::getString() {
|
||||||
uint32_t length = (uint32_t)getInt32();
|
uint32_t length = (uint32_t)getInt32();
|
||||||
if (pos+length > size) {
|
if (pos + length > size) {
|
||||||
throw std::runtime_error("buffer underflow");
|
throw std::runtime_error("buffer underflow");
|
||||||
}
|
}
|
||||||
pos += length;
|
pos += length;
|
||||||
return std::string(reinterpret_cast<const char*>(data+pos-length), length);
|
return std::string(
|
||||||
|
reinterpret_cast<const char*>(data + pos - length), length
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ByteReader::hasNext() const {
|
bool ByteReader::hasNext() const {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#ifndef CODERS_BYTE_UTILS_HPP_
|
#ifndef CODERS_BYTE_UTILS_HPP_
|
||||||
#define CODERS_BYTE_UTILS_HPP_
|
#define CODERS_BYTE_UTILS_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
/* byteorder: little-endian */
|
/* byteorder: little-endian */
|
||||||
class ByteBuilder {
|
class ByteBuilder {
|
||||||
std::vector<ubyte> buffer;
|
std::vector<ubyte> buffer;
|
||||||
@ -80,4 +80,4 @@ public:
|
|||||||
void skip(size_t n);
|
void skip(size_t n);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CODERS_BYTE_UTILS_HPP_
|
#endif // CODERS_BYTE_UTILS_HPP_
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
|
|
||||||
#include "../util/stringutil.hpp"
|
#include <math.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <math.h>
|
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
inline double power(double base, int64_t power) {
|
inline double power(double base, int64_t power) {
|
||||||
double result = 1.0;
|
double result = 1.0;
|
||||||
@ -21,21 +22,25 @@ parsing_error::parsing_error(
|
|||||||
uint pos,
|
uint pos,
|
||||||
uint line,
|
uint line,
|
||||||
uint linestart
|
uint linestart
|
||||||
) : std::runtime_error(message), filename(filename),
|
)
|
||||||
pos(pos), line(line), linestart(linestart)
|
: std::runtime_error(message),
|
||||||
{
|
filename(filename),
|
||||||
|
pos(pos),
|
||||||
|
line(line),
|
||||||
|
linestart(linestart) {
|
||||||
size_t end = source.find("\n", linestart);
|
size_t end = source.find("\n", linestart);
|
||||||
if (end == std::string::npos) {
|
if (end == std::string::npos) {
|
||||||
end = source.length();
|
end = source.length();
|
||||||
}
|
}
|
||||||
this->source = source.substr(linestart, end-linestart);
|
this->source = source.substr(linestart, end - linestart);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string parsing_error::errorLog() const {
|
std::string parsing_error::errorLog() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
uint linepos = pos - linestart;
|
uint linepos = pos - linestart;
|
||||||
ss << "parsing error in file '" << filename;
|
ss << "parsing error in file '" << filename;
|
||||||
ss << "' at " << (line+1) << ":" << linepos << ": " << this->what() << "\n";
|
ss << "' at " << (line + 1) << ":" << linepos << ": " << this->what()
|
||||||
|
<< "\n";
|
||||||
ss << source << "\n";
|
ss << source << "\n";
|
||||||
for (uint i = 0; i < linepos; i++) {
|
for (uint i = 0; i < linepos; i++) {
|
||||||
ss << " ";
|
ss << " ";
|
||||||
@ -44,10 +49,8 @@ std::string parsing_error::errorLog() const {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicParser::BasicParser(
|
BasicParser::BasicParser(std::string_view file, std::string_view source)
|
||||||
std::string_view file,
|
: filename(file), source(source) {
|
||||||
std::string_view source
|
|
||||||
) : filename(file), source(source) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasicParser::skipWhitespace() {
|
void BasicParser::skipWhitespace() {
|
||||||
@ -67,7 +70,7 @@ void BasicParser::skipWhitespace() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BasicParser::skip(size_t n) {
|
void BasicParser::skip(size_t n) {
|
||||||
n = std::min(n, source.length()-pos);
|
n = std::min(n, source.length() - pos);
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
char next = source[pos++];
|
char next = source[pos++];
|
||||||
@ -93,10 +96,10 @@ void BasicParser::skipLine() {
|
|||||||
bool BasicParser::skipTo(const std::string& substring) {
|
bool BasicParser::skipTo(const std::string& substring) {
|
||||||
size_t idx = source.find(substring, pos);
|
size_t idx = source.find(substring, pos);
|
||||||
if (idx == std::string::npos) {
|
if (idx == std::string::npos) {
|
||||||
skip(source.length()-pos);
|
skip(source.length() - pos);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
skip(idx-pos);
|
skip(idx - pos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,17 +125,16 @@ char BasicParser::nextChar() {
|
|||||||
void BasicParser::expect(char expected) {
|
void BasicParser::expect(char expected) {
|
||||||
char c = peek();
|
char c = peek();
|
||||||
if (c != expected) {
|
if (c != expected) {
|
||||||
throw error("'"+std::string({expected})+"' expected");
|
throw error("'" + std::string({expected}) + "' expected");
|
||||||
}
|
}
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasicParser::expect(const std::string& substring) {
|
void BasicParser::expect(const std::string& substring) {
|
||||||
if (substring.empty())
|
if (substring.empty()) return;
|
||||||
return;
|
|
||||||
for (uint i = 0; i < substring.length(); i++) {
|
for (uint i = 0; i < substring.length(); i++) {
|
||||||
if (source.length() <= pos + i || source[pos+i] != substring[i]) {
|
if (source.length() <= pos + i || source[pos + i] != substring[i]) {
|
||||||
throw error(util::quote(substring)+" expected");
|
throw error(util::quote(substring) + " expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos += substring.length();
|
pos += substring.length();
|
||||||
@ -205,7 +207,7 @@ std::string_view BasicParser::readUntil(char c) {
|
|||||||
while (hasNext() && source[pos] != c) {
|
while (hasNext() && source[pos] != c) {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return source.substr(start, pos-start);
|
return source.substr(start, pos - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view BasicParser::readUntilEOL() {
|
std::string_view BasicParser::readUntilEOL() {
|
||||||
@ -213,7 +215,7 @@ std::string_view BasicParser::readUntilEOL() {
|
|||||||
while (hasNext() && source[pos] != '\r' && source[pos] != '\n') {
|
while (hasNext() && source[pos] != '\r' && source[pos] != '\n') {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return source.substr(start, pos-start);
|
return source.substr(start, pos - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BasicParser::parseName() {
|
std::string BasicParser::parseName() {
|
||||||
@ -229,7 +231,7 @@ std::string BasicParser::parseName() {
|
|||||||
while (hasNext() && is_identifier_part(source[pos])) {
|
while (hasNext() && is_identifier_part(source[pos])) {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return std::string(source.substr(start, pos-start));
|
return std::string(source.substr(start, pos - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t BasicParser::parseSimpleInt(int base) {
|
int64_t BasicParser::parseSimpleInt(int base) {
|
||||||
@ -273,13 +275,13 @@ dynamic::Value BasicParser::parseNumber(int sign) {
|
|||||||
char c = peek();
|
char c = peek();
|
||||||
int base = 10;
|
int base = 10;
|
||||||
if (c == '0' && pos + 1 < source.length() &&
|
if (c == '0' && pos + 1 < source.length() &&
|
||||||
(base = is_box(source[pos+1])) != 10) {
|
(base = is_box(source[pos + 1])) != 10) {
|
||||||
pos += 2;
|
pos += 2;
|
||||||
return parseSimpleInt(base);
|
return parseSimpleInt(base);
|
||||||
} else if (c == 'i' && pos + 2 < source.length() && source[pos+1] == 'n' && source[pos+2] == 'f') {
|
} else if (c == 'i' && pos + 2 < source.length() && source[pos + 1] == 'n' && source[pos + 2] == 'f') {
|
||||||
pos += 3;
|
pos += 3;
|
||||||
return INFINITY * sign;
|
return INFINITY * sign;
|
||||||
} else if (c == 'n' && pos + 2 < source.length() && source[pos+1] == 'a' && source[pos+2] == 'n') {
|
} else if (c == 'n' && pos + 2 < source.length() && source[pos + 1] == 'a' && source[pos + 2] == 'n') {
|
||||||
pos += 3;
|
pos += 3;
|
||||||
return NAN * sign;
|
return NAN * sign;
|
||||||
}
|
}
|
||||||
@ -294,7 +296,7 @@ dynamic::Value BasicParser::parseNumber(int sign) {
|
|||||||
if (peek() == '-') {
|
if (peek() == '-') {
|
||||||
s = -1;
|
s = -1;
|
||||||
pos++;
|
pos++;
|
||||||
} else if (peek() == '+'){
|
} else if (peek() == '+') {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return sign * value * power(10.0, s * parseSimpleInt(10));
|
return sign * value * power(10.0, s * parseSimpleInt(10));
|
||||||
@ -320,7 +322,7 @@ dynamic::Value BasicParser::parseNumber(int sign) {
|
|||||||
if (peek() == '-') {
|
if (peek() == '-') {
|
||||||
s = -1;
|
s = -1;
|
||||||
pos++;
|
pos++;
|
||||||
} else if (peek() == '+'){
|
} else if (peek() == '+') {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return sign * dvalue * power(10.0, s * parseSimpleInt(10));
|
return sign * dvalue * power(10.0, s * parseSimpleInt(10));
|
||||||
@ -347,19 +349,40 @@ std::string BasicParser::parseString(char quote, bool closeRequired) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'n': ss << '\n'; break;
|
case 'n':
|
||||||
case 'r': ss << '\r'; break;
|
ss << '\n';
|
||||||
case 'b': ss << '\b'; break;
|
break;
|
||||||
case 't': ss << '\t'; break;
|
case 'r':
|
||||||
case 'f': ss << '\f'; break;
|
ss << '\r';
|
||||||
case '\'': ss << '\\'; break;
|
break;
|
||||||
case '"': ss << '"'; break;
|
case 'b':
|
||||||
case '\\': ss << '\\'; break;
|
ss << '\b';
|
||||||
case '/': ss << '/'; break;
|
break;
|
||||||
case '\n': pos++; continue;
|
case 't':
|
||||||
|
ss << '\t';
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
ss << '\f';
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
ss << '\\';
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
ss << '"';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
ss << '\\';
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
ss << '/';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
default:
|
default:
|
||||||
throw error("'\\" + std::string({c}) +
|
throw error(
|
||||||
"' is an illegal escape");
|
"'\\" + std::string({c}) + "' is an illegal escape"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef CODERS_COMMONS_HPP_
|
#ifndef CODERS_COMMONS_HPP_
|
||||||
#define CODERS_COMMONS_HPP_
|
#define CODERS_COMMONS_HPP_
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
inline int is_box(int c) {
|
inline int is_box(int c) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'B':
|
case 'B':
|
||||||
@ -31,7 +31,8 @@ inline bool is_whitespace(int c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_identifier_start(int c) {
|
inline bool is_identifier_start(int c) {
|
||||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || c == '.';
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' ||
|
||||||
|
c == '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_identifier_part(int c) {
|
inline bool is_identifier_part(int c) {
|
||||||
@ -86,16 +87,15 @@ protected:
|
|||||||
void expect(const std::string& substring);
|
void expect(const std::string& substring);
|
||||||
bool isNext(const std::string& substring);
|
bool isNext(const std::string& substring);
|
||||||
void expectNewLine();
|
void expectNewLine();
|
||||||
void goBack(size_t count=1);
|
void goBack(size_t count = 1);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
int64_t parseSimpleInt(int base);
|
int64_t parseSimpleInt(int base);
|
||||||
dynamic::Value parseNumber(int sign);
|
dynamic::Value parseNumber(int sign);
|
||||||
dynamic::Value parseNumber();
|
dynamic::Value parseNumber();
|
||||||
std::string parseString(char chr, bool closeRequired=true);
|
std::string parseString(char chr, bool closeRequired = true);
|
||||||
|
|
||||||
parsing_error error(const std::string& message);
|
parsing_error error(const std::string& message);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string_view readUntil(char c);
|
std::string_view readUntil(char c);
|
||||||
std::string_view readUntilEOL();
|
std::string_view readUntilEOL();
|
||||||
@ -109,4 +109,4 @@ public:
|
|||||||
BasicParser(std::string_view file, std::string_view source);
|
BasicParser(std::string_view file, std::string_view source);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CODERS_COMMONS_HPP_
|
#endif // CODERS_COMMONS_HPP_
|
||||||
|
|||||||
@ -3,12 +3,13 @@
|
|||||||
#include "byte_utils.hpp"
|
#include "byte_utils.hpp"
|
||||||
|
|
||||||
#define ZLIB_CONST
|
#define ZLIB_CONST
|
||||||
#include <zlib.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
|
std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
|
||||||
size_t buffer_size = 23+size*1.01;
|
size_t buffer_size = 23 + size * 1.01;
|
||||||
std::vector<ubyte> buffer;
|
std::vector<ubyte> buffer;
|
||||||
buffer.resize(buffer_size);
|
buffer.resize(buffer_size);
|
||||||
|
|
||||||
@ -23,8 +24,14 @@ std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
|
|||||||
defstream.next_out = buffer.data();
|
defstream.next_out = buffer.data();
|
||||||
|
|
||||||
// compression
|
// compression
|
||||||
deflateInit2(&defstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
deflateInit2(
|
||||||
16 + MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
|
&defstream,
|
||||||
|
Z_DEFAULT_COMPRESSION,
|
||||||
|
Z_DEFLATED,
|
||||||
|
16 + MAX_WBITS,
|
||||||
|
8,
|
||||||
|
Z_DEFAULT_STRATEGY
|
||||||
|
);
|
||||||
deflate(&defstream, Z_FINISH);
|
deflate(&defstream, Z_FINISH);
|
||||||
deflateEnd(&defstream);
|
deflateEnd(&defstream);
|
||||||
|
|
||||||
@ -35,7 +42,8 @@ std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
|
|||||||
|
|
||||||
std::vector<ubyte> gzip::decompress(const ubyte* src, size_t size) {
|
std::vector<ubyte> gzip::decompress(const ubyte* src, size_t size) {
|
||||||
// getting uncompressed data length from gzip footer
|
// getting uncompressed data length from gzip footer
|
||||||
size_t decompressed_size = *reinterpret_cast<const uint32_t*>(src+size-4);
|
size_t decompressed_size =
|
||||||
|
*reinterpret_cast<const uint32_t*>(src + size - 4);
|
||||||
std::vector<ubyte> buffer;
|
std::vector<ubyte> buffer;
|
||||||
buffer.resize(decompressed_size);
|
buffer.resize(decompressed_size);
|
||||||
|
|
||||||
@ -49,7 +57,7 @@ std::vector<ubyte> gzip::decompress(const ubyte* src, size_t size) {
|
|||||||
infstream.avail_out = decompressed_size;
|
infstream.avail_out = decompressed_size;
|
||||||
infstream.next_out = buffer.data();
|
infstream.next_out = buffer.data();
|
||||||
|
|
||||||
inflateInit2(&infstream, 16+MAX_WBITS);
|
inflateInit2(&infstream, 16 + MAX_WBITS);
|
||||||
inflate(&infstream, Z_NO_FLUSH);
|
inflate(&infstream, Z_NO_FLUSH);
|
||||||
inflateEnd(&infstream);
|
inflateEnd(&infstream);
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
#ifndef CODERS_GZIP_HPP_
|
#ifndef CODERS_GZIP_HPP_
|
||||||
#define CODERS_GZIP_HPP_
|
#define CODERS_GZIP_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
namespace gzip {
|
namespace gzip {
|
||||||
const unsigned char MAGIC[] = "\x1F\x8B";
|
const unsigned char MAGIC[] = "\x1F\x8B";
|
||||||
|
|
||||||
@ -18,4 +19,4 @@ namespace gzip {
|
|||||||
std::vector<ubyte> decompress(const ubyte* src, size_t size);
|
std::vector<ubyte> decompress(const ubyte* src, size_t size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_GZIP_HPP_
|
#endif // CODERS_GZIP_HPP_
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
#include "imageio.hpp"
|
#include "imageio.hpp"
|
||||||
|
|
||||||
#include "png.hpp"
|
|
||||||
#include "../graphics/core/ImageData.hpp"
|
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "../graphics/core/ImageData.hpp"
|
||||||
|
#include "png.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
using image_reader = std::function<std::unique_ptr<ImageData>(const std::string&)>;
|
using image_reader =
|
||||||
|
std::function<std::unique_ptr<ImageData>(const std::string&)>;
|
||||||
using image_writer = std::function<void(const std::string&, const ImageData*)>;
|
using image_writer = std::function<void(const std::string&, const ImageData*)>;
|
||||||
|
|
||||||
static std::unordered_map<std::string, image_reader> readers {
|
static std::unordered_map<std::string, image_reader> readers {
|
||||||
@ -35,7 +36,9 @@ inline std::string extensionOf(const std::string& filename) {
|
|||||||
std::unique_ptr<ImageData> imageio::read(const std::string& filename) {
|
std::unique_ptr<ImageData> imageio::read(const std::string& filename) {
|
||||||
auto found = readers.find(extensionOf(filename));
|
auto found = readers.find(extensionOf(filename));
|
||||||
if (found == readers.end()) {
|
if (found == readers.end()) {
|
||||||
throw std::runtime_error("file format is not supported (read): "+filename);
|
throw std::runtime_error(
|
||||||
|
"file format is not supported (read): " + filename
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return std::unique_ptr<ImageData>(found->second(filename));
|
return std::unique_ptr<ImageData>(found->second(filename));
|
||||||
}
|
}
|
||||||
@ -43,7 +46,9 @@ std::unique_ptr<ImageData> imageio::read(const std::string& filename) {
|
|||||||
void imageio::write(const std::string& filename, const ImageData* image) {
|
void imageio::write(const std::string& filename, const ImageData* image) {
|
||||||
auto found = writers.find(extensionOf(filename));
|
auto found = writers.find(extensionOf(filename));
|
||||||
if (found == writers.end()) {
|
if (found == writers.end()) {
|
||||||
throw std::runtime_error("file format is not supported (write): "+filename);
|
throw std::runtime_error(
|
||||||
|
"file format is not supported (write): " + filename
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return found->second(filename, image);
|
return found->second(filename, image);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#ifndef CODERS_IMAGEIO_HPP_
|
#ifndef CODERS_IMAGEIO_HPP_
|
||||||
#define CODERS_IMAGEIO_HPP_
|
#define CODERS_IMAGEIO_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class ImageData;
|
class ImageData;
|
||||||
|
|
||||||
@ -16,4 +16,4 @@ namespace imageio {
|
|||||||
void write(const std::string& filename, const ImageData* image);
|
void write(const std::string& filename, const ImageData* image);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_IMAGEIO_HPP_
|
#endif // CODERS_IMAGEIO_HPP_
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../util/stringutil.hpp"
|
#include "../util/stringutil.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
#include <math.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace json;
|
using namespace json;
|
||||||
using namespace dynamic;
|
using namespace dynamic;
|
||||||
@ -24,9 +24,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline void newline(
|
inline void newline(
|
||||||
std::stringstream& ss,
|
std::stringstream& ss, bool nice, uint indent, const std::string& indentstr
|
||||||
bool nice, uint indent,
|
|
||||||
const std::string& indentstr
|
|
||||||
) {
|
) {
|
||||||
if (nice) {
|
if (nice) {
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
@ -55,8 +53,7 @@ void stringifyValue(
|
|||||||
) {
|
) {
|
||||||
if (auto map = std::get_if<Map_sptr>(&value)) {
|
if (auto map = std::get_if<Map_sptr>(&value)) {
|
||||||
stringifyObj(map->get(), ss, indent, indentstr, nice);
|
stringifyObj(map->get(), ss, indent, indentstr, nice);
|
||||||
}
|
} else if (auto listptr = std::get_if<List_sptr>(&value)) {
|
||||||
else if (auto listptr = std::get_if<List_sptr>(&value)) {
|
|
||||||
auto list = *listptr;
|
auto list = *listptr;
|
||||||
if (list->size() == 0) {
|
if (list->size() == 0) {
|
||||||
ss << "[]";
|
ss << "[]";
|
||||||
@ -68,7 +65,7 @@ void stringifyValue(
|
|||||||
if (i > 0 || nice) {
|
if (i > 0 || nice) {
|
||||||
newline(ss, nice, indent, indentstr);
|
newline(ss, nice, indent, indentstr);
|
||||||
}
|
}
|
||||||
stringifyValue(value, ss, indent+1, indentstr, nice);
|
stringifyValue(value, ss, indent + 1, indentstr, nice);
|
||||||
if (i + 1 < list->size()) {
|
if (i + 1 < list->size()) {
|
||||||
ss << ',';
|
ss << ',';
|
||||||
}
|
}
|
||||||
@ -114,22 +111,20 @@ void stringifyObj(
|
|||||||
}
|
}
|
||||||
const Value& value = entry.second;
|
const Value& value = entry.second;
|
||||||
ss << util::escape(key) << ": ";
|
ss << util::escape(key) << ": ";
|
||||||
stringifyValue(value, ss, indent+1, indentstr, nice);
|
stringifyValue(value, ss, indent + 1, indentstr, nice);
|
||||||
index++;
|
index++;
|
||||||
if (index < obj->values.size()) {
|
if (index < obj->values.size()) {
|
||||||
ss << ',';
|
ss << ',';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nice) {
|
if (nice) {
|
||||||
newline(ss, true, indent-1, indentstr);
|
newline(ss, true, indent - 1, indentstr);
|
||||||
}
|
}
|
||||||
ss << '}';
|
ss << '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string json::stringify(
|
std::string json::stringify(
|
||||||
const Map* obj,
|
const Map* obj, bool nice, const std::string& indent
|
||||||
bool nice,
|
|
||||||
const std::string& indent
|
|
||||||
) {
|
) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
stringifyObj(obj, ss, 1, indent, nice);
|
stringifyObj(obj, ss, 1, indent, nice);
|
||||||
@ -137,9 +132,7 @@ std::string json::stringify(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string json::stringify(
|
std::string json::stringify(
|
||||||
const dynamic::Value& value,
|
const dynamic::Value& value, bool nice, const std::string& indent
|
||||||
bool nice,
|
|
||||||
const std::string& indent
|
|
||||||
) {
|
) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
stringifyValue(value, ss, 1, indent, nice);
|
stringifyValue(value, ss, 1, indent, nice);
|
||||||
@ -239,10 +232,12 @@ Value Parser::parseValue() {
|
|||||||
pos++;
|
pos++;
|
||||||
return parseString(next);
|
return parseString(next);
|
||||||
}
|
}
|
||||||
throw error("unexpected character '"+std::string({next})+"'");
|
throw error("unexpected character '" + std::string({next}) + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic::Map_sptr json::parse(std::string_view filename, std::string_view source) {
|
dynamic::Map_sptr json::parse(
|
||||||
|
std::string_view filename, std::string_view source
|
||||||
|
) {
|
||||||
Parser parser(filename, source);
|
Parser parser(filename, source);
|
||||||
return parser.parse();
|
return parser.parse();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +1,23 @@
|
|||||||
#ifndef CODERS_JSON_HPP_
|
#ifndef CODERS_JSON_HPP_
|
||||||
#define CODERS_JSON_HPP_
|
#define CODERS_JSON_HPP_
|
||||||
|
|
||||||
#include "binary_json.hpp"
|
#include <string>
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
#include "binary_json.hpp"
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace json {
|
namespace json {
|
||||||
dynamic::Map_sptr parse(std::string_view filename, std::string_view source);
|
dynamic::Map_sptr parse(std::string_view filename, std::string_view source);
|
||||||
dynamic::Map_sptr parse(std::string_view source);
|
dynamic::Map_sptr parse(std::string_view source);
|
||||||
|
|
||||||
std::string stringify(
|
std::string stringify(
|
||||||
const dynamic::Map* obj,
|
const dynamic::Map* obj, bool nice, const std::string& indent
|
||||||
bool nice,
|
|
||||||
const std::string& indent
|
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string stringify(
|
std::string stringify(
|
||||||
const dynamic::Value& value,
|
const dynamic::Value& value, bool nice, const std::string& indent
|
||||||
bool nice,
|
|
||||||
const std::string& indent
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_JSON_HPP_
|
#endif // CODERS_JSON_HPP_
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "obj.hpp"
|
#include "obj.hpp"
|
||||||
|
|
||||||
#include "commons.hpp"
|
|
||||||
#include "../graphics/core/Model.hpp"
|
#include "../graphics/core/Model.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
using namespace model;
|
using namespace model;
|
||||||
|
|
||||||
@ -34,8 +34,7 @@ class ObjParser : BasicParser {
|
|||||||
} while (peekInLine() != '\n' && ++i < 3);
|
} while (peekInLine() != '\n' && ++i < 3);
|
||||||
|
|
||||||
vertices.push_back(Vertex {
|
vertices.push_back(Vertex {
|
||||||
coords[indices[0]], uvs[indices[1]], normals[indices[2]]
|
coords[indices[0]], uvs[indices[1]], normals[indices[2]]});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peekInLine() != '\n' && hasNext()) {
|
if (peekInLine() != '\n' && hasNext()) {
|
||||||
@ -51,7 +50,8 @@ class ObjParser : BasicParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ObjParser(const std::string_view file, const std::string_view src) : BasicParser(file, src) {
|
ObjParser(const std::string_view file, const std::string_view src)
|
||||||
|
: BasicParser(file, src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Model> parse() {
|
std::unique_ptr<Model> parse() {
|
||||||
@ -111,7 +111,7 @@ public:
|
|||||||
}
|
}
|
||||||
skipLine();
|
skipLine();
|
||||||
}
|
}
|
||||||
} while(hasNext());
|
} while (hasNext());
|
||||||
model->clean();
|
model->clean();
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#ifndef CODERS_OBJ_HPP_
|
#ifndef CODERS_OBJ_HPP_
|
||||||
#define CODERS_OBJ_HPP_
|
#define CODERS_OBJ_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
/// Wavefont OBJ files parser
|
/// Wavefont OBJ files parser
|
||||||
|
|
||||||
@ -16,4 +16,4 @@ namespace obj {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_OBJ_HPP_
|
#endif // CODERS_OBJ_HPP_
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
#include "ogg.hpp"
|
#include "ogg.hpp"
|
||||||
|
|
||||||
#include "../debug/Logger.hpp"
|
|
||||||
#include "../audio/audio.hpp"
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vorbis/codec.h>
|
#include <vorbis/codec.h>
|
||||||
#include <vorbis/vorbisfile.h>
|
#include <vorbis/vorbisfile.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../audio/audio.hpp"
|
||||||
|
#include "../debug/Logger.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("ogg");
|
static debug::Logger logger("ogg");
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@ -15,13 +16,20 @@ using namespace audio;
|
|||||||
|
|
||||||
static inline std::string vorbis_error_message(int code) {
|
static inline std::string vorbis_error_message(int code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0: return "no error";
|
case 0:
|
||||||
case OV_EREAD: return "a read from media returned an error";
|
return "no error";
|
||||||
case OV_ENOTVORBIS: return "the given file/data was not recognized as Ogg Vorbis data";
|
case OV_EREAD:
|
||||||
case OV_EVERSION: return "vorbis version mismatch";
|
return "a read from media returned an error";
|
||||||
case OV_EBADHEADER: return "invalid Vorbis bitstream header";
|
case OV_ENOTVORBIS:
|
||||||
case OV_EFAULT: return "internal logic fault";
|
return "the given file/data was not recognized as Ogg Vorbis data";
|
||||||
case OV_EINVAL: return "invalid read operation";
|
case OV_EVERSION:
|
||||||
|
return "vorbis version mismatch";
|
||||||
|
case OV_EBADHEADER:
|
||||||
|
return "invalid Vorbis bitstream header";
|
||||||
|
case OV_EFAULT:
|
||||||
|
return "internal logic fault";
|
||||||
|
case OV_EINVAL:
|
||||||
|
return "invalid read operation";
|
||||||
case OV_EBADLINK:
|
case OV_EBADLINK:
|
||||||
return "the given link exists in the Vorbis data stream,"
|
return "the given link exists in the Vorbis data stream,"
|
||||||
" but is not decipherable due to garbacge or corruption";
|
" but is not decipherable due to garbacge or corruption";
|
||||||
@ -30,15 +38,17 @@ static inline std::string vorbis_error_message(int code) {
|
|||||||
case OV_EIMPL:
|
case OV_EIMPL:
|
||||||
return "feature not implemented";
|
return "feature not implemented";
|
||||||
default:
|
default:
|
||||||
return "unknown error ["+std::to_string(code)+"]";
|
return "unknown error [" + std::to_string(code) + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<audio::PCM> ogg::load_pcm(const fs::path& file, bool headerOnly) {
|
std::unique_ptr<audio::PCM> ogg::load_pcm(
|
||||||
|
const fs::path& file, bool headerOnly
|
||||||
|
) {
|
||||||
OggVorbis_File vf;
|
OggVorbis_File vf;
|
||||||
int code;
|
int code;
|
||||||
if ((code = ov_fopen(file.u8string().c_str(), &vf))) {
|
if ((code = ov_fopen(file.u8string().c_str(), &vf))) {
|
||||||
throw std::runtime_error("vorbis: "+vorbis_error_message(code));
|
throw std::runtime_error("vorbis: " + vorbis_error_message(code));
|
||||||
}
|
}
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
|
|
||||||
@ -59,9 +69,12 @@ std::unique_ptr<audio::PCM> ogg::load_pcm(const fs::path& file, bool headerOnly)
|
|||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
eof = true;
|
eof = true;
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
logger.error() << "ogg::load_pcm: " << vorbis_error_message(ret);
|
logger.error()
|
||||||
|
<< "ogg::load_pcm: " << vorbis_error_message(ret);
|
||||||
} else {
|
} else {
|
||||||
data.insert(data.end(), std::begin(buffer), std::begin(buffer)+ret);
|
data.insert(
|
||||||
|
data.end(), std::begin(buffer), std::begin(buffer) + ret
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalSamples = data.size() / channels / 2;
|
totalSamples = data.size() / channels / 2;
|
||||||
@ -103,7 +116,8 @@ public:
|
|||||||
int bitstream = 0;
|
int bitstream = 0;
|
||||||
long bytes = ov_read(&vf, buffer, bufferSize, 0, 2, true, &bitstream);
|
long bytes = ov_read(&vf, buffer, bufferSize, 0, 2, true, &bitstream);
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
logger.error() << "ogg::load_pcm: " << vorbis_error_message(bytes) << " " << bytes;
|
logger.error() << "ogg::load_pcm: " << vorbis_error_message(bytes)
|
||||||
|
<< " " << bytes;
|
||||||
return PCMStream::ERROR;
|
return PCMStream::ERROR;
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -156,7 +170,7 @@ std::unique_ptr<PCMStream> ogg::create_stream(const fs::path& file) {
|
|||||||
OggVorbis_File vf;
|
OggVorbis_File vf;
|
||||||
int code;
|
int code;
|
||||||
if ((code = ov_fopen(file.u8string().c_str(), &vf))) {
|
if ((code = ov_fopen(file.u8string().c_str(), &vf))) {
|
||||||
throw std::runtime_error("vorbis: "+vorbis_error_message(code));
|
throw std::runtime_error("vorbis: " + vorbis_error_message(code));
|
||||||
}
|
}
|
||||||
return std::make_unique<OggStream>(vf);
|
return std::make_unique<OggStream>(vf);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,12 @@ namespace audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace ogg {
|
namespace ogg {
|
||||||
std::unique_ptr<audio::PCM> load_pcm(const std::filesystem::path& file, bool headerOnly);
|
std::unique_ptr<audio::PCM> load_pcm(
|
||||||
std::unique_ptr<audio::PCMStream> create_stream(const std::filesystem::path& file);
|
const std::filesystem::path& file, bool headerOnly
|
||||||
|
);
|
||||||
|
std::unique_ptr<audio::PCMStream> create_stream(
|
||||||
|
const std::filesystem::path& file
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_OGG_HPP_
|
#endif // CODERS_OGG_HPP_
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
#include "png.hpp"
|
#include "png.hpp"
|
||||||
|
|
||||||
#include "../graphics/core/ImageData.hpp"
|
#include <GL/glew.h>
|
||||||
#include "../graphics/core/GLTexture.hpp"
|
|
||||||
#include "../files/files.hpp"
|
|
||||||
#include "../debug/Logger.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <GL/glew.h>
|
|
||||||
|
#include "../debug/Logger.hpp"
|
||||||
|
#include "../files/files.hpp"
|
||||||
|
#include "../graphics/core/GLTexture.hpp"
|
||||||
|
#include "../graphics/core/ImageData.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("png-coder");
|
static debug::Logger logger("png-coder");
|
||||||
|
|
||||||
@ -18,7 +19,9 @@ static debug::Logger logger("png-coder");
|
|||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
|
||||||
// returns 0 if all-right, 1 otherwise
|
// returns 0 if all-right, 1 otherwise
|
||||||
int _png_write(const char* filename, uint width, uint height, const ubyte* data, bool alpha) {
|
int _png_write(
|
||||||
|
const char* filename, uint width, uint height, const ubyte* data, bool alpha
|
||||||
|
) {
|
||||||
uint pixsize = alpha ? 4 : 3;
|
uint pixsize = alpha ? 4 : 3;
|
||||||
|
|
||||||
// Open file for writing (binary mode)
|
// Open file for writing (binary mode)
|
||||||
@ -30,7 +33,9 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize write structure
|
// Initialize write structure
|
||||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
png_structp png_ptr = png_create_write_struct(
|
||||||
|
PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr
|
||||||
|
);
|
||||||
if (png_ptr == nullptr) {
|
if (png_ptr == nullptr) {
|
||||||
logger.error() << "could not allocate write struct";
|
logger.error() << "could not allocate write struct";
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -43,9 +48,8 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
logger.error() << "could not allocate info struct";
|
logger.error() << "could not allocate info struct";
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
|
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
|
||||||
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
|
png_destroy_write_struct(&png_ptr, (png_infopp) nullptr);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup Exception handling
|
// Setup Exception handling
|
||||||
@ -60,13 +64,17 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
png_init_io(png_ptr, fp);
|
png_init_io(png_ptr, fp);
|
||||||
|
|
||||||
// Write header (8 bit colour depth)
|
// Write header (8 bit colour depth)
|
||||||
png_set_IHDR(png_ptr, info_ptr, width, height,
|
png_set_IHDR(
|
||||||
8,
|
png_ptr,
|
||||||
alpha ? PNG_COLOR_TYPE_RGBA :
|
info_ptr,
|
||||||
PNG_COLOR_TYPE_RGB,
|
width,
|
||||||
PNG_INTERLACE_NONE,
|
height,
|
||||||
PNG_COMPRESSION_TYPE_BASE,
|
8,
|
||||||
PNG_FILTER_TYPE_BASE);
|
alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
||||||
|
PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE,
|
||||||
|
PNG_FILTER_TYPE_BASE
|
||||||
|
);
|
||||||
|
|
||||||
png_write_info(png_ptr, info_ptr);
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
@ -75,7 +83,8 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
for (uint y = 0; y < height; y++) {
|
for (uint y = 0; y < height; y++) {
|
||||||
for (uint x = 0; x < width; x++) {
|
for (uint x = 0; x < width; x++) {
|
||||||
for (uint i = 0; i < pixsize; i++) {
|
for (uint i = 0; i < pixsize; i++) {
|
||||||
row[x * pixsize + i] = (png_byte)data[(y * width + x) * pixsize + i];
|
row[x * pixsize + i] =
|
||||||
|
(png_byte)data[(y * width + x) * pixsize + i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
png_write_row(png_ptr, row.get());
|
png_write_row(png_ptr, row.get());
|
||||||
@ -90,25 +99,27 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ImageData> _png_load(const char* file){
|
std::unique_ptr<ImageData> _png_load(const char* file) {
|
||||||
FILE* fp = nullptr;
|
FILE* fp = nullptr;
|
||||||
if ((fp = fopen(file, "rb")) == nullptr) {
|
if ((fp = fopen(file, "rb")) == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
png_struct* png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
png_struct* png = png_create_read_struct(
|
||||||
|
PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr
|
||||||
|
);
|
||||||
if (png == nullptr) {
|
if (png == nullptr) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
png_info* info = png_create_info_struct(png);
|
png_info* info = png_create_info_struct(png);
|
||||||
if (info == nullptr) {
|
if (info == nullptr) {
|
||||||
png_destroy_read_struct(&png, (png_info**) nullptr, (png_info**) nullptr);
|
png_destroy_read_struct(&png, (png_info**)nullptr, (png_info**)nullptr);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
png_info* end_info = png_create_info_struct(png);
|
png_info* end_info = png_create_info_struct(png);
|
||||||
if (end_info == nullptr) {
|
if (end_info == nullptr) {
|
||||||
png_destroy_read_struct(&png, (png_info**) nullptr, (png_info**) nullptr);
|
png_destroy_read_struct(&png, (png_info**)nullptr, (png_info**)nullptr);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -122,46 +133,42 @@ std::unique_ptr<ImageData> _png_load(const char* file){
|
|||||||
png_init_io(png, fp);
|
png_init_io(png, fp);
|
||||||
png_read_info(png, info);
|
png_read_info(png, info);
|
||||||
|
|
||||||
int width = png_get_image_width(png, info);
|
int width = png_get_image_width(png, info);
|
||||||
int height = png_get_image_height(png, info);
|
int height = png_get_image_height(png, info);
|
||||||
png_byte color_type = png_get_color_type(png, info);
|
png_byte color_type = png_get_color_type(png, info);
|
||||||
int bit_depth = png_get_bit_depth(png, info);
|
int bit_depth = png_get_bit_depth(png, info);
|
||||||
|
|
||||||
if(bit_depth == 16)
|
if (bit_depth == 16) png_set_strip_16(png);
|
||||||
png_set_strip_16(png);
|
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_PALETTE)
|
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
||||||
png_set_palette_to_rgb(png);
|
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||||
png_set_expand_gray_1_2_4_to_8(png);
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
|
||||||
if(png_get_valid(png, info, PNG_INFO_tRNS))
|
if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
|
||||||
png_set_tRNS_to_alpha(png);
|
|
||||||
|
|
||||||
// These color_type don't have an alpha channel then fill it with 0xff.
|
// These color_type don't have an alpha channel then fill it with 0xff.
|
||||||
if(color_type == PNG_COLOR_TYPE_RGB ||
|
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
color_type == PNG_COLOR_TYPE_GRAY ||
|
|
||||||
color_type == PNG_COLOR_TYPE_PALETTE)
|
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_GRAY ||
|
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
png_set_gray_to_rgb(png);
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
png_read_update_info(png, info);
|
png_read_update_info(png, info);
|
||||||
|
|
||||||
int row_bytes = png_get_rowbytes(png, info);
|
int row_bytes = png_get_rowbytes(png, info);
|
||||||
//color_type = png_get_color_type(png, info);
|
// color_type = png_get_color_type(png, info);
|
||||||
// png_get_color_type returns 2 (RGB) but raster always have alpha channel
|
// png_get_color_type returns 2 (RGB) but raster always have alpha channel
|
||||||
// due to PNG_FILLER_AFTER
|
// due to PNG_FILLER_AFTER
|
||||||
|
|
||||||
color_type = 6;
|
color_type = 6;
|
||||||
bit_depth = png_get_bit_depth(png, info);
|
bit_depth = png_get_bit_depth(png, info);
|
||||||
|
|
||||||
auto image_data = std::make_unique<png_byte[]>(row_bytes * height);
|
auto image_data = std::make_unique<png_byte[]>(row_bytes * height);
|
||||||
auto row_pointers = std::make_unique<png_byte*[]>(height);
|
auto row_pointers = std::make_unique<png_byte*[]>(height);
|
||||||
for (int i = 0; i < height; ++i ) {
|
for (int i = 0; i < height; ++i) {
|
||||||
row_pointers[height - 1 - i] = image_data.get() + i * row_bytes;
|
row_pointers[height - 1 - i] = image_data.get() + i * row_bytes;
|
||||||
}
|
}
|
||||||
png_read_image(png, row_pointers.get());
|
png_read_image(png, row_pointers.get());
|
||||||
@ -175,29 +182,34 @@ std::unique_ptr<ImageData> _png_load(const char* file){
|
|||||||
format = ImageFormat::rgb888;
|
format = ImageFormat::rgb888;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.error() << "color type " << color_type << " is not supported!";
|
logger.error() << "color type " << color_type
|
||||||
|
<< " is not supported!";
|
||||||
png_destroy_read_struct(&png, &info, &end_info);
|
png_destroy_read_struct(&png, &info, &end_info);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto image = std::make_unique<ImageData>(format, width, height, std::move(image_data));
|
auto image = std::make_unique<ImageData>(
|
||||||
|
format, width, height, std::move(image_data)
|
||||||
|
);
|
||||||
png_destroy_read_struct(&png, &info, &end_info);
|
png_destroy_read_struct(&png, &info, &end_info);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
#include <inttypes.h>
|
||||||
#include <spng.h>
|
#include <spng.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
static const int SPNG_SUCCESS = 0;
|
static const int SPNG_SUCCESS = 0;
|
||||||
//returns spng result code
|
// returns spng result code
|
||||||
int _png_write(const char* filename, uint width, uint height, const ubyte* data, bool alpha) {
|
int _png_write(
|
||||||
|
const char* filename, uint width, uint height, const ubyte* data, bool alpha
|
||||||
|
) {
|
||||||
int fmt;
|
int fmt;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
spng_ctx* ctx = nullptr;
|
spng_ctx* ctx = nullptr;
|
||||||
spng_ihdr ihdr = { 0 };
|
spng_ihdr ihdr = {0};
|
||||||
uint pixsize = alpha ? 4 : 3;
|
uint pixsize = alpha ? 4 : 3;
|
||||||
|
|
||||||
ctx = spng_ctx_new(SPNG_CTX_ENCODER);
|
ctx = spng_ctx_new(SPNG_CTX_ENCODER);
|
||||||
@ -205,12 +217,19 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
|
|
||||||
ihdr.width = width;
|
ihdr.width = width;
|
||||||
ihdr.height = height;
|
ihdr.height = height;
|
||||||
ihdr.color_type = alpha ? SPNG_COLOR_TYPE_TRUECOLOR_ALPHA : SPNG_COLOR_TYPE_TRUECOLOR;
|
ihdr.color_type =
|
||||||
|
alpha ? SPNG_COLOR_TYPE_TRUECOLOR_ALPHA : SPNG_COLOR_TYPE_TRUECOLOR;
|
||||||
ihdr.bit_depth = 8;
|
ihdr.bit_depth = 8;
|
||||||
|
|
||||||
spng_set_ihdr(ctx, &ihdr);
|
spng_set_ihdr(ctx, &ihdr);
|
||||||
fmt = SPNG_FMT_PNG;
|
fmt = SPNG_FMT_PNG;
|
||||||
ret = spng_encode_image(ctx, data, (size_t)width * (size_t)height * pixsize , fmt, SPNG_ENCODE_FINALIZE);
|
ret = spng_encode_image(
|
||||||
|
ctx,
|
||||||
|
data,
|
||||||
|
(size_t)width * (size_t)height * pixsize,
|
||||||
|
fmt,
|
||||||
|
SPNG_ENCODE_FINALIZE
|
||||||
|
);
|
||||||
if (ret != SPNG_SUCCESS) {
|
if (ret != SPNG_SUCCESS) {
|
||||||
logger.error() << "spng_encode_image() error: " << spng_strerror(ret);
|
logger.error() << "spng_encode_image() error: " << spng_strerror(ret);
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
@ -222,21 +241,20 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data,
|
|||||||
|
|
||||||
if (png_buf == nullptr) {
|
if (png_buf == nullptr) {
|
||||||
logger.error() << "spng_get_png_buffer() error: " << spng_strerror(ret);
|
logger.error() << "spng_get_png_buffer() error: " << spng_strerror(ret);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
files::write_bytes(filename, (const unsigned char*)png_buf, png_size);
|
files::write_bytes(filename, (const unsigned char*)png_buf, png_size);
|
||||||
}
|
}
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ImageData> _png_load(const char* file){
|
std::unique_ptr<ImageData> _png_load(const char* file) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
FILE *png = nullptr;
|
FILE* png = nullptr;
|
||||||
spng_ctx *ctx = nullptr;
|
spng_ctx* ctx = nullptr;
|
||||||
|
|
||||||
png = fopen(file, "rb");
|
png = fopen(file, "rb");
|
||||||
if (png == nullptr){
|
if (png == nullptr) {
|
||||||
logger.error() << "could not to open file " << file;
|
logger.error() << "could not to open file " << file;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -244,31 +262,32 @@ std::unique_ptr<ImageData> _png_load(const char* file){
|
|||||||
fseek(png, 0, SEEK_END);
|
fseek(png, 0, SEEK_END);
|
||||||
long siz_pngbuf = ftell(png);
|
long siz_pngbuf = ftell(png);
|
||||||
rewind(png);
|
rewind(png);
|
||||||
if(siz_pngbuf < 1) {
|
if (siz_pngbuf < 1) {
|
||||||
fclose(png);
|
fclose(png);
|
||||||
logger.error() << "could not to read file " << file;
|
logger.error() << "could not to read file " << file;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto pngbuf = std::make_unique<char[]>(siz_pngbuf);
|
auto pngbuf = std::make_unique<char[]>(siz_pngbuf);
|
||||||
if(fread(pngbuf.get(), siz_pngbuf, 1, png) != 1){ //check of read elements count
|
if (fread(pngbuf.get(), siz_pngbuf, 1, png) !=
|
||||||
|
1) { // check of read elements count
|
||||||
fclose(png);
|
fclose(png);
|
||||||
logger.error() << "fread() failed: " << file;
|
logger.error() << "fread() failed: " << file;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
fclose(png); // <- finally closing file
|
fclose(png); // <- finally closing file
|
||||||
ctx = spng_ctx_new(0);
|
ctx = spng_ctx_new(0);
|
||||||
if (ctx == nullptr){
|
if (ctx == nullptr) {
|
||||||
logger.error() << "spng_ctx_new() failed";
|
logger.error() << "spng_ctx_new() failed";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
r = spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
|
r = spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
|
||||||
if (r != SPNG_SUCCESS){
|
if (r != SPNG_SUCCESS) {
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
logger.error() << "spng_set_crc_action(): " << spng_strerror(r);
|
logger.error() << "spng_set_crc_action(): " << spng_strerror(r);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
r = spng_set_png_buffer(ctx, pngbuf.get(), siz_pngbuf);
|
r = spng_set_png_buffer(ctx, pngbuf.get(), siz_pngbuf);
|
||||||
if (r != SPNG_SUCCESS){
|
if (r != SPNG_SUCCESS) {
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
logger.error() << "spng_set_png_buffer(): " << spng_strerror(r);
|
logger.error() << "spng_set_png_buffer(): " << spng_strerror(r);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -276,7 +295,7 @@ std::unique_ptr<ImageData> _png_load(const char* file){
|
|||||||
|
|
||||||
spng_ihdr ihdr;
|
spng_ihdr ihdr;
|
||||||
r = spng_get_ihdr(ctx, &ihdr);
|
r = spng_get_ihdr(ctx, &ihdr);
|
||||||
if (r != SPNG_SUCCESS){
|
if (r != SPNG_SUCCESS) {
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
logger.error() << "spng_get_ihdr(): " << spng_strerror(r);
|
logger.error() << "spng_get_ihdr(): " << spng_strerror(r);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -284,28 +303,30 @@ std::unique_ptr<ImageData> _png_load(const char* file){
|
|||||||
|
|
||||||
size_t out_size;
|
size_t out_size;
|
||||||
r = spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
|
r = spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
|
||||||
if (r != SPNG_SUCCESS){
|
if (r != SPNG_SUCCESS) {
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
logger.error() << "spng_decoded_image_size(): " << spng_strerror(r);
|
logger.error() << "spng_decoded_image_size(): " << spng_strerror(r);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto out = std::make_unique<ubyte[]>(out_size);
|
auto out = std::make_unique<ubyte[]>(out_size);
|
||||||
r = spng_decode_image(ctx, out.get(), out_size, SPNG_FMT_RGBA8, 0);
|
r = spng_decode_image(ctx, out.get(), out_size, SPNG_FMT_RGBA8, 0);
|
||||||
if (r != SPNG_SUCCESS){
|
if (r != SPNG_SUCCESS) {
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
logger.error() << "spng_decode_image(): " << spng_strerror(r);
|
logger.error() << "spng_decode_image(): " << spng_strerror(r);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto flipped = std::make_unique<ubyte[]>(out_size);
|
auto flipped = std::make_unique<ubyte[]>(out_size);
|
||||||
for (size_t i = 0; i < ihdr.height; i+=1){
|
for (size_t i = 0; i < ihdr.height; i += 1) {
|
||||||
size_t rowsize = ihdr.width*4;
|
size_t rowsize = ihdr.width * 4;
|
||||||
for (size_t j = 0; j < rowsize; j++){
|
for (size_t j = 0; j < rowsize; j++) {
|
||||||
flipped[(ihdr.height-i-1)*rowsize+j] = out[i*rowsize+j];
|
flipped[(ihdr.height - i - 1) * rowsize + j] = out[i * rowsize + j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto image = std::make_unique<ImageData>(ImageFormat::rgba8888, ihdr.width, ihdr.height, std::move(flipped));
|
auto image = std::make_unique<ImageData>(
|
||||||
|
ImageFormat::rgba8888, ihdr.width, ihdr.height, std::move(flipped)
|
||||||
|
);
|
||||||
spng_ctx_free(ctx);
|
spng_ctx_free(ctx);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
@ -314,7 +335,7 @@ std::unique_ptr<ImageData> _png_load(const char* file){
|
|||||||
std::unique_ptr<ImageData> png::load_image(const std::string& filename) {
|
std::unique_ptr<ImageData> png::load_image(const std::string& filename) {
|
||||||
auto image = _png_load(filename.c_str());
|
auto image = _png_load(filename.c_str());
|
||||||
if (image == nullptr) {
|
if (image == nullptr) {
|
||||||
throw std::runtime_error("could not load image "+filename);
|
throw std::runtime_error("could not load image " + filename);
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,4 +13,4 @@ namespace png {
|
|||||||
std::unique_ptr<Texture> load_texture(const std::string& filename);
|
std::unique_ptr<Texture> load_texture(const std::string& filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_PNG_HPP_
|
#endif // CODERS_PNG_HPP_
|
||||||
|
|||||||
@ -26,8 +26,7 @@ size_t rle::encode(const ubyte* src, size_t srclen, ubyte* dst) {
|
|||||||
dst[offset++] = c;
|
dst[offset++] = c;
|
||||||
c = cnext;
|
c = cnext;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,7 +35,6 @@ size_t rle::encode(const ubyte* src, size_t srclen, ubyte* dst) {
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t extrle::decode(const ubyte* src, size_t srclen, ubyte* dst) {
|
size_t extrle::decode(const ubyte* src, size_t srclen, ubyte* dst) {
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
for (size_t i = 0; i < srclen;) {
|
for (size_t i = 0; i < srclen;) {
|
||||||
@ -66,23 +64,20 @@ size_t extrle::encode(const ubyte* src, size_t srclen, ubyte* dst) {
|
|||||||
if (counter >= 0x80) {
|
if (counter >= 0x80) {
|
||||||
dst[offset++] = 0x80 | (counter & 0x7F);
|
dst[offset++] = 0x80 | (counter & 0x7F);
|
||||||
dst[offset++] = counter >> 7;
|
dst[offset++] = counter >> 7;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dst[offset++] = counter;
|
dst[offset++] = counter;
|
||||||
}
|
}
|
||||||
dst[offset++] = c;
|
dst[offset++] = c;
|
||||||
c = cnext;
|
c = cnext;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (counter >= 0x80) {
|
if (counter >= 0x80) {
|
||||||
dst[offset++] = 0x80 | (counter & 0x7F);
|
dst[offset++] = 0x80 | (counter & 0x7F);
|
||||||
dst[offset++] = counter >> 7;
|
dst[offset++] = counter >> 7;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dst[offset++] = counter;
|
dst[offset++] = counter;
|
||||||
}
|
}
|
||||||
dst[offset++] = c;
|
dst[offset++] = c;
|
||||||
|
|||||||
@ -14,4 +14,4 @@ namespace extrle {
|
|||||||
size_t decode(const ubyte* src, size_t length, ubyte* dst);
|
size_t decode(const ubyte* src, size_t length, ubyte* dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_RLE_HPP_
|
#endif // CODERS_RLE_HPP_
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
#include "toml.hpp"
|
#include "toml.hpp"
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include <assert.h>
|
||||||
#include "../data/setting.hpp"
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
#include "../util/stringutil.hpp"
|
|
||||||
#include "../files/settings_io.hpp"
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <assert.h>
|
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
#include "../data/setting.hpp"
|
||||||
|
#include "../files/settings_io.hpp"
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
using namespace toml;
|
using namespace toml;
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ class TomlReader : BasicParser {
|
|||||||
} else {
|
} else {
|
||||||
rootMap = *map;
|
rootMap = *map;
|
||||||
}
|
}
|
||||||
offset = index+1;
|
offset = index + 1;
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,12 +94,9 @@ class TomlReader : BasicParser {
|
|||||||
expectNewLine();
|
expectNewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TomlReader(
|
TomlReader(std::string_view file, std::string_view source)
|
||||||
std::string_view file,
|
: BasicParser(file, source) {
|
||||||
std::string_view source)
|
|
||||||
: BasicParser(file, source) {
|
|
||||||
root = dynamic::create_map();
|
root = dynamic::create_map();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +127,7 @@ void toml::parse(
|
|||||||
for (auto& sectionEntry : (*sectionMap)->values) {
|
for (auto& sectionEntry : (*sectionMap)->values) {
|
||||||
const auto& name = sectionEntry.first;
|
const auto& name = sectionEntry.first;
|
||||||
auto& value = sectionEntry.second;
|
auto& value = sectionEntry.second;
|
||||||
auto fullname = sectionName+"."+name;
|
auto fullname = sectionName + "." + name;
|
||||||
if (handler.has(fullname)) {
|
if (handler.has(fullname)) {
|
||||||
handler.setValue(fullname, value);
|
handler.setValue(fullname, value);
|
||||||
}
|
}
|
||||||
@ -150,9 +148,11 @@ std::string toml::stringify(dynamic::Map& root, const std::string& name) {
|
|||||||
}
|
}
|
||||||
for (auto& entry : root.values) {
|
for (auto& entry : root.values) {
|
||||||
if (auto submap = std::get_if<dynamic::Map_sptr>(&entry.second)) {
|
if (auto submap = std::get_if<dynamic::Map_sptr>(&entry.second)) {
|
||||||
ss << "\n" << toml::stringify(
|
ss << "\n"
|
||||||
**submap, name.empty() ? entry.first : name+"."+entry.first
|
<< toml::stringify(
|
||||||
);
|
**submap,
|
||||||
|
name.empty() ? entry.first : name + "." + entry.first
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
@ -166,7 +166,7 @@ std::string toml::stringify(SettingsHandler& handler) {
|
|||||||
ss << "[" << section.name << "]\n";
|
ss << "[" << section.name << "]\n";
|
||||||
for (const std::string& key : section.keys) {
|
for (const std::string& key : section.keys) {
|
||||||
ss << key << " = ";
|
ss << key << " = ";
|
||||||
auto setting = handler.getSetting(section.name+"."+key);
|
auto setting = handler.getSetting(section.name + "." + key);
|
||||||
assert(setting != nullptr);
|
assert(setting != nullptr);
|
||||||
if (auto integer = dynamic_cast<IntegerSetting*>(setting)) {
|
if (auto integer = dynamic_cast<IntegerSetting*>(setting)) {
|
||||||
ss << integer->get();
|
ss << integer->get();
|
||||||
|
|||||||
@ -1,21 +1,20 @@
|
|||||||
#ifndef CODERS_TOML_HPP_
|
#ifndef CODERS_TOML_HPP_
|
||||||
#define CODERS_TOML_HPP_
|
#define CODERS_TOML_HPP_
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
|
||||||
class SettingsHandler;
|
class SettingsHandler;
|
||||||
|
|
||||||
namespace toml {
|
namespace toml {
|
||||||
std::string stringify(SettingsHandler& handler);
|
std::string stringify(SettingsHandler& handler);
|
||||||
std::string stringify(dynamic::Map& root, const std::string& name="");
|
std::string stringify(dynamic::Map& root, const std::string& name = "");
|
||||||
dynamic::Map_sptr parse(std::string_view file, std::string_view source);
|
dynamic::Map_sptr parse(std::string_view file, std::string_view source);
|
||||||
|
|
||||||
void parse(
|
void parse(
|
||||||
SettingsHandler& handler,
|
SettingsHandler& handler, std::string_view file, std::string_view source
|
||||||
std::string_view file,
|
|
||||||
std::string_view source
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_TOML_HPP_
|
#endif // CODERS_TOML_HPP_
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#include "wav.hpp"
|
#include "wav.hpp"
|
||||||
|
|
||||||
#include "../audio/audio.hpp"
|
|
||||||
#include "../debug/Logger.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../audio/audio.hpp"
|
||||||
|
#include "../debug/Logger.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -20,12 +20,11 @@ bool is_big_endian() {
|
|||||||
return bytes[0] == 1;
|
return bytes[0] == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::int32_t convert_to_int(char* buffer, std::size_t len){
|
std::int32_t convert_to_int(char* buffer, std::size_t len) {
|
||||||
std::int32_t a = 0;
|
std::int32_t a = 0;
|
||||||
if (!is_big_endian()) {
|
if (!is_big_endian()) {
|
||||||
std::memcpy(&a, buffer, len);
|
std::memcpy(&a, buffer, len);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (std::size_t i = 0; i < len; ++i) {
|
for (std::size_t i = 0; i < len; ++i) {
|
||||||
reinterpret_cast<char*>(&a)[3 - i] = buffer[i];
|
reinterpret_cast<char*>(&a)[3 - i] = buffer[i];
|
||||||
}
|
}
|
||||||
@ -50,12 +49,12 @@ public:
|
|||||||
uint sampleRate,
|
uint sampleRate,
|
||||||
size_t size,
|
size_t size,
|
||||||
size_t initialPosition
|
size_t initialPosition
|
||||||
) : in(std::move(in)),
|
)
|
||||||
channels(channels),
|
: in(std::move(in)),
|
||||||
bytesPerSample(bitsPerSample/8),
|
channels(channels),
|
||||||
sampleRate(sampleRate),
|
bytesPerSample(bitsPerSample / 8),
|
||||||
totalSize(size)
|
sampleRate(sampleRate),
|
||||||
{
|
totalSize(size) {
|
||||||
totalSamples = totalSize / channels / bytesPerSample;
|
totalSamples = totalSize / channels / bytesPerSample;
|
||||||
this->initialPosition = initialPosition;
|
this->initialPosition = initialPosition;
|
||||||
}
|
}
|
||||||
@ -76,8 +75,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void close() override {
|
void close() override {
|
||||||
if (!isOpen())
|
if (!isOpen()) return;
|
||||||
return;
|
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,58 +108,66 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void seek(size_t position) override {
|
void seek(size_t position) override {
|
||||||
if (!isOpen())
|
if (!isOpen()) return;
|
||||||
return;
|
|
||||||
position %= totalSamples;
|
position %= totalSamples;
|
||||||
in.clear();
|
in.clear();
|
||||||
in.seekg(initialPosition + position * channels * bytesPerSample, std::ios_base::beg);
|
in.seekg(
|
||||||
|
initialPosition + position * channels * bytesPerSample,
|
||||||
|
std::ios_base::beg
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<audio::PCMStream> wav::create_stream(const fs::path& file) {
|
std::unique_ptr<audio::PCMStream> wav::create_stream(const fs::path& file) {
|
||||||
std::ifstream in(file, std::ios::binary);
|
std::ifstream in(file, std::ios::binary);
|
||||||
if(!in.is_open()){
|
if (!in.is_open()) {
|
||||||
throw std::runtime_error("could not to open file '"+file.u8string()+"'");
|
throw std::runtime_error(
|
||||||
|
"could not to open file '" + file.u8string() + "'"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[6];
|
char buffer[6];
|
||||||
// the RIFF
|
// the RIFF
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not to read RIFF");
|
throw std::runtime_error("could not to read RIFF");
|
||||||
}
|
}
|
||||||
if(std::strncmp(buffer, "RIFF", 4) != 0){
|
if (std::strncmp(buffer, "RIFF", 4) != 0) {
|
||||||
throw std::runtime_error("file is not a valid WAVE file (header doesn't begin with RIFF)");
|
throw std::runtime_error(
|
||||||
|
"file is not a valid WAVE file (header doesn't begin with RIFF)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// the size of the file
|
// the size of the file
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read size of file");
|
throw std::runtime_error("could not read size of file");
|
||||||
}
|
}
|
||||||
// the WAVE
|
// the WAVE
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not to read WAVE");
|
throw std::runtime_error("could not to read WAVE");
|
||||||
}
|
}
|
||||||
if(std::strncmp(buffer, "WAVE", 4) != 0){
|
if (std::strncmp(buffer, "WAVE", 4) != 0) {
|
||||||
throw std::runtime_error("file is not a valid WAVE file (header doesn't contain WAVE)");
|
throw std::runtime_error(
|
||||||
|
"file is not a valid WAVE file (header doesn't contain WAVE)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// "fmt/0"
|
// "fmt/0"
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read fmt/0");
|
throw std::runtime_error("could not read fmt/0");
|
||||||
}
|
}
|
||||||
// this is always 16, the size of the fmt data chunk
|
// this is always 16, the size of the fmt data chunk
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read the 16");
|
throw std::runtime_error("could not read the 16");
|
||||||
}
|
}
|
||||||
// PCM should be 1?
|
// PCM should be 1?
|
||||||
if(!in.read(buffer, 2)){
|
if (!in.read(buffer, 2)) {
|
||||||
throw std::runtime_error("could not read PCM");
|
throw std::runtime_error("could not read PCM");
|
||||||
}
|
}
|
||||||
// the number of channels
|
// the number of channels
|
||||||
if(!in.read(buffer, 2)){
|
if (!in.read(buffer, 2)) {
|
||||||
throw std::runtime_error("could not read number of channels");
|
throw std::runtime_error("could not read number of channels");
|
||||||
}
|
}
|
||||||
int channels = convert_to_int(buffer, 2);
|
int channels = convert_to_int(buffer, 2);
|
||||||
// sample rate
|
// sample rate
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read sample rate");
|
throw std::runtime_error("could not read sample rate");
|
||||||
}
|
}
|
||||||
int sampleRate = convert_to_int(buffer, 4);
|
int sampleRate = convert_to_int(buffer, 4);
|
||||||
@ -170,16 +176,19 @@ std::unique_ptr<audio::PCMStream> wav::create_stream(const fs::path& file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bitsPerSample
|
// bitsPerSample
|
||||||
if(!in.read(buffer, 2)){
|
if (!in.read(buffer, 2)) {
|
||||||
throw std::runtime_error("could not read bits per sample");
|
throw std::runtime_error("could not read bits per sample");
|
||||||
}
|
}
|
||||||
int bitsPerSample = convert_to_int(buffer, 2);
|
int bitsPerSample = convert_to_int(buffer, 2);
|
||||||
if (bitsPerSample >= 24) {
|
if (bitsPerSample >= 24) {
|
||||||
throw std::runtime_error(std::to_string(bitsPerSample)+" bit depth is not supported by OpenAL");
|
throw std::runtime_error(
|
||||||
|
std::to_string(bitsPerSample) +
|
||||||
|
" bit depth is not supported by OpenAL"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// data chunk header "data"
|
// data chunk header "data"
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read data chunk header");
|
throw std::runtime_error("could not read data chunk header");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +196,7 @@ std::unique_ptr<audio::PCMStream> wav::create_stream(const fs::path& file) {
|
|||||||
// skip garbage in WAV
|
// skip garbage in WAV
|
||||||
if (std::strncmp(buffer, "LIST", 4) == 0) {
|
if (std::strncmp(buffer, "LIST", 4) == 0) {
|
||||||
// chunk size
|
// chunk size
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read comment chunk size");
|
throw std::runtime_error("could not read comment chunk size");
|
||||||
}
|
}
|
||||||
int chunkSize = convert_to_int(buffer, 4);
|
int chunkSize = convert_to_int(buffer, 4);
|
||||||
@ -195,26 +204,28 @@ std::unique_ptr<audio::PCMStream> wav::create_stream(const fs::path& file) {
|
|||||||
|
|
||||||
initialOffset += chunkSize + 4;
|
initialOffset += chunkSize + 4;
|
||||||
|
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read data chunk header");
|
throw std::runtime_error("could not read data chunk header");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std::strncmp(buffer, "data", 4) != 0){
|
if (std::strncmp(buffer, "data", 4) != 0) {
|
||||||
throw std::runtime_error("file is not a valid WAVE file (doesn't have 'data' tag)");
|
throw std::runtime_error(
|
||||||
|
"file is not a valid WAVE file (doesn't have 'data' tag)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// size of data
|
// size of data
|
||||||
if(!in.read(buffer, 4)){
|
if (!in.read(buffer, 4)) {
|
||||||
throw std::runtime_error("could not read data size");
|
throw std::runtime_error("could not read data size");
|
||||||
}
|
}
|
||||||
size_t size = convert_to_int(buffer, 4);
|
size_t size = convert_to_int(buffer, 4);
|
||||||
|
|
||||||
/* cannot be at the end of file */
|
/* cannot be at the end of file */
|
||||||
if(in.eof()){
|
if (in.eof()) {
|
||||||
throw std::runtime_error("reached EOF on the file");
|
throw std::runtime_error("reached EOF on the file");
|
||||||
}
|
}
|
||||||
if(in.fail()){
|
if (in.fail()) {
|
||||||
throw std::runtime_error("fail state set on the file");
|
throw std::runtime_error("fail state set on the file");
|
||||||
}
|
}
|
||||||
return std::make_unique<WavStream>(
|
return std::make_unique<WavStream>(
|
||||||
@ -222,7 +233,9 @@ 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) {
|
std::unique_ptr<audio::PCM> wav::load_pcm(
|
||||||
|
const fs::path& file, bool headerOnly
|
||||||
|
) {
|
||||||
auto stream = wav::create_stream(file);
|
auto stream = wav::create_stream(file);
|
||||||
|
|
||||||
size_t totalSamples = stream->getTotalSamples();
|
size_t totalSamples = stream->getTotalSamples();
|
||||||
@ -233,8 +246,7 @@ std::unique_ptr<audio::PCM> wav::load_pcm(const fs::path& file, bool headerOnly)
|
|||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
if (!headerOnly) {
|
if (!headerOnly) {
|
||||||
size_t size = stream->getTotalSamples() *
|
size_t size = stream->getTotalSamples() *
|
||||||
(stream->getBitsPerSample()/8) *
|
(stream->getBitsPerSample() / 8) * stream->getChannels();
|
||||||
stream->getChannels();
|
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
stream->readFully(data.data(), size, false);
|
stream->readFully(data.data(), size, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,12 @@ namespace audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace wav {
|
namespace wav {
|
||||||
std::unique_ptr<audio::PCM> load_pcm(const std::filesystem::path& file, bool headerOnly);
|
std::unique_ptr<audio::PCM> load_pcm(
|
||||||
std::unique_ptr<audio::PCMStream> create_stream(const std::filesystem::path& file);
|
const std::filesystem::path& file, bool headerOnly
|
||||||
|
);
|
||||||
|
std::unique_ptr<audio::PCMStream> create_stream(
|
||||||
|
const std::filesystem::path& file
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_WAV_HPP_
|
#endif // CODERS_WAV_HPP_
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
#include "xml.hpp"
|
#include "xml.hpp"
|
||||||
|
|
||||||
#include "../util/stringutil.hpp"
|
|
||||||
|
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <stdexcept>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
using namespace xml;
|
using namespace xml;
|
||||||
|
|
||||||
Attribute::Attribute(std::string name, std::string text)
|
Attribute::Attribute(std::string name, std::string text)
|
||||||
: name(std::move(name)),
|
: name(std::move(name)), text(std::move(text)) {
|
||||||
text(std::move(text)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Attribute::getName() const {
|
const std::string& Attribute::getName() const {
|
||||||
@ -42,7 +41,7 @@ glm::vec2 Attribute::asVec2() const {
|
|||||||
}
|
}
|
||||||
return glm::vec2(
|
return glm::vec2(
|
||||||
util::parse_double(text, 0, pos),
|
util::parse_double(text, 0, pos),
|
||||||
util::parse_double(text, pos+1, text.length()-pos-1)
|
util::parse_double(text, pos + 1, text.length() - pos - 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,14 +51,14 @@ glm::vec3 Attribute::asVec3() const {
|
|||||||
if (pos1 == std::string::npos) {
|
if (pos1 == std::string::npos) {
|
||||||
return glm::vec3(util::parse_double(text, 0, text.length()));
|
return glm::vec3(util::parse_double(text, 0, text.length()));
|
||||||
}
|
}
|
||||||
size_t pos2 = text.find(',', pos1+1);
|
size_t pos2 = text.find(',', pos1 + 1);
|
||||||
if (pos2 == std::string::npos) {
|
if (pos2 == std::string::npos) {
|
||||||
throw std::runtime_error("invalid vec3 value "+util::quote(text));
|
throw std::runtime_error("invalid vec3 value " + util::quote(text));
|
||||||
}
|
}
|
||||||
return glm::vec3(
|
return glm::vec3(
|
||||||
util::parse_double(text, 0, pos1),
|
util::parse_double(text, 0, pos1),
|
||||||
util::parse_double(text, pos1+1, pos2),
|
util::parse_double(text, pos1 + 1, pos2),
|
||||||
util::parse_double(text, pos2+1, text.length()-pos2-1)
|
util::parse_double(text, pos2 + 1, text.length() - pos2 - 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,19 +68,19 @@ glm::vec4 Attribute::asVec4() const {
|
|||||||
if (pos1 == std::string::npos) {
|
if (pos1 == std::string::npos) {
|
||||||
return glm::vec4(util::parse_double(text, 0, text.length()));
|
return glm::vec4(util::parse_double(text, 0, text.length()));
|
||||||
}
|
}
|
||||||
size_t pos2 = text.find(',', pos1+1);
|
size_t pos2 = text.find(',', pos1 + 1);
|
||||||
if (pos2 == std::string::npos) {
|
if (pos2 == std::string::npos) {
|
||||||
throw std::runtime_error("invalid vec4 value "+util::quote(text));
|
throw std::runtime_error("invalid vec4 value " + util::quote(text));
|
||||||
}
|
}
|
||||||
size_t pos3 = text.find(',', pos2+1);
|
size_t pos3 = text.find(',', pos2 + 1);
|
||||||
if (pos3 == std::string::npos) {
|
if (pos3 == std::string::npos) {
|
||||||
throw std::runtime_error("invalid vec4 value "+util::quote(text));
|
throw std::runtime_error("invalid vec4 value " + util::quote(text));
|
||||||
}
|
}
|
||||||
return glm::vec4(
|
return glm::vec4(
|
||||||
util::parse_double(text, 0, pos1),
|
util::parse_double(text, 0, pos1),
|
||||||
util::parse_double(text, pos1+1, pos2-pos1-1),
|
util::parse_double(text, pos1 + 1, pos2 - pos1 - 1),
|
||||||
util::parse_double(text, pos2+1, pos3-pos2-1),
|
util::parse_double(text, pos2 + 1, pos3 - pos2 - 1),
|
||||||
util::parse_double(text, pos3+1, text.length()-pos3-1)
|
util::parse_double(text, pos3 + 1, text.length() - pos3 - 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +111,7 @@ void Node::add(const xmlelement& element) {
|
|||||||
elements.push_back(element);
|
elements.push_back(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::set(const std::string& name, const std::string &text) {
|
void Node::set(const std::string& name, const std::string& text) {
|
||||||
attrs[name] = Attribute(name, text);
|
attrs[name] = Attribute(name, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +122,9 @@ const std::string& Node::getTag() const {
|
|||||||
const xmlattribute& Node::attr(const std::string& name) const {
|
const xmlattribute& Node::attr(const std::string& name) const {
|
||||||
auto found = attrs.find(name);
|
auto found = attrs.find(name);
|
||||||
if (found == attrs.end()) {
|
if (found == attrs.end()) {
|
||||||
throw std::runtime_error("element <"+tag+" ...> missing attribute "+name);
|
throw std::runtime_error(
|
||||||
|
"element <" + tag + " ...> missing attribute " + name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
@ -158,11 +159,10 @@ const xmlelements_map& Node::getAttributes() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Document::Document(std::string version, std::string encoding)
|
Document::Document(std::string version, std::string encoding)
|
||||||
: version(std::move(version)),
|
: version(std::move(version)), encoding(std::move(encoding)) {
|
||||||
encoding(std::move(encoding)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::setRoot(const xmlelement &element) {
|
void Document::setRoot(const xmlelement& element) {
|
||||||
this->root = element;
|
this->root = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,8 +190,7 @@ xmlelement Parser::parseOpenTag() {
|
|||||||
while (true) {
|
while (true) {
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
c = peek();
|
c = peek();
|
||||||
if (c == '/' || c == '>' || c == '?')
|
if (c == '/' || c == '>' || c == '?') break;
|
||||||
break;
|
|
||||||
std::string attrname = parseXMLName();
|
std::string attrname = parseXMLName();
|
||||||
std::string attrtext = "";
|
std::string attrtext = "";
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
@ -251,7 +250,7 @@ std::string Parser::parseText() {
|
|||||||
}
|
}
|
||||||
nextChar();
|
nextChar();
|
||||||
}
|
}
|
||||||
return std::string(source.substr(start, pos-start));
|
return std::string(source.substr(start, pos - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_xml_identifier_start(char c) {
|
inline bool is_xml_identifier_start(char c) {
|
||||||
@ -259,7 +258,7 @@ inline bool is_xml_identifier_start(char c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_xml_identifier_part(char c) {
|
inline bool is_xml_identifier_part(char c) {
|
||||||
return is_identifier_part(c) || c == '-' || c == '.' || c == ':';
|
return is_identifier_part(c) || c == '-' || c == '.' || c == ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Parser::parseXMLName() {
|
std::string Parser::parseXMLName() {
|
||||||
@ -271,7 +270,7 @@ std::string Parser::parseXMLName() {
|
|||||||
while (hasNext() && is_xml_identifier_part(source[pos])) {
|
while (hasNext() && is_xml_identifier_part(source[pos])) {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return std::string(source.substr(start, pos-start));
|
return std::string(source.substr(start, pos - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlelement Parser::parseElement() {
|
xmlelement Parser::parseElement() {
|
||||||
@ -343,13 +342,9 @@ xmldocument xml::parse(const std::string& filename, const std::string& source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void newline(
|
inline void newline(
|
||||||
std::stringstream& ss,
|
std::stringstream& ss, bool nice, const std::string& indentStr, int indent
|
||||||
bool nice,
|
|
||||||
const std::string& indentStr,
|
|
||||||
int indent
|
|
||||||
) {
|
) {
|
||||||
if (!nice)
|
if (!nice) return;
|
||||||
return;
|
|
||||||
ss << '\n';
|
ss << '\n';
|
||||||
for (int i = 0; i < indent; i++) {
|
for (int i = 0; i < indent; i++) {
|
||||||
ss << indentStr;
|
ss << indentStr;
|
||||||
@ -366,7 +361,7 @@ static void stringifyElement(
|
|||||||
if (element->isText()) {
|
if (element->isText()) {
|
||||||
std::string text = element->attr("#").getText();
|
std::string text = element->attr("#").getText();
|
||||||
util::replaceAll(text, "&", "&");
|
util::replaceAll(text, "&", "&");
|
||||||
util::replaceAll(text, "\"",""");
|
util::replaceAll(text, "\"", """);
|
||||||
util::replaceAll(text, "'", "'");
|
util::replaceAll(text, "'", "'");
|
||||||
util::replaceAll(text, "<", "<");
|
util::replaceAll(text, "<", "<");
|
||||||
util::replaceAll(text, ">", ">");
|
util::replaceAll(text, ">", ">");
|
||||||
@ -395,15 +390,15 @@ static void stringifyElement(
|
|||||||
auto& elements = element->getElements();
|
auto& elements = element->getElements();
|
||||||
if (elements.size() == 1 && elements[0]->isText()) {
|
if (elements.size() == 1 && elements[0]->isText()) {
|
||||||
ss << ">";
|
ss << ">";
|
||||||
stringifyElement(ss, elements[0], nice, indentStr, indent+1);
|
stringifyElement(ss, elements[0], nice, indentStr, indent + 1);
|
||||||
ss << "</" << tag << ">";
|
ss << "</" << tag << ">";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!elements.empty()) {
|
if (!elements.empty()) {
|
||||||
ss << '>';
|
ss << '>';
|
||||||
for (auto& sub : elements) {
|
for (auto& sub : elements) {
|
||||||
newline(ss, nice, indentStr, indent+1);
|
newline(ss, nice, indentStr, indent + 1);
|
||||||
stringifyElement(ss, sub, nice, indentStr, indent+1);
|
stringifyElement(ss, sub, nice, indentStr, indent + 1);
|
||||||
}
|
}
|
||||||
newline(ss, nice, indentStr, indent);
|
newline(ss, nice, indentStr, indent);
|
||||||
ss << "</" << tag << ">";
|
ss << "</" << tag << ">";
|
||||||
@ -411,13 +406,10 @@ static void stringifyElement(
|
|||||||
} else {
|
} else {
|
||||||
ss << "/>";
|
ss << "/>";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string xml::stringify(
|
std::string xml::stringify(
|
||||||
const xmldocument& document,
|
const xmldocument& document, bool nice, const std::string& indentStr
|
||||||
bool nice,
|
|
||||||
const std::string& indentStr
|
|
||||||
) {
|
) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#ifndef CODERS_XML_HPP_
|
#ifndef CODERS_XML_HPP_
|
||||||
#define CODERS_XML_HPP_
|
#define CODERS_XML_HPP_
|
||||||
|
|
||||||
#include "commons.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
namespace xml {
|
namespace xml {
|
||||||
class Node;
|
class Node;
|
||||||
@ -37,7 +37,8 @@ namespace xml {
|
|||||||
glm::vec4 asColor() const;
|
glm::vec4 asColor() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief XML element class. Text element has tag 'text' and attribute 'text'
|
/// @brief XML element class. Text element has tag 'text' and attribute
|
||||||
|
/// 'text'
|
||||||
class Node {
|
class Node {
|
||||||
std::string tag;
|
std::string tag;
|
||||||
std::unordered_map<std::string, xmlattribute> attrs;
|
std::unordered_map<std::string, xmlattribute> attrs;
|
||||||
@ -51,7 +52,7 @@ namespace xml {
|
|||||||
/// @brief Set attribute value. Creates attribute if does not exists
|
/// @brief Set attribute value. Creates attribute if does not exists
|
||||||
/// @param name attribute name
|
/// @param name attribute name
|
||||||
/// @param text attribute value
|
/// @param text attribute value
|
||||||
void set(const std::string& name, const std::string &text);
|
void set(const std::string& name, const std::string& text);
|
||||||
|
|
||||||
/// @brief Get element tag
|
/// @brief Get element tag
|
||||||
const std::string& getTag() const;
|
const std::string& getTag() const;
|
||||||
@ -75,7 +76,8 @@ namespace xml {
|
|||||||
/// @param def default value will be returned wrapped in xmlattribute
|
/// @param def default value will be returned wrapped in xmlattribute
|
||||||
/// if element has no attribute
|
/// if element has no attribute
|
||||||
/// @return xmlattribute - {name, value} or {name, def} if not found*/
|
/// @return xmlattribute - {name, value} or {name, def} if not found*/
|
||||||
xmlattribute attr(const std::string& name, const std::string& def) const;
|
xmlattribute attr(const std::string& name, const std::string& def)
|
||||||
|
const;
|
||||||
|
|
||||||
/// @brief Check if element has attribute
|
/// @brief Check if element has attribute
|
||||||
/// @param name attribute name
|
/// @param name attribute name
|
||||||
@ -101,7 +103,7 @@ namespace xml {
|
|||||||
public:
|
public:
|
||||||
Document(std::string version, std::string encoding);
|
Document(std::string version, std::string encoding);
|
||||||
|
|
||||||
void setRoot(const xmlelement &element);
|
void setRoot(const xmlelement& element);
|
||||||
xmlelement getRoot() const;
|
xmlelement getRoot() const;
|
||||||
|
|
||||||
const std::string& getVersion() const;
|
const std::string& getVersion() const;
|
||||||
@ -130,15 +132,17 @@ namespace xml {
|
|||||||
/// @return XML string
|
/// @return XML string
|
||||||
extern std::string stringify(
|
extern std::string stringify(
|
||||||
const xmldocument& document,
|
const xmldocument& document,
|
||||||
bool nice=true,
|
bool nice = true,
|
||||||
const std::string& indentStr=" "
|
const std::string& indentStr = " "
|
||||||
);
|
);
|
||||||
|
|
||||||
/// @brief Read XML Document from string
|
/// @brief Read XML Document from string
|
||||||
/// @param filename file name will be shown in error messages
|
/// @param filename file name will be shown in error messages
|
||||||
/// @param source xml source code string
|
/// @param source xml source code string
|
||||||
/// @return xml document
|
/// @return xml document
|
||||||
extern xmldocument parse(const std::string& filename, const std::string& source);
|
extern xmldocument parse(
|
||||||
|
const std::string& filename, const std::string& source
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_XML_HPP_
|
#endif // CODERS_XML_HPP_
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
#include "Content.hpp"
|
#include "Content.hpp"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../voxels/Block.hpp"
|
|
||||||
#include "../items/ItemDef.hpp"
|
#include "../items/ItemDef.hpp"
|
||||||
|
#include "../logic/scripting/scripting.hpp"
|
||||||
#include "../objects/EntityDef.hpp"
|
#include "../objects/EntityDef.hpp"
|
||||||
#include "../objects/rigging.hpp"
|
#include "../objects/rigging.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
#include "ContentPack.hpp"
|
#include "ContentPack.hpp"
|
||||||
#include "../logic/scripting/scripting.hpp"
|
|
||||||
|
|
||||||
ContentIndices::ContentIndices(
|
ContentIndices::ContentIndices(
|
||||||
ContentUnitIndices<Block> blocks,
|
ContentUnitIndices<Block> blocks,
|
||||||
ContentUnitIndices<ItemDef> items,
|
ContentUnitIndices<ItemDef> items,
|
||||||
ContentUnitIndices<EntityDef> entities
|
ContentUnitIndices<EntityDef> entities
|
||||||
) : blocks(std::move(blocks)),
|
)
|
||||||
items(std::move(items)),
|
: blocks(std::move(blocks)),
|
||||||
entities(std::move(entities))
|
items(std::move(items)),
|
||||||
{}
|
entities(std::move(entities)) {
|
||||||
|
}
|
||||||
|
|
||||||
Content::Content(
|
Content::Content(
|
||||||
std::unique_ptr<ContentIndices> indices,
|
std::unique_ptr<ContentIndices> indices,
|
||||||
@ -32,15 +32,15 @@ Content::Content(
|
|||||||
UptrsMap<std::string, BlockMaterial> blockMaterials,
|
UptrsMap<std::string, BlockMaterial> blockMaterials,
|
||||||
UptrsMap<std::string, rigging::SkeletonConfig> skeletons,
|
UptrsMap<std::string, rigging::SkeletonConfig> skeletons,
|
||||||
ResourceIndicesSet resourceIndices
|
ResourceIndicesSet resourceIndices
|
||||||
) : indices(std::move(indices)),
|
)
|
||||||
packs(std::move(packs)),
|
: indices(std::move(indices)),
|
||||||
blockMaterials(std::move(blockMaterials)),
|
packs(std::move(packs)),
|
||||||
skeletons(std::move(skeletons)),
|
blockMaterials(std::move(blockMaterials)),
|
||||||
blocks(std::move(blocks)),
|
skeletons(std::move(skeletons)),
|
||||||
items(std::move(items)),
|
blocks(std::move(blocks)),
|
||||||
entities(std::move(entities)),
|
items(std::move(items)),
|
||||||
drawGroups(std::move(drawGroups))
|
entities(std::move(entities)),
|
||||||
{
|
drawGroups(std::move(drawGroups)) {
|
||||||
for (size_t i = 0; i < RESOURCE_TYPES_COUNT; i++) {
|
for (size_t i = 0; i < RESOURCE_TYPES_COUNT; i++) {
|
||||||
this->resourceIndices[i] = std::move(resourceIndices[i]);
|
this->resourceIndices[i] = std::move(resourceIndices[i]);
|
||||||
}
|
}
|
||||||
@ -48,7 +48,8 @@ Content::Content(
|
|||||||
|
|
||||||
Content::~Content() = default;
|
Content::~Content() = default;
|
||||||
|
|
||||||
const rigging::SkeletonConfig* Content::getSkeleton(const std::string& id) const {
|
const rigging::SkeletonConfig* Content::getSkeleton(const std::string& id
|
||||||
|
) const {
|
||||||
auto found = skeletons.find(id);
|
auto found = skeletons.find(id);
|
||||||
if (found == skeletons.end()) {
|
if (found == skeletons.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -80,6 +81,7 @@ const UptrsMap<std::string, ContentPackRuntime>& Content::getPacks() const {
|
|||||||
return packs;
|
return packs;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UptrsMap<std::string, rigging::SkeletonConfig>& Content::getSkeletons() const {
|
const UptrsMap<std::string, rigging::SkeletonConfig>& Content::getSkeletons(
|
||||||
|
) const {
|
||||||
return skeletons;
|
return skeletons;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
#ifndef CONTENT_CONTENT_HPP_
|
#ifndef CONTENT_CONTENT_HPP_
|
||||||
#define CONTENT_CONTENT_HPP_
|
#define CONTENT_CONTENT_HPP_
|
||||||
|
|
||||||
#include "content_fwd.hpp"
|
|
||||||
|
|
||||||
#include "../data/dynamic_fwd.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../data/dynamic_fwd.hpp"
|
||||||
|
#include "content_fwd.hpp"
|
||||||
|
|
||||||
using DrawGroups = std::set<ubyte>;
|
using DrawGroups = std::set<ubyte>;
|
||||||
template<class K, class V>
|
template <class K, class V>
|
||||||
using UptrsMap = std::unordered_map<K, std::unique_ptr<V>>;
|
using UptrsMap = std::unordered_map<K, std::unique_ptr<V>>;
|
||||||
|
|
||||||
class Block;
|
class Block;
|
||||||
@ -28,31 +27,37 @@ namespace rigging {
|
|||||||
|
|
||||||
constexpr const char* contenttype_name(contenttype type) {
|
constexpr const char* contenttype_name(contenttype type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case contenttype::none: return "none";
|
case contenttype::none:
|
||||||
case contenttype::block: return "block";
|
return "none";
|
||||||
case contenttype::item: return "item";
|
case contenttype::block:
|
||||||
case contenttype::entity: return "entity";
|
return "block";
|
||||||
|
case contenttype::item:
|
||||||
|
return "item";
|
||||||
|
case contenttype::entity:
|
||||||
|
return "entity";
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class namereuse_error: public std::runtime_error {
|
class namereuse_error : public std::runtime_error {
|
||||||
contenttype type;
|
contenttype type;
|
||||||
public:
|
public:
|
||||||
namereuse_error(const std::string& msg, contenttype type)
|
namereuse_error(const std::string& msg, contenttype type)
|
||||||
: std::runtime_error(msg), type(type) {}
|
: std::runtime_error(msg), type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
inline contenttype getType() const {
|
inline contenttype getType() const {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
class ContentUnitIndices {
|
class ContentUnitIndices {
|
||||||
std::vector<T*> defs;
|
std::vector<T*> defs;
|
||||||
public:
|
public:
|
||||||
ContentUnitIndices(std::vector<T*> defs) : defs(std::move(defs)) {}
|
ContentUnitIndices(std::vector<T*> defs) : defs(std::move(defs)) {
|
||||||
|
}
|
||||||
|
|
||||||
inline T* get(blockid_t id) const {
|
inline T* get(blockid_t id) const {
|
||||||
if (id >= defs.size()) {
|
if (id >= defs.size()) {
|
||||||
@ -84,12 +89,11 @@ public:
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
class ContentUnitDefs {
|
class ContentUnitDefs {
|
||||||
UptrsMap<std::string, T> defs;
|
UptrsMap<std::string, T> defs;
|
||||||
public:
|
public:
|
||||||
ContentUnitDefs(UptrsMap<std::string, T> defs)
|
ContentUnitDefs(UptrsMap<std::string, T> defs) : defs(std::move(defs)) {
|
||||||
: defs(std::move(defs)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T* find(const std::string& id) const {
|
T* find(const std::string& id) const {
|
||||||
@ -102,7 +106,7 @@ public:
|
|||||||
T& require(const std::string& id) const {
|
T& require(const std::string& id) const {
|
||||||
const auto& found = defs.find(id);
|
const auto& found = defs.find(id);
|
||||||
if (found == defs.end()) {
|
if (found == defs.end()) {
|
||||||
throw std::runtime_error("missing content unit "+id);
|
throw std::runtime_error("missing content unit " + id);
|
||||||
}
|
}
|
||||||
return *found->second;
|
return *found->second;
|
||||||
}
|
}
|
||||||
@ -114,7 +118,7 @@ class ResourceIndices {
|
|||||||
std::unique_ptr<std::vector<dynamic::Map_sptr>> savedData;
|
std::unique_ptr<std::vector<dynamic::Map_sptr>> savedData;
|
||||||
public:
|
public:
|
||||||
ResourceIndices()
|
ResourceIndices()
|
||||||
: savedData(std::make_unique<std::vector<dynamic::Map_sptr>>()){
|
: savedData(std::make_unique<std::vector<dynamic::Map_sptr>>()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr size_t MISSING = SIZE_MAX;
|
static constexpr size_t MISSING = SIZE_MAX;
|
||||||
@ -152,8 +156,10 @@ public:
|
|||||||
|
|
||||||
constexpr const char* to_string(ResourceType type) {
|
constexpr const char* to_string(ResourceType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ResourceType::CAMERA: return "camera";
|
case ResourceType::CAMERA:
|
||||||
default: return "unknown";
|
return "camera";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,4 +215,4 @@ public:
|
|||||||
const UptrsMap<std::string, rigging::SkeletonConfig>& getSkeletons() const;
|
const UptrsMap<std::string, rigging::SkeletonConfig>& getSkeletons() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_HPP_
|
#endif // CONTENT_CONTENT_HPP_
|
||||||
|
|||||||
@ -66,9 +66,8 @@ std::unique_ptr<Content> ContentBuilder::build() {
|
|||||||
|
|
||||||
auto content = std::make_unique<Content>(
|
auto content = std::make_unique<Content>(
|
||||||
std::make_unique<ContentIndices>(
|
std::make_unique<ContentIndices>(
|
||||||
blockDefsIndices,
|
blockDefsIndices, itemDefsIndices, entityDefsIndices
|
||||||
itemDefsIndices,
|
),
|
||||||
entityDefsIndices),
|
|
||||||
std::move(groups),
|
std::move(groups),
|
||||||
blocks.build(),
|
blocks.build(),
|
||||||
items.build(),
|
items.build(),
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
#ifndef CONTENT_CONTENT_BUILDER_HPP_
|
#ifndef CONTENT_CONTENT_BUILDER_HPP_
|
||||||
#define CONTENT_CONTENT_BUILDER_HPP_
|
#define CONTENT_CONTENT_BUILDER_HPP_
|
||||||
|
|
||||||
#include "../items/ItemDef.hpp"
|
#include <memory>
|
||||||
#include "../voxels/Block.hpp"
|
#include <unordered_map>
|
||||||
#include "../objects/EntityDef.hpp"
|
#include <vector>
|
||||||
|
|
||||||
#include "../content/Content.hpp"
|
#include "../content/Content.hpp"
|
||||||
#include "../content/ContentPack.hpp"
|
#include "../content/ContentPack.hpp"
|
||||||
|
#include "../items/ItemDef.hpp"
|
||||||
|
#include "../objects/EntityDef.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
|
|
||||||
#include <memory>
|
template <class T>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class ContentUnitBuilder {
|
class ContentUnitBuilder {
|
||||||
std::unordered_map<std::string, contenttype>& allNames;
|
std::unordered_map<std::string, contenttype>& allNames;
|
||||||
contenttype type;
|
contenttype type;
|
||||||
@ -19,7 +19,9 @@ class ContentUnitBuilder {
|
|||||||
void checkIdentifier(const std::string& id) {
|
void checkIdentifier(const std::string& id) {
|
||||||
const auto& found = allNames.find(id);
|
const auto& found = allNames.find(id);
|
||||||
if (found != allNames.end()) {
|
if (found != allNames.end()) {
|
||||||
throw namereuse_error("name "+id+" is already used", found->second);
|
throw namereuse_error(
|
||||||
|
"name " + id + " is already used", found->second
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
@ -27,9 +29,10 @@ public:
|
|||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
|
|
||||||
ContentUnitBuilder(
|
ContentUnitBuilder(
|
||||||
std::unordered_map<std::string, contenttype>& allNames,
|
std::unordered_map<std::string, contenttype>& allNames, contenttype type
|
||||||
contenttype type
|
)
|
||||||
) : allNames(allNames), type(type) {}
|
: allNames(allNames), type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
T& create(const std::string& id) {
|
T& create(const std::string& id) {
|
||||||
auto found = defs.find(id);
|
auto found = defs.find(id);
|
||||||
@ -69,4 +72,4 @@ public:
|
|||||||
std::unique_ptr<Content> build();
|
std::unique_ptr<Content> build();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_BUILDER_HPP_
|
#endif // CONTENT_CONTENT_BUILDER_HPP_
|
||||||
|
|||||||
@ -1,26 +1,30 @@
|
|||||||
#include "ContentLUT.hpp"
|
#include "ContentLUT.hpp"
|
||||||
|
|
||||||
#include "Content.hpp"
|
|
||||||
#include "../constants.hpp"
|
|
||||||
#include "../files/files.hpp"
|
|
||||||
#include "../coders/json.hpp"
|
|
||||||
#include "../voxels/Block.hpp"
|
|
||||||
#include "../items/ItemDef.hpp"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
ContentLUT::ContentLUT(const ContentIndices* indices, size_t blocksCount, size_t itemsCount)
|
#include "../coders/json.hpp"
|
||||||
: blocks(blocksCount, indices->blocks, BLOCK_VOID, contenttype::block),
|
#include "../constants.hpp"
|
||||||
items(itemsCount, indices->items, ITEM_VOID, contenttype::item)
|
#include "../files/files.hpp"
|
||||||
{}
|
#include "../items/ItemDef.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
|
#include "Content.hpp"
|
||||||
|
|
||||||
template<class T> static constexpr size_t get_entries_count(
|
ContentLUT::ContentLUT(
|
||||||
const ContentUnitIndices<T>& indices, const dynamic::List_sptr& list) {
|
const ContentIndices* indices, size_t blocksCount, size_t itemsCount
|
||||||
|
)
|
||||||
|
: blocks(blocksCount, indices->blocks, BLOCK_VOID, contenttype::block),
|
||||||
|
items(itemsCount, indices->items, ITEM_VOID, contenttype::item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static constexpr size_t get_entries_count(
|
||||||
|
const ContentUnitIndices<T>& indices, const dynamic::List_sptr& list
|
||||||
|
) {
|
||||||
return list ? std::max(list->size(), indices.count()) : indices.count();
|
return list ? std::max(list->size(), indices.count()) : indices.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ContentLUT> ContentLUT::create(
|
std::shared_ptr<ContentLUT> ContentLUT::create(
|
||||||
const fs::path& filename,
|
const fs::path& filename, const Content* content
|
||||||
const Content* content
|
|
||||||
) {
|
) {
|
||||||
auto root = files::read_json(filename);
|
auto root = files::read_json(filename);
|
||||||
auto blocklist = root->list("blocks");
|
auto blocklist = root->list("blocks");
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
#ifndef CONTENT_CONTENT_LUT_HPP_
|
#ifndef CONTENT_CONTENT_LUT_HPP_
|
||||||
#define CONTENT_CONTENT_LUT_HPP_
|
#define CONTENT_CONTENT_LUT_HPP_
|
||||||
|
|
||||||
#include "Content.hpp"
|
#include <filesystem>
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../constants.hpp"
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
|
||||||
|
#include "../constants.hpp"
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
#include "Content.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ struct contententry {
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, class U>
|
template <typename T, class U>
|
||||||
class ContentUnitLUT {
|
class ContentUnitLUT {
|
||||||
std::vector<T> indices;
|
std::vector<T> indices;
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
@ -28,8 +27,13 @@ class ContentUnitLUT {
|
|||||||
T missingValue;
|
T missingValue;
|
||||||
contenttype type;
|
contenttype type;
|
||||||
public:
|
public:
|
||||||
ContentUnitLUT(size_t count, const ContentUnitIndices<U>& unitIndices, T missingValue, contenttype type)
|
ContentUnitLUT(
|
||||||
: missingValue(missingValue), type(type) {
|
size_t count,
|
||||||
|
const ContentUnitIndices<U>& unitIndices,
|
||||||
|
T missingValue,
|
||||||
|
contenttype type
|
||||||
|
)
|
||||||
|
: missingValue(missingValue), type(type) {
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
indices.push_back(i);
|
indices.push_back(i);
|
||||||
}
|
}
|
||||||
@ -97,8 +101,7 @@ public:
|
|||||||
ContentLUT(const ContentIndices* indices, size_t blocks, size_t items);
|
ContentLUT(const ContentIndices* indices, size_t blocks, size_t items);
|
||||||
|
|
||||||
static std::shared_ptr<ContentLUT> create(
|
static std::shared_ptr<ContentLUT> create(
|
||||||
const fs::path& filename,
|
const fs::path& filename, const Content* content
|
||||||
const Content* content
|
|
||||||
);
|
);
|
||||||
|
|
||||||
inline bool hasContentReorder() const {
|
inline bool hasContentReorder() const {
|
||||||
@ -111,4 +114,4 @@ public:
|
|||||||
std::vector<contententry> getMissingContent() const;
|
std::vector<contententry> getMissingContent() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_LUT_HPP_
|
#endif // CONTENT_CONTENT_LUT_HPP_
|
||||||
|
|||||||
@ -1,34 +1,33 @@
|
|||||||
#include "ContentLoader.hpp"
|
#include "ContentLoader.hpp"
|
||||||
|
|
||||||
#include "Content.hpp"
|
#include <algorithm>
|
||||||
#include "ContentPack.hpp"
|
#include <glm/glm.hpp>
|
||||||
#include "ContentBuilder.hpp"
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
#include "../core_defs.hpp"
|
#include "../core_defs.hpp"
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../debug/Logger.hpp"
|
#include "../debug/Logger.hpp"
|
||||||
#include "../files/files.hpp"
|
#include "../files/files.hpp"
|
||||||
#include "../items/ItemDef.hpp"
|
#include "../items/ItemDef.hpp"
|
||||||
#include "../objects/rigging.hpp"
|
|
||||||
#include "../logic/scripting/scripting.hpp"
|
#include "../logic/scripting/scripting.hpp"
|
||||||
|
#include "../objects/rigging.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
#include "../util/listutil.hpp"
|
#include "../util/listutil.hpp"
|
||||||
#include "../util/stringutil.hpp"
|
#include "../util/stringutil.hpp"
|
||||||
#include "../voxels/Block.hpp"
|
#include "../voxels/Block.hpp"
|
||||||
|
#include "Content.hpp"
|
||||||
#include <iostream>
|
#include "ContentBuilder.hpp"
|
||||||
#include <string>
|
#include "ContentPack.hpp"
|
||||||
#include <memory>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
static debug::Logger logger("content-loader");
|
static debug::Logger logger("content-loader");
|
||||||
|
|
||||||
ContentLoader::ContentLoader(ContentPack* pack, ContentBuilder& builder)
|
ContentLoader::ContentLoader(ContentPack* pack, ContentBuilder& builder)
|
||||||
: pack(pack), builder(builder)
|
: pack(pack), builder(builder) {
|
||||||
{
|
|
||||||
auto runtime = std::make_unique<ContentPackRuntime>(
|
auto runtime = std::make_unique<ContentPackRuntime>(
|
||||||
*pack, scripting::create_pack_environment(*pack)
|
*pack, scripting::create_pack_environment(*pack)
|
||||||
);
|
);
|
||||||
@ -97,9 +96,9 @@ bool ContentLoader::fixPackIndices(
|
|||||||
void ContentLoader::fixPackIndices() {
|
void ContentLoader::fixPackIndices() {
|
||||||
auto folder = pack->folder;
|
auto folder = pack->folder;
|
||||||
auto indexFile = pack->getContentFile();
|
auto indexFile = pack->getContentFile();
|
||||||
auto blocksFolder = folder/ContentPack::BLOCKS_FOLDER;
|
auto blocksFolder = folder / ContentPack::BLOCKS_FOLDER;
|
||||||
auto itemsFolder = folder/ContentPack::ITEMS_FOLDER;
|
auto itemsFolder = folder / ContentPack::ITEMS_FOLDER;
|
||||||
auto entitiesFolder = folder/ContentPack::ENTITIES_FOLDER;
|
auto entitiesFolder = folder / ContentPack::ENTITIES_FOLDER;
|
||||||
|
|
||||||
dynamic::Map_sptr root;
|
dynamic::Map_sptr root;
|
||||||
if (fs::is_regular_file(indexFile)) {
|
if (fs::is_regular_file(indexFile)) {
|
||||||
@ -113,13 +112,15 @@ void ContentLoader::fixPackIndices() {
|
|||||||
modified |= fixPackIndices(itemsFolder, root.get(), "items");
|
modified |= fixPackIndices(itemsFolder, root.get(), "items");
|
||||||
modified |= fixPackIndices(entitiesFolder, root.get(), "entities");
|
modified |= fixPackIndices(entitiesFolder, root.get(), "entities");
|
||||||
|
|
||||||
if (modified){
|
if (modified) {
|
||||||
// rewrite modified json
|
// rewrite modified json
|
||||||
files::write_json(indexFile, root.get());
|
files::write_json(indexFile, root.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::path& file) {
|
void ContentLoader::loadBlock(
|
||||||
|
Block& def, const std::string& name, const fs::path& file
|
||||||
|
) {
|
||||||
auto root = files::read_json(file);
|
auto root = files::read_json(file);
|
||||||
|
|
||||||
root->str("caption", def.caption);
|
root->str("caption", def.caption);
|
||||||
@ -181,16 +182,16 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
hitboxesIndex.b = glm::vec3(box->num(3), box->num(4), box->num(5));
|
hitboxesIndex.b = glm::vec3(box->num(3), box->num(4), box->num(5));
|
||||||
hitboxesIndex.b += hitboxesIndex.a;
|
hitboxesIndex.b += hitboxesIndex.a;
|
||||||
}
|
}
|
||||||
} else if ((boxarr = root->list("hitbox"))){
|
} else if ((boxarr = root->list("hitbox"))) {
|
||||||
AABB aabb;
|
AABB aabb;
|
||||||
aabb.a = glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
aabb.a = glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
||||||
aabb.b = glm::vec3(boxarr->num(3), boxarr->num(4), boxarr->num(5));
|
aabb.b = glm::vec3(boxarr->num(3), boxarr->num(4), boxarr->num(5));
|
||||||
aabb.b += aabb.a;
|
aabb.b += aabb.a;
|
||||||
def.hitboxes = { aabb };
|
def.hitboxes = {aabb};
|
||||||
} else if (!def.modelBoxes.empty()) {
|
} else if (!def.modelBoxes.empty()) {
|
||||||
def.hitboxes = def.modelBoxes;
|
def.hitboxes = def.modelBoxes;
|
||||||
} else {
|
} else {
|
||||||
def.hitboxes = { AABB() };
|
def.hitboxes = {AABB()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// block light emission [r, g, b] where r,g,b in range [0..15]
|
// block light emission [r, g, b] where r,g,b in range [0..15]
|
||||||
@ -206,7 +207,7 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
def.size.y = sizearr->num(1);
|
def.size.y = sizearr->num(1);
|
||||||
def.size.z = sizearr->num(2);
|
def.size.z = sizearr->num(2);
|
||||||
if (def.model == BlockModel::block &&
|
if (def.model == BlockModel::block &&
|
||||||
(def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) {
|
(def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) {
|
||||||
def.model = BlockModel::aabb;
|
def.model = BlockModel::aabb;
|
||||||
def.hitboxes = {AABB(def.size)};
|
def.hitboxes = {AABB(def.size)};
|
||||||
}
|
}
|
||||||
@ -233,7 +234,7 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
def.tickInterval = 1;
|
def.tickInterval = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def.hidden && def.pickingItem == def.name+BLOCK_ITEM_SUFFIX) {
|
if (def.hidden && def.pickingItem == def.name + BLOCK_ITEM_SUFFIX) {
|
||||||
def.pickingItem = CORE_EMPTY;
|
def.pickingItem = CORE_EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,12 +242,14 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
|
|||||||
void ContentLoader::loadCustomBlockModel(Block& def, dynamic::Map* primitives) {
|
void ContentLoader::loadCustomBlockModel(Block& def, dynamic::Map* primitives) {
|
||||||
if (primitives->has("aabbs")) {
|
if (primitives->has("aabbs")) {
|
||||||
auto modelboxes = primitives->list("aabbs");
|
auto modelboxes = primitives->list("aabbs");
|
||||||
for (uint i = 0; i < modelboxes->size(); i++ ) {
|
for (uint i = 0; i < modelboxes->size(); i++) {
|
||||||
/* Parse aabb */
|
/* Parse aabb */
|
||||||
auto boxarr = modelboxes->list(i);
|
auto boxarr = modelboxes->list(i);
|
||||||
AABB modelbox;
|
AABB modelbox;
|
||||||
modelbox.a = glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
modelbox.a =
|
||||||
modelbox.b = glm::vec3(boxarr->num(3), boxarr->num(4), boxarr->num(5));
|
glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
||||||
|
modelbox.b =
|
||||||
|
glm::vec3(boxarr->num(3), boxarr->num(4), boxarr->num(5));
|
||||||
modelbox.b += modelbox.a;
|
modelbox.b += modelbox.a;
|
||||||
def.modelBoxes.push_back(modelbox);
|
def.modelBoxes.push_back(modelbox);
|
||||||
|
|
||||||
@ -270,19 +273,21 @@ void ContentLoader::loadCustomBlockModel(Block& def, dynamic::Map* primitives) {
|
|||||||
/* Parse tetragon to points */
|
/* Parse tetragon to points */
|
||||||
auto tgonobj = modeltetragons->list(i);
|
auto tgonobj = modeltetragons->list(i);
|
||||||
glm::vec3 p1(tgonobj->num(0), tgonobj->num(1), tgonobj->num(2)),
|
glm::vec3 p1(tgonobj->num(0), tgonobj->num(1), tgonobj->num(2)),
|
||||||
xw(tgonobj->num(3), tgonobj->num(4), tgonobj->num(5)),
|
xw(tgonobj->num(3), tgonobj->num(4), tgonobj->num(5)),
|
||||||
yh(tgonobj->num(6), tgonobj->num(7), tgonobj->num(8));
|
yh(tgonobj->num(6), tgonobj->num(7), tgonobj->num(8));
|
||||||
def.modelExtraPoints.push_back(p1);
|
def.modelExtraPoints.push_back(p1);
|
||||||
def.modelExtraPoints.push_back(p1+xw);
|
def.modelExtraPoints.push_back(p1 + xw);
|
||||||
def.modelExtraPoints.push_back(p1+xw+yh);
|
def.modelExtraPoints.push_back(p1 + xw + yh);
|
||||||
def.modelExtraPoints.push_back(p1+yh);
|
def.modelExtraPoints.push_back(p1 + yh);
|
||||||
|
|
||||||
def.modelTextures.emplace_back(tgonobj->str(9));
|
def.modelTextures.emplace_back(tgonobj->str(9));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadItem(ItemDef& def, const std::string& name, const fs::path& file) {
|
void ContentLoader::loadItem(
|
||||||
|
ItemDef& def, const std::string& name, const fs::path& file
|
||||||
|
) {
|
||||||
auto root = files::read_json(file);
|
auto root = files::read_json(file);
|
||||||
root->str("caption", def.caption);
|
root->str("caption", def.caption);
|
||||||
|
|
||||||
@ -294,7 +299,7 @@ void ContentLoader::loadItem(ItemDef& def, const std::string& name, const fs::pa
|
|||||||
def.iconType = item_icon_type::block;
|
def.iconType = item_icon_type::block;
|
||||||
} else if (iconTypeStr == "sprite") {
|
} else if (iconTypeStr == "sprite") {
|
||||||
def.iconType = item_icon_type::sprite;
|
def.iconType = item_icon_type::sprite;
|
||||||
} else if (iconTypeStr.length()){
|
} else if (iconTypeStr.length()) {
|
||||||
logger.error() << name << ": unknown icon type" << iconTypeStr;
|
logger.error() << name << ": unknown icon type" << iconTypeStr;
|
||||||
}
|
}
|
||||||
root->str("icon", def.icon);
|
root->str("icon", def.icon);
|
||||||
@ -310,7 +315,9 @@ void ContentLoader::loadItem(ItemDef& def, const std::string& name, const fs::pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadEntity(EntityDef& def, const std::string& name, const fs::path& file) {
|
void ContentLoader::loadEntity(
|
||||||
|
EntityDef& def, const std::string& name, const fs::path& file
|
||||||
|
) {
|
||||||
auto root = files::read_json(file);
|
auto root = files::read_json(file);
|
||||||
if (auto componentsarr = root->list("components")) {
|
if (auto componentsarr = root->list("components")) {
|
||||||
for (size_t i = 0; i < componentsarr->size(); i++) {
|
for (size_t i = 0; i < componentsarr->size(); i++) {
|
||||||
@ -325,14 +332,21 @@ void ContentLoader::loadEntity(EntityDef& def, const std::string& name, const fs
|
|||||||
if (auto sensorarr = sensorsarr->list(i)) {
|
if (auto sensorarr = sensorsarr->list(i)) {
|
||||||
auto sensorType = sensorarr->str(0);
|
auto sensorType = sensorarr->str(0);
|
||||||
if (sensorType == "aabb") {
|
if (sensorType == "aabb") {
|
||||||
def.boxSensors.emplace_back(i, AABB{
|
def.boxSensors.emplace_back(
|
||||||
{sensorarr->num(1), sensorarr->num(2), sensorarr->num(3)},
|
i,
|
||||||
{sensorarr->num(4), sensorarr->num(5), sensorarr->num(6)}
|
AABB {
|
||||||
});
|
{sensorarr->num(1),
|
||||||
|
sensorarr->num(2),
|
||||||
|
sensorarr->num(3)},
|
||||||
|
{sensorarr->num(4),
|
||||||
|
sensorarr->num(5),
|
||||||
|
sensorarr->num(6)}}
|
||||||
|
);
|
||||||
} else if (sensorType == "radius") {
|
} else if (sensorType == "radius") {
|
||||||
def.radialSensors.emplace_back(i, sensorarr->num(1));
|
def.radialSensors.emplace_back(i, sensorarr->num(1));
|
||||||
} else {
|
} else {
|
||||||
logger.error() << name << ": sensor #" << i << " - unknown type "
|
logger.error()
|
||||||
|
<< name << ": sensor #" << i << " - unknown type "
|
||||||
<< util::quote(sensorType);
|
<< util::quote(sensorType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,23 +368,27 @@ void ContentLoader::loadEntity(EntityDef& def, const std::string& name, const fs
|
|||||||
root->flag("blocking", def.blocking);
|
root->flag("blocking", def.blocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadEntity(EntityDef& def, const std::string& full, const std::string& name) {
|
void ContentLoader::loadEntity(
|
||||||
|
EntityDef& def, const std::string& full, const std::string& name
|
||||||
|
) {
|
||||||
auto folder = pack->folder;
|
auto folder = pack->folder;
|
||||||
auto configFile = folder/fs::path("entities/"+name+".json");
|
auto configFile = folder / fs::path("entities/" + name + ".json");
|
||||||
if (fs::exists(configFile)) loadEntity(def, full, configFile);
|
if (fs::exists(configFile)) loadEntity(def, full, configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadBlock(Block& def, const std::string& full, const std::string& name) {
|
void ContentLoader::loadBlock(
|
||||||
|
Block& def, const std::string& full, const std::string& name
|
||||||
|
) {
|
||||||
auto folder = pack->folder;
|
auto folder = pack->folder;
|
||||||
auto configFile = folder/fs::path("blocks/"+name+".json");
|
auto configFile = folder / fs::path("blocks/" + name + ".json");
|
||||||
if (fs::exists(configFile)) loadBlock(def, full, configFile);
|
if (fs::exists(configFile)) loadBlock(def, full, configFile);
|
||||||
|
|
||||||
auto scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua");
|
auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua");
|
||||||
if (fs::is_regular_file(scriptfile)) {
|
if (fs::is_regular_file(scriptfile)) {
|
||||||
scripting::load_block_script(env, full, scriptfile, def.rt.funcsset);
|
scripting::load_block_script(env, full, scriptfile, def.rt.funcsset);
|
||||||
}
|
}
|
||||||
if (!def.hidden) {
|
if (!def.hidden) {
|
||||||
auto& item = builder.items.create(full+BLOCK_ITEM_SUFFIX);
|
auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX);
|
||||||
item.generated = true;
|
item.generated = true;
|
||||||
item.caption = def.caption;
|
item.caption = def.caption;
|
||||||
item.iconType = item_icon_type::block;
|
item.iconType = item_icon_type::block;
|
||||||
@ -384,18 +402,22 @@ void ContentLoader::loadBlock(Block& def, const std::string& full, const std::st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadItem(ItemDef& def, const std::string& full, const std::string& name) {
|
void ContentLoader::loadItem(
|
||||||
|
ItemDef& def, const std::string& full, const std::string& name
|
||||||
|
) {
|
||||||
auto folder = pack->folder;
|
auto folder = pack->folder;
|
||||||
auto configFile = folder/fs::path("items/"+name+".json");
|
auto configFile = folder / fs::path("items/" + name + ".json");
|
||||||
if (fs::exists(configFile)) loadItem(def, full, configFile);
|
if (fs::exists(configFile)) loadItem(def, full, configFile);
|
||||||
|
|
||||||
auto scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua");
|
auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua");
|
||||||
if (fs::is_regular_file(scriptfile)) {
|
if (fs::is_regular_file(scriptfile)) {
|
||||||
scripting::load_item_script(env, full, scriptfile, def.rt.funcsset);
|
scripting::load_item_script(env, full, scriptfile, def.rt.funcsset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadBlockMaterial(BlockMaterial& def, const fs::path& file) {
|
void ContentLoader::loadBlockMaterial(
|
||||||
|
BlockMaterial& def, const fs::path& file
|
||||||
|
) {
|
||||||
auto root = files::read_json(file);
|
auto root = files::read_json(file);
|
||||||
root->str("steps-sound", def.stepsSound);
|
root->str("steps-sound", def.stepsSound);
|
||||||
root->str("place-sound", def.placeSound);
|
root->str("place-sound", def.placeSound);
|
||||||
@ -409,13 +431,14 @@ void ContentLoader::load() {
|
|||||||
|
|
||||||
auto folder = pack->folder;
|
auto folder = pack->folder;
|
||||||
|
|
||||||
fs::path scriptFile = folder/fs::path("scripts/world.lua");
|
fs::path scriptFile = folder / fs::path("scripts/world.lua");
|
||||||
if (fs::is_regular_file(scriptFile)) {
|
if (fs::is_regular_file(scriptFile)) {
|
||||||
scripting::load_world_script(env, pack->id, scriptFile, runtime->worldfuncsset);
|
scripting::load_world_script(
|
||||||
|
env, pack->id, scriptFile, runtime->worldfuncsset
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs::is_regular_file(pack->getContentFile()))
|
if (!fs::is_regular_file(pack->getContentFile())) return;
|
||||||
return;
|
|
||||||
|
|
||||||
auto root = files::read_json(pack->getContentFile());
|
auto root = files::read_json(pack->getContentFile());
|
||||||
|
|
||||||
@ -423,10 +446,12 @@ void ContentLoader::load() {
|
|||||||
for (size_t i = 0; i < blocksarr->size(); i++) {
|
for (size_t i = 0; i < blocksarr->size(); i++) {
|
||||||
std::string name = blocksarr->str(i);
|
std::string name = blocksarr->str(i);
|
||||||
auto colon = name.find(':');
|
auto colon = name.find(':');
|
||||||
std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
|
std::string full =
|
||||||
|
colon == std::string::npos ? pack->id + ":" + name : name;
|
||||||
if (colon != std::string::npos) name[colon] = '/';
|
if (colon != std::string::npos) name[colon] = '/';
|
||||||
auto& def = builder.blocks.create(full);
|
auto& def = builder.blocks.create(full);
|
||||||
if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
|
if (colon != std::string::npos)
|
||||||
|
def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
|
||||||
loadBlock(def, full, name);
|
loadBlock(def, full, name);
|
||||||
stats->totalBlocks++;
|
stats->totalBlocks++;
|
||||||
}
|
}
|
||||||
@ -435,10 +460,12 @@ void ContentLoader::load() {
|
|||||||
for (size_t i = 0; i < itemsarr->size(); i++) {
|
for (size_t i = 0; i < itemsarr->size(); i++) {
|
||||||
std::string name = itemsarr->str(i);
|
std::string name = itemsarr->str(i);
|
||||||
auto colon = name.find(':');
|
auto colon = name.find(':');
|
||||||
std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
|
std::string full =
|
||||||
|
colon == std::string::npos ? pack->id + ":" + name : name;
|
||||||
if (colon != std::string::npos) name[colon] = '/';
|
if (colon != std::string::npos) name[colon] = '/';
|
||||||
auto& def = builder.items.create(full);
|
auto& def = builder.items.create(full);
|
||||||
if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
|
if (colon != std::string::npos)
|
||||||
|
def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
|
||||||
loadItem(def, full, name);
|
loadItem(def, full, name);
|
||||||
stats->totalItems++;
|
stats->totalItems++;
|
||||||
}
|
}
|
||||||
@ -448,7 +475,8 @@ void ContentLoader::load() {
|
|||||||
for (size_t i = 0; i < entitiesarr->size(); i++) {
|
for (size_t i = 0; i < entitiesarr->size(); i++) {
|
||||||
std::string name = entitiesarr->str(i);
|
std::string name = entitiesarr->str(i);
|
||||||
auto colon = name.find(':');
|
auto colon = name.find(':');
|
||||||
std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
|
std::string full =
|
||||||
|
colon == std::string::npos ? pack->id + ":" + name : name;
|
||||||
if (colon != std::string::npos) name[colon] = '/';
|
if (colon != std::string::npos) name[colon] = '/';
|
||||||
auto& def = builder.entities.create(full);
|
auto& def = builder.entities.create(full);
|
||||||
loadEntity(def, full, name);
|
loadEntity(def, full, name);
|
||||||
@ -460,7 +488,7 @@ void ContentLoader::load() {
|
|||||||
if (fs::is_directory(materialsDir)) {
|
if (fs::is_directory(materialsDir)) {
|
||||||
for (const auto& entry : fs::directory_iterator(materialsDir)) {
|
for (const auto& entry : fs::directory_iterator(materialsDir)) {
|
||||||
const fs::path& file = entry.path();
|
const fs::path& file = entry.path();
|
||||||
std::string name = pack->id+":"+file.stem().u8string();
|
std::string name = pack->id + ":" + file.stem().u8string();
|
||||||
loadBlockMaterial(builder.createBlockMaterial(name), file);
|
loadBlockMaterial(builder.createBlockMaterial(name), file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,9 +497,11 @@ void ContentLoader::load() {
|
|||||||
if (fs::is_directory(skeletonsDir)) {
|
if (fs::is_directory(skeletonsDir)) {
|
||||||
for (const auto& entry : fs::directory_iterator(skeletonsDir)) {
|
for (const auto& entry : fs::directory_iterator(skeletonsDir)) {
|
||||||
const fs::path& file = entry.path();
|
const fs::path& file = entry.path();
|
||||||
std::string name = pack->id+":"+file.stem().u8string();
|
std::string name = pack->id + ":" + file.stem().u8string();
|
||||||
std::string text = files::read_string(file);
|
std::string text = files::read_string(file);
|
||||||
builder.add(rigging::SkeletonConfig::parse(text, file.u8string(), name));
|
builder.add(
|
||||||
|
rigging::SkeletonConfig::parse(text, file.u8string(), name)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +510,7 @@ void ContentLoader::load() {
|
|||||||
for (const auto& entry : fs::directory_iterator(componentsDir)) {
|
for (const auto& entry : fs::directory_iterator(componentsDir)) {
|
||||||
fs::path scriptfile = entry.path();
|
fs::path scriptfile = entry.path();
|
||||||
if (fs::is_regular_file(scriptfile)) {
|
if (fs::is_regular_file(scriptfile)) {
|
||||||
auto name = pack->id+":"+scriptfile.stem().u8string();
|
auto name = pack->id + ":" + scriptfile.stem().u8string();
|
||||||
scripting::load_entity_component(name, scriptfile);
|
scripting::load_entity_component(name, scriptfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -504,6 +534,7 @@ void ContentLoader::load() {
|
|||||||
void ContentLoader::loadResources(ResourceType type, dynamic::List* list) {
|
void ContentLoader::loadResources(ResourceType type, dynamic::List* list) {
|
||||||
for (size_t i = 0; i < list->size(); i++) {
|
for (size_t i = 0; i < list->size(); i++) {
|
||||||
builder.resourceIndices[static_cast<size_t>(type)].add(
|
builder.resourceIndices[static_cast<size_t>(type)].add(
|
||||||
pack->id+":"+list->str(i), nullptr);
|
pack->id + ":" + list->str(i), nullptr
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#ifndef CONTENT_CONTENT_LOADER_HPP_
|
#ifndef CONTENT_CONTENT_LOADER_HPP_
|
||||||
#define CONTENT_CONTENT_LOADER_HPP_
|
#define CONTENT_CONTENT_LOADER_HPP_
|
||||||
|
|
||||||
#include "content_fwd.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "content_fwd.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -31,15 +31,27 @@ class ContentLoader {
|
|||||||
ContentBuilder& builder;
|
ContentBuilder& builder;
|
||||||
ContentPackStats* stats;
|
ContentPackStats* stats;
|
||||||
|
|
||||||
void loadBlock(Block& def, const std::string& full, const std::string& name);
|
void loadBlock(
|
||||||
void loadItem(ItemDef& def, const std::string& full, const std::string& name);
|
Block& def, const std::string& full, const std::string& name
|
||||||
void loadEntity(EntityDef& def, const std::string& full, const std::string& name);
|
);
|
||||||
|
void loadItem(
|
||||||
|
ItemDef& def, const std::string& full, const std::string& name
|
||||||
|
);
|
||||||
|
void loadEntity(
|
||||||
|
EntityDef& def, const std::string& full, const std::string& name
|
||||||
|
);
|
||||||
|
|
||||||
static void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
|
static void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
|
||||||
static void loadBlockMaterial(BlockMaterial& def, const fs::path& file);
|
static void loadBlockMaterial(BlockMaterial& def, const fs::path& file);
|
||||||
static void loadBlock(Block& def, const std::string& name, const fs::path& file);
|
static void loadBlock(
|
||||||
static void loadItem(ItemDef& def, const std::string& name, const fs::path& file);
|
Block& def, const std::string& name, const fs::path& file
|
||||||
static void loadEntity(EntityDef& def, const std::string& name, const fs::path& file);
|
);
|
||||||
|
static void loadItem(
|
||||||
|
ItemDef& def, const std::string& name, const fs::path& file
|
||||||
|
);
|
||||||
|
static void loadEntity(
|
||||||
|
EntityDef& def, const std::string& name, const fs::path& file
|
||||||
|
);
|
||||||
void loadResources(ResourceType type, dynamic::List* list);
|
void loadResources(ResourceType type, dynamic::List* list);
|
||||||
public:
|
public:
|
||||||
ContentLoader(ContentPack* pack, ContentBuilder& builder);
|
ContentLoader(ContentPack* pack, ContentBuilder& builder);
|
||||||
@ -53,4 +65,4 @@ public:
|
|||||||
void load();
|
void load();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_LOADER_HPP_
|
#endif // CONTENT_CONTENT_LOADER_HPP_
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
#include "ContentPack.hpp"
|
#include "ContentPack.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
#include "../files/files.hpp"
|
|
||||||
#include "../files/engine_paths.hpp"
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
|
#include "../files/engine_paths.hpp"
|
||||||
|
#include "../files/files.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
const std::vector<std::string> ContentPack::RESERVED_NAMES = {
|
const std::vector<std::string> ContentPack::RESERVED_NAMES = {
|
||||||
"res", "abs", "local", "core", "user", "world", "none", "null"
|
"res", "abs", "local", "core", "user", "world", "none", "null"};
|
||||||
};
|
|
||||||
|
|
||||||
contentpack_error::contentpack_error(
|
contentpack_error::contentpack_error(
|
||||||
std::string packId,
|
std::string packId, fs::path folder, const std::string& message
|
||||||
fs::path folder,
|
)
|
||||||
const std::string& message)
|
: std::runtime_error(message),
|
||||||
: std::runtime_error(message), packId(std::move(packId)), folder(std::move(folder)) {
|
packId(std::move(packId)),
|
||||||
|
folder(std::move(folder)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string contentpack_error::getPackId() const {
|
std::string contentpack_error::getPackId() const {
|
||||||
@ -30,36 +30,40 @@ fs::path contentpack_error::getFolder() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs::path ContentPack::getContentFile() const {
|
fs::path ContentPack::getContentFile() const {
|
||||||
return folder/fs::path(CONTENT_FILENAME);
|
return folder / fs::path(CONTENT_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContentPack::is_pack(const fs::path& folder) {
|
bool ContentPack::is_pack(const fs::path& folder) {
|
||||||
return fs::is_regular_file(folder/fs::path(PACKAGE_FILENAME));
|
return fs::is_regular_file(folder / fs::path(PACKAGE_FILENAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkContentPackId(const std::string& id, const fs::path& folder) {
|
static void checkContentPackId(const std::string& id, const fs::path& folder) {
|
||||||
if (id.length() < 2 || id.length() > 24)
|
if (id.length() < 2 || id.length() > 24)
|
||||||
throw contentpack_error(id, folder,
|
throw contentpack_error(
|
||||||
"content-pack id length is out of range [2, 24]");
|
id, folder, "content-pack id length is out of range [2, 24]"
|
||||||
|
);
|
||||||
if (isdigit(id[0]))
|
if (isdigit(id[0]))
|
||||||
throw contentpack_error(id, folder,
|
throw contentpack_error(
|
||||||
"content-pack id must not start with a digit");
|
id, folder, "content-pack id must not start with a digit"
|
||||||
|
);
|
||||||
for (char c : id) {
|
for (char c : id) {
|
||||||
if (!isalnum(c) && c != '_') {
|
if (!isalnum(c) && c != '_') {
|
||||||
throw contentpack_error(id, folder,
|
throw contentpack_error(
|
||||||
"illegal character in content-pack id");
|
id, folder, "illegal character in content-pack id"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (std::find(ContentPack::RESERVED_NAMES.begin(),
|
if (std::find(
|
||||||
ContentPack::RESERVED_NAMES.end(), id)
|
ContentPack::RESERVED_NAMES.begin(),
|
||||||
!= ContentPack::RESERVED_NAMES.end()) {
|
ContentPack::RESERVED_NAMES.end(),
|
||||||
throw contentpack_error(id, folder,
|
id
|
||||||
"this content-pack id is reserved");
|
) != ContentPack::RESERVED_NAMES.end()) {
|
||||||
|
throw contentpack_error(id, folder, "this content-pack id is reserved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentPack ContentPack::read(const fs::path& folder) {
|
ContentPack ContentPack::read(const fs::path& folder) {
|
||||||
auto root = files::read_json(folder/fs::path(PACKAGE_FILENAME));
|
auto root = files::read_json(folder / fs::path(PACKAGE_FILENAME));
|
||||||
ContentPack pack;
|
ContentPack pack;
|
||||||
root->str("id", pack.id);
|
root->str("id", pack.id);
|
||||||
root->str("title", pack.title);
|
root->str("title", pack.title);
|
||||||
@ -78,26 +82,24 @@ ContentPack ContentPack::read(const fs::path& folder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pack.id == "none")
|
if (pack.id == "none")
|
||||||
throw contentpack_error(pack.id, folder,
|
throw contentpack_error(
|
||||||
"content-pack id is not specified");
|
pack.id, folder, "content-pack id is not specified"
|
||||||
|
);
|
||||||
checkContentPackId(pack.id, folder);
|
checkContentPackId(pack.id, folder);
|
||||||
|
|
||||||
return pack;
|
return pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentPack::scanFolder(
|
void ContentPack::scanFolder(
|
||||||
const fs::path& folder,
|
const fs::path& folder, std::vector<ContentPack>& packs
|
||||||
std::vector<ContentPack>& packs
|
|
||||||
) {
|
) {
|
||||||
if (!fs::is_directory(folder)) {
|
if (!fs::is_directory(folder)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||||
const fs::path& folder = entry.path();
|
const fs::path& folder = entry.path();
|
||||||
if (!fs::is_directory(folder))
|
if (!fs::is_directory(folder)) continue;
|
||||||
continue;
|
if (!is_pack(folder)) continue;
|
||||||
if (!is_pack(folder))
|
|
||||||
continue;
|
|
||||||
try {
|
try {
|
||||||
packs.push_back(read(folder));
|
packs.push_back(read(folder));
|
||||||
} catch (const contentpack_error& err) {
|
} catch (const contentpack_error& err) {
|
||||||
@ -119,7 +121,9 @@ std::vector<std::string> ContentPack::worldPacksList(const fs::path& folder) {
|
|||||||
return files::read_list(listfile);
|
return files::read_list(listfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path ContentPack::findPack(const EnginePaths* paths, const fs::path& worldDir, const std::string& name) {
|
fs::path ContentPack::findPack(
|
||||||
|
const EnginePaths* paths, const fs::path& worldDir, const std::string& name
|
||||||
|
) {
|
||||||
fs::path folder = worldDir / fs::path("content") / fs::path(name);
|
fs::path folder = worldDir / fs::path("content") / fs::path(name);
|
||||||
if (fs::is_directory(folder)) {
|
if (fs::is_directory(folder)) {
|
||||||
return folder;
|
return folder;
|
||||||
@ -135,11 +139,8 @@ fs::path ContentPack::findPack(const EnginePaths* paths, const fs::path& worldDi
|
|||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentPackRuntime::ContentPackRuntime(
|
ContentPackRuntime::ContentPackRuntime(ContentPack info, scriptenv env)
|
||||||
ContentPack info,
|
: info(std::move(info)), env(std::move(env)) {
|
||||||
scriptenv env
|
|
||||||
) : info(std::move(info)), env(std::move(env))
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentPackRuntime::~ContentPackRuntime() = default;
|
ContentPackRuntime::~ContentPackRuntime() = default;
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef CONTENT_CONTENT_PACK_HPP_
|
#ifndef CONTENT_CONTENT_PACK_HPP_
|
||||||
#define CONTENT_CONTENT_PACK_HPP_
|
#define CONTENT_CONTENT_PACK_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdexcept>
|
|
||||||
#include <filesystem>
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
class EnginePaths;
|
class EnginePaths;
|
||||||
|
|
||||||
@ -16,19 +16,20 @@ class contentpack_error : public std::runtime_error {
|
|||||||
std::string packId;
|
std::string packId;
|
||||||
fs::path folder;
|
fs::path folder;
|
||||||
public:
|
public:
|
||||||
contentpack_error(std::string packId, fs::path folder, const std::string& message);
|
contentpack_error(
|
||||||
|
std::string packId, fs::path folder, const std::string& message
|
||||||
|
);
|
||||||
|
|
||||||
std::string getPackId() const;
|
std::string getPackId() const;
|
||||||
fs::path getFolder() const;
|
fs::path getFolder() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DependencyLevel {
|
enum class DependencyLevel {
|
||||||
required, // dependency must be installed
|
required, // dependency must be installed
|
||||||
optional, // dependency will be installed if found
|
optional, // dependency will be installed if found
|
||||||
weak, // only affects packs order
|
weak, // only affects packs order
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// @brief Content-pack that should be installed earlier the dependent
|
/// @brief Content-pack that should be installed earlier the dependent
|
||||||
struct DependencyPack {
|
struct DependencyPack {
|
||||||
DependencyLevel level;
|
DependencyLevel level;
|
||||||
@ -57,8 +58,7 @@ struct ContentPack {
|
|||||||
static ContentPack read(const fs::path& folder);
|
static ContentPack read(const fs::path& folder);
|
||||||
|
|
||||||
static void scanFolder(
|
static void scanFolder(
|
||||||
const fs::path& folder,
|
const fs::path& folder, std::vector<ContentPack>& packs
|
||||||
std::vector<ContentPack>& packs
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static std::vector<std::string> worldPacksList(const fs::path& folder);
|
static std::vector<std::string> worldPacksList(const fs::path& folder);
|
||||||
@ -92,10 +92,7 @@ class ContentPackRuntime {
|
|||||||
public:
|
public:
|
||||||
world_funcs_set worldfuncsset {};
|
world_funcs_set worldfuncsset {};
|
||||||
|
|
||||||
ContentPackRuntime(
|
ContentPackRuntime(ContentPack info, scriptenv env);
|
||||||
ContentPack info,
|
|
||||||
scriptenv env
|
|
||||||
);
|
|
||||||
~ContentPackRuntime();
|
~ContentPackRuntime();
|
||||||
|
|
||||||
inline const ContentPackStats& getStats() const {
|
inline const ContentPackStats& getStats() const {
|
||||||
@ -119,4 +116,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_PACK_HPP_
|
#endif // CONTENT_CONTENT_PACK_HPP_
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#include "PacksManager.hpp"
|
#include "PacksManager.hpp"
|
||||||
|
|
||||||
#include "../util/listutil.hpp"
|
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "../util/listutil.hpp"
|
||||||
|
|
||||||
PacksManager::PacksManager() = default;
|
PacksManager::PacksManager() = default;
|
||||||
|
|
||||||
void PacksManager::setSources(std::vector<fs::path> sources) {
|
void PacksManager::setSources(std::vector<fs::path> sources) {
|
||||||
@ -35,7 +35,9 @@ std::vector<std::string> PacksManager::getAllNames() const {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ContentPack> PacksManager::getAll(const std::vector<std::string>& names) const {
|
std::vector<ContentPack> PacksManager::getAll(
|
||||||
|
const std::vector<std::string>& names
|
||||||
|
) const {
|
||||||
std::vector<ContentPack> packsList;
|
std::vector<ContentPack> packsList;
|
||||||
for (auto& name : names) {
|
for (auto& name : names) {
|
||||||
auto found = packs.find(name);
|
auto found = packs.find(name);
|
||||||
@ -47,7 +49,9 @@ std::vector<ContentPack> PacksManager::getAll(const std::vector<std::string>& na
|
|||||||
return packsList;
|
return packsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
static contentpack_error on_circular_dependency(std::queue<const ContentPack*>& queue) {
|
static contentpack_error on_circular_dependency(
|
||||||
|
std::queue<const ContentPack*>& queue
|
||||||
|
) {
|
||||||
const ContentPack* lastPack = queue.back();
|
const ContentPack* lastPack = queue.back();
|
||||||
// circular dependency
|
// circular dependency
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@ -66,10 +70,12 @@ static contentpack_error on_circular_dependency(std::queue<const ContentPack*>&
|
|||||||
/// @param allNames all already done or enqueued packs
|
/// @param allNames all already done or enqueued packs
|
||||||
/// @param added packs with all dependencies resolved
|
/// @param added packs with all dependencies resolved
|
||||||
/// @param queue current pass queue
|
/// @param queue current pass queue
|
||||||
/// @param resolveWeaks make weak dependencies resolved if found but not added to queue
|
/// @param resolveWeaks make weak dependencies resolved if found but not added
|
||||||
/// @return true if all dependencies are already added or not found (optional/weak)
|
/// to queue
|
||||||
|
/// @return true if all dependencies are already added or not found
|
||||||
|
/// (optional/weak)
|
||||||
/// @throws contentpack_error if required dependency is not found
|
/// @throws contentpack_error if required dependency is not found
|
||||||
static bool resolve_dependencies (
|
static bool resolve_dependencies(
|
||||||
const ContentPack* pack,
|
const ContentPack* pack,
|
||||||
const std::unordered_map<std::string, ContentPack>& packs,
|
const std::unordered_map<std::string, ContentPack>& packs,
|
||||||
std::vector<std::string>& allNames,
|
std::vector<std::string>& allNames,
|
||||||
@ -85,7 +91,9 @@ static bool resolve_dependencies (
|
|||||||
auto found = packs.find(dep.id);
|
auto found = packs.find(dep.id);
|
||||||
bool exists = found != packs.end();
|
bool exists = found != packs.end();
|
||||||
if (!exists && dep.level == DependencyLevel::required) {
|
if (!exists && dep.level == DependencyLevel::required) {
|
||||||
throw contentpack_error(dep.id, fs::path(), "dependency of '"+pack->id+"'");
|
throw contentpack_error(
|
||||||
|
dep.id, fs::path(), "dependency of '" + pack->id + "'"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
// ignored for optional or weak dependencies
|
// ignored for optional or weak dependencies
|
||||||
@ -93,11 +101,13 @@ static bool resolve_dependencies (
|
|||||||
}
|
}
|
||||||
if (resolveWeaks && dep.level == DependencyLevel::weak) {
|
if (resolveWeaks && dep.level == DependencyLevel::weak) {
|
||||||
// dependency pack is found but not added yet
|
// dependency pack is found but not added yet
|
||||||
// resolveWeaks is used on second iteration, so it's will not be added
|
// resolveWeaks is used on second iteration, so it's will not be
|
||||||
|
// added
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!util::contains(allNames, dep.id) && dep.level != DependencyLevel::weak) {
|
if (!util::contains(allNames, dep.id) &&
|
||||||
|
dep.level != DependencyLevel::weak) {
|
||||||
allNames.push_back(dep.id);
|
allNames.push_back(dep.id);
|
||||||
queue.push(&found->second);
|
queue.push(&found->second);
|
||||||
}
|
}
|
||||||
@ -106,7 +116,9 @@ static bool resolve_dependencies (
|
|||||||
return satisfied;
|
return satisfied;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> PacksManager::assembly(const std::vector<std::string>& names) const {
|
std::vector<std::string> PacksManager::assembly(
|
||||||
|
const std::vector<std::string>& names
|
||||||
|
) const {
|
||||||
std::vector<std::string> allNames = names;
|
std::vector<std::string> allNames = names;
|
||||||
std::vector<std::string> added;
|
std::vector<std::string> added;
|
||||||
std::queue<const ContentPack*> queue;
|
std::queue<const ContentPack*> queue;
|
||||||
@ -127,9 +139,13 @@ std::vector<std::string> PacksManager::assembly(const std::vector<std::string>&
|
|||||||
auto* pack = queue.front();
|
auto* pack = queue.front();
|
||||||
queue.pop();
|
queue.pop();
|
||||||
|
|
||||||
if (resolve_dependencies(pack, packs, allNames, added, queue, resolveWeaks)) {
|
if (resolve_dependencies(
|
||||||
|
pack, packs, allNames, added, queue, resolveWeaks
|
||||||
|
)) {
|
||||||
if (util::contains(added, pack->id)) {
|
if (util::contains(added, pack->id)) {
|
||||||
throw contentpack_error(pack->id, pack->folder, "pack duplication");
|
throw contentpack_error(
|
||||||
|
pack->id, pack->folder, "pack duplication"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
added.push_back(pack->id);
|
added.push_back(pack->id);
|
||||||
addedInIteration++;
|
addedInIteration++;
|
||||||
@ -148,7 +164,9 @@ std::vector<std::string> PacksManager::assembly(const std::vector<std::string>&
|
|||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> PacksManager::getNames(const std::vector<ContentPack>& packs) {
|
std::vector<std::string> PacksManager::getNames(
|
||||||
|
const std::vector<ContentPack>& packs
|
||||||
|
) {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
for (const auto& pack : packs) {
|
for (const auto& pack : packs) {
|
||||||
result.push_back(pack.id);
|
result.push_back(pack.id);
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#ifndef CONTENT_PACKS_MANAGER_HPP_
|
#ifndef CONTENT_PACKS_MANAGER_HPP_
|
||||||
#define CONTENT_PACKS_MANAGER_HPP_
|
#define CONTENT_PACKS_MANAGER_HPP_
|
||||||
|
|
||||||
#include "ContentPack.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ContentPack.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -31,17 +31,21 @@ public:
|
|||||||
/// @brief Get packs by names (id)
|
/// @brief Get packs by names (id)
|
||||||
/// @param names pack names
|
/// @param names pack names
|
||||||
/// @throws contentpack_error if pack not found
|
/// @throws contentpack_error if pack not found
|
||||||
std::vector<ContentPack> getAll(const std::vector<std::string>& names) const;
|
std::vector<ContentPack> getAll(const std::vector<std::string>& names
|
||||||
|
) const;
|
||||||
|
|
||||||
/// @brief Resolve all dependencies and fix packs order
|
/// @brief Resolve all dependencies and fix packs order
|
||||||
/// @param names required packs (method can add extra packs)
|
/// @param names required packs (method can add extra packs)
|
||||||
/// @return resulting ordered vector of pack names
|
/// @return resulting ordered vector of pack names
|
||||||
/// @throws contentpack_error if required dependency not found or
|
/// @throws contentpack_error if required dependency not found or
|
||||||
/// circular dependency detected
|
/// circular dependency detected
|
||||||
std::vector<std::string> assembly(const std::vector<std::string>& names) const;
|
std::vector<std::string> assembly(const std::vector<std::string>& names
|
||||||
|
) const;
|
||||||
|
|
||||||
/// @brief Collect all pack names (identifiers) into a new vector
|
/// @brief Collect all pack names (identifiers) into a new vector
|
||||||
static std::vector<std::string> getNames(const std::vector<ContentPack>& packs);
|
static std::vector<std::string> getNames(
|
||||||
|
const std::vector<ContentPack>& packs
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTENT_PACKS_MANAGER_HPP_
|
#endif // CONTENT_PACKS_MANAGER_HPP_
|
||||||
|
|||||||
@ -6,15 +6,11 @@
|
|||||||
class Content;
|
class Content;
|
||||||
class ContentPackRuntime;
|
class ContentPackRuntime;
|
||||||
|
|
||||||
enum class contenttype {
|
enum class contenttype { none, block, item, entity };
|
||||||
none, block, item, entity
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ResourceType : size_t {
|
enum class ResourceType : size_t { CAMERA, LAST = CAMERA };
|
||||||
CAMERA,
|
|
||||||
LAST=CAMERA
|
|
||||||
};
|
|
||||||
|
|
||||||
inline constexpr auto RESOURCE_TYPES_COUNT = static_cast<size_t>(ResourceType::LAST)+1;
|
inline constexpr auto RESOURCE_TYPES_COUNT =
|
||||||
|
static_cast<size_t>(ResourceType::LAST) + 1;
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_FWD_HPP_
|
#endif // CONTENT_CONTENT_FWD_HPP_
|
||||||
|
|||||||
@ -14,7 +14,9 @@ std::ostream& operator<<(std::ostream& stream, const dynamic::Map_sptr& value) {
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& stream, const dynamic::List_sptr& value) {
|
std::ostream& operator<<(
|
||||||
|
std::ostream& stream, const dynamic::List_sptr& value
|
||||||
|
) {
|
||||||
stream << json::stringify(value, false, " ");
|
stream << json::stringify(value, false, " ");
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
@ -22,10 +24,14 @@ std::ostream& operator<<(std::ostream& stream, const dynamic::List_sptr& value)
|
|||||||
std::string List::str(size_t index) const {
|
std::string List::str(size_t index) const {
|
||||||
const auto& value = values[index];
|
const auto& value = values[index];
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::string: return std::get<std::string>(value);
|
case Type::string:
|
||||||
case Type::boolean: return std::get<bool>(value) ? "true" : "false";
|
return std::get<std::string>(value);
|
||||||
case Type::number: return std::to_string(std::get<double>(value));
|
case Type::boolean:
|
||||||
case Type::integer: return std::to_string(std::get<int64_t>(value));
|
return std::get<bool>(value) ? "true" : "false";
|
||||||
|
case Type::number:
|
||||||
|
return std::to_string(std::get<double>(value));
|
||||||
|
case Type::integer:
|
||||||
|
return std::to_string(std::get<int64_t>(value));
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("type error");
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
@ -34,10 +40,14 @@ std::string List::str(size_t index) const {
|
|||||||
number_t List::num(size_t index) const {
|
number_t List::num(size_t index) const {
|
||||||
const auto& value = values[index];
|
const auto& value = values[index];
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::number: return std::get<number_t>(value);
|
case Type::number:
|
||||||
case Type::integer: return std::get<integer_t>(value);
|
return std::get<number_t>(value);
|
||||||
case Type::string: return std::stoll(std::get<std::string>(value));
|
case Type::integer:
|
||||||
case Type::boolean: return std::get<bool>(value);
|
return std::get<integer_t>(value);
|
||||||
|
case Type::string:
|
||||||
|
return std::stoll(std::get<std::string>(value));
|
||||||
|
case Type::boolean:
|
||||||
|
return std::get<bool>(value);
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("type error");
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
@ -46,10 +56,14 @@ number_t List::num(size_t index) const {
|
|||||||
integer_t List::integer(size_t index) const {
|
integer_t List::integer(size_t index) const {
|
||||||
const auto& value = values[index];
|
const auto& value = values[index];
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::number: return std::get<number_t>(value);
|
case Type::number:
|
||||||
case Type::integer: return std::get<integer_t>(value);
|
return std::get<number_t>(value);
|
||||||
case Type::string: return std::stoll(std::get<std::string>(value));
|
case Type::integer:
|
||||||
case Type::boolean: return std::get<bool>(value);
|
return std::get<integer_t>(value);
|
||||||
|
case Type::string:
|
||||||
|
return std::stoll(std::get<std::string>(value));
|
||||||
|
case Type::boolean:
|
||||||
|
return std::get<bool>(value);
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("type error");
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
@ -74,8 +88,10 @@ List* List::list(size_t index) const {
|
|||||||
bool List::flag(size_t index) const {
|
bool List::flag(size_t index) const {
|
||||||
const auto& value = values[index];
|
const auto& value = values[index];
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::integer: return std::get<integer_t>(value);
|
case Type::integer:
|
||||||
case Type::boolean: return std::get<bool>(value);
|
return std::get<integer_t>(value);
|
||||||
|
case Type::boolean:
|
||||||
|
return std::get<bool>(value);
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("type error");
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
@ -112,55 +128,69 @@ void Map::str(const std::string& key, std::string& dst) const {
|
|||||||
|
|
||||||
std::string Map::get(const std::string& key, const std::string& def) const {
|
std::string Map::get(const std::string& key, const std::string& def) const {
|
||||||
auto found = values.find(key);
|
auto found = values.find(key);
|
||||||
if (found == values.end())
|
if (found == values.end()) return def;
|
||||||
return def;
|
|
||||||
auto& value = found->second;
|
auto& value = found->second;
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::string: return std::get<std::string>(value);
|
case Type::string:
|
||||||
case Type::boolean: return std::get<bool>(value) ? "true" : "false";
|
return std::get<std::string>(value);
|
||||||
case Type::number: return std::to_string(std::get<number_t>(value));
|
case Type::boolean:
|
||||||
case Type::integer: return std::to_string(std::get<integer_t>(value));
|
return std::get<bool>(value) ? "true" : "false";
|
||||||
default: throw std::runtime_error("type error");
|
case Type::number:
|
||||||
|
return std::to_string(std::get<number_t>(value));
|
||||||
|
case Type::integer:
|
||||||
|
return std::to_string(std::get<integer_t>(value));
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
number_t Map::get(const std::string& key, double def) const {
|
number_t Map::get(const std::string& key, double def) const {
|
||||||
auto found = values.find(key);
|
auto found = values.find(key);
|
||||||
if (found == values.end())
|
if (found == values.end()) return def;
|
||||||
return def;
|
|
||||||
auto& value = found->second;
|
auto& value = found->second;
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::number: return std::get<number_t>(value);
|
case Type::number:
|
||||||
case Type::integer: return std::get<integer_t>(value);
|
return std::get<number_t>(value);
|
||||||
case Type::string: return std::stoull(std::get<std::string>(value));
|
case Type::integer:
|
||||||
case Type::boolean: return std::get<bool>(value);
|
return std::get<integer_t>(value);
|
||||||
default: throw std::runtime_error("type error");
|
case Type::string:
|
||||||
|
return std::stoull(std::get<std::string>(value));
|
||||||
|
case Type::boolean:
|
||||||
|
return std::get<bool>(value);
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
integer_t Map::get(const std::string& key, integer_t def) const {
|
integer_t Map::get(const std::string& key, integer_t def) const {
|
||||||
auto found = values.find(key);
|
auto found = values.find(key);
|
||||||
if (found == values.end())
|
if (found == values.end()) return def;
|
||||||
return def;
|
|
||||||
auto& value = found->second;
|
auto& value = found->second;
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::number: return std::get<number_t>(value);
|
case Type::number:
|
||||||
case Type::integer: return std::get<integer_t>(value);
|
return std::get<number_t>(value);
|
||||||
case Type::string: return std::stoull(std::get<std::string>(value));
|
case Type::integer:
|
||||||
case Type::boolean: return std::get<bool>(value);
|
return std::get<integer_t>(value);
|
||||||
default: throw std::runtime_error("type error");
|
case Type::string:
|
||||||
|
return std::stoull(std::get<std::string>(value));
|
||||||
|
case Type::boolean:
|
||||||
|
return std::get<bool>(value);
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::get(const std::string& key, bool def) const {
|
bool Map::get(const std::string& key, bool def) const {
|
||||||
auto found = values.find(key);
|
auto found = values.find(key);
|
||||||
if (found == values.end())
|
if (found == values.end()) return def;
|
||||||
return def;
|
|
||||||
auto& value = found->second;
|
auto& value = found->second;
|
||||||
switch (static_cast<Type>(value.index())) {
|
switch (static_cast<Type>(value.index())) {
|
||||||
case Type::integer: return std::get<integer_t>(value);
|
case Type::integer:
|
||||||
case Type::boolean: return std::get<bool>(value);
|
return std::get<integer_t>(value);
|
||||||
default: throw std::runtime_error("type error");
|
case Type::boolean:
|
||||||
|
return std::get<bool>(value);
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("type error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,8 +234,7 @@ Map_sptr Map::map(const std::string& key) const {
|
|||||||
|
|
||||||
List_sptr Map::list(const std::string& key) const {
|
List_sptr Map::list(const std::string& key) const {
|
||||||
auto found = values.find(key);
|
auto found = values.find(key);
|
||||||
if (found != values.end())
|
if (found != values.end()) return std::get<List_sptr>(found->second);
|
||||||
return std::get<List_sptr>(found->second);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +289,9 @@ List_sptr dynamic::create_list(std::initializer_list<Value> values) {
|
|||||||
return std::make_shared<List>(values);
|
return std::make_shared<List>(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map_sptr dynamic::create_map(std::initializer_list<std::pair<const std::string, Value>> entries) {
|
Map_sptr dynamic::create_map(
|
||||||
|
std::initializer_list<std::pair<const std::string, Value>> entries
|
||||||
|
) {
|
||||||
return std::make_shared<Map>(entries);
|
return std::make_shared<Map>(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,12 +301,12 @@ number_t dynamic::get_number(const Value& value) {
|
|||||||
} else if (auto num = std::get_if<integer_t>(&value)) {
|
} else if (auto num = std::get_if<integer_t>(&value)) {
|
||||||
return *num;
|
return *num;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("cannot cast "+type_name(value)+" to number");
|
throw std::runtime_error("cannot cast " + type_name(value) + " to number");
|
||||||
}
|
}
|
||||||
|
|
||||||
integer_t dynamic::get_integer(const Value& value) {
|
integer_t dynamic::get_integer(const Value& value) {
|
||||||
if (auto num = std::get_if<integer_t>(&value)) {
|
if (auto num = std::get_if<integer_t>(&value)) {
|
||||||
return *num;
|
return *num;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("cannot cast "+type_name(value)+" to integer");
|
throw std::runtime_error("cannot cast " + type_name(value) + " to integer");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +1,24 @@
|
|||||||
#ifndef DATA_DYNAMIC_HPP_
|
#ifndef DATA_DYNAMIC_HPP_
|
||||||
#define DATA_DYNAMIC_HPP_
|
#define DATA_DYNAMIC_HPP_
|
||||||
|
|
||||||
#include "dynamic_fwd.hpp"
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dynamic_fwd.hpp"
|
||||||
|
|
||||||
namespace dynamic {
|
namespace dynamic {
|
||||||
enum class Type {
|
enum class Type { none = 0, map, list, string, number, boolean, integer };
|
||||||
none=0, map, list, string, number, boolean, integer
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::string& type_name(const Value& value);
|
const std::string& type_name(const Value& value);
|
||||||
List_sptr create_list(std::initializer_list<Value> values={});
|
List_sptr create_list(std::initializer_list<Value> values = {});
|
||||||
Map_sptr create_map(std::initializer_list<std::pair<const std::string, Value>> entries={});
|
Map_sptr create_map(
|
||||||
|
std::initializer_list<std::pair<const std::string, Value>> entries = {}
|
||||||
|
);
|
||||||
number_t get_number(const Value& value);
|
number_t get_number(const Value& value);
|
||||||
integer_t get_integer(const Value& value);
|
integer_t get_integer(const Value& value);
|
||||||
|
|
||||||
@ -42,7 +41,8 @@ namespace dynamic {
|
|||||||
std::vector<Value> values;
|
std::vector<Value> values;
|
||||||
|
|
||||||
List() = default;
|
List() = default;
|
||||||
List(std::vector<Value> values) : values(std::move(values)) {}
|
List(std::vector<Value> values) : values(std::move(values)) {
|
||||||
|
}
|
||||||
|
|
||||||
std::string str(size_t index) const;
|
std::string str(size_t index) const;
|
||||||
number_t num(size_t index) const;
|
number_t num(size_t index) const;
|
||||||
@ -81,12 +81,12 @@ namespace dynamic {
|
|||||||
|
|
||||||
Map() = default;
|
Map() = default;
|
||||||
Map(std::unordered_map<std::string, Value> values)
|
Map(std::unordered_map<std::string, Value> values)
|
||||||
: values(std::move(values)) {};
|
: values(std::move(values)) {};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T get(const std::string& key) const {
|
T get(const std::string& key) const {
|
||||||
if (!has(key)) {
|
if (!has(key)) {
|
||||||
throw std::runtime_error("missing key '"+key+"'");
|
throw std::runtime_error("missing key '" + key + "'");
|
||||||
}
|
}
|
||||||
return get(key, T());
|
return get(key, T());
|
||||||
}
|
}
|
||||||
@ -164,4 +164,4 @@ std::ostream& operator<<(std::ostream& stream, const dynamic::Value& value);
|
|||||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Map_sptr& value);
|
std::ostream& operator<<(std::ostream& stream, const dynamic::Map_sptr& value);
|
||||||
std::ostream& operator<<(std::ostream& stream, const dynamic::List_sptr& value);
|
std::ostream& operator<<(std::ostream& stream, const dynamic::List_sptr& value);
|
||||||
|
|
||||||
#endif // DATA_DYNAMIC_HPP_
|
#endif // DATA_DYNAMIC_HPP_
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef DATA_DYNAMIC_FWD_HPP_
|
#ifndef DATA_DYNAMIC_FWD_HPP_
|
||||||
#define DATA_DYNAMIC_FWD_HPP_
|
#define DATA_DYNAMIC_FWD_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
#include <functional>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <functional>
|
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
namespace dynamic {
|
namespace dynamic {
|
||||||
class Map;
|
class Map;
|
||||||
@ -26,10 +26,9 @@ namespace dynamic {
|
|||||||
std::string,
|
std::string,
|
||||||
number_t,
|
number_t,
|
||||||
bool,
|
bool,
|
||||||
integer_t
|
integer_t>;
|
||||||
>;
|
|
||||||
|
|
||||||
using to_string_func = std::function<std::string(const Value&)>;
|
using to_string_func = std::function<std::string(const Value&)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DATA_DYNAMIC_FWD_HPP_
|
#endif // DATA_DYNAMIC_FWD_HPP_
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef DATA_DYNAMIC_UTIL_HPP_
|
#ifndef DATA_DYNAMIC_UTIL_HPP_
|
||||||
#define DATA_DYNAMIC_UTIL_HPP_
|
#define DATA_DYNAMIC_UTIL_HPP_
|
||||||
|
|
||||||
#include "dynamic.hpp"
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "dynamic.hpp"
|
||||||
|
|
||||||
namespace dynamic {
|
namespace dynamic {
|
||||||
template<int n>
|
template <int n>
|
||||||
inline dynamic::List_sptr to_value(glm::vec<n, float> vec) {
|
inline dynamic::List_sptr to_value(glm::vec<n, float> vec) {
|
||||||
auto list = dynamic::create_list();
|
auto list = dynamic::create_list();
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
@ -15,7 +15,7 @@ namespace dynamic {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int n, int m>
|
template <int n, int m>
|
||||||
inline dynamic::List_sptr to_value(glm::mat<n, m, float> mat) {
|
inline dynamic::List_sptr to_value(glm::mat<n, m, float> mat) {
|
||||||
auto list = dynamic::create_list();
|
auto list = dynamic::create_list();
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
@ -26,8 +26,12 @@ namespace dynamic {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int n>
|
template <int n>
|
||||||
void get_vec(const dynamic::Map_sptr& root, const std::string& name, glm::vec<n, float>& vec) {
|
void get_vec(
|
||||||
|
const dynamic::Map_sptr& root,
|
||||||
|
const std::string& name,
|
||||||
|
glm::vec<n, float>& vec
|
||||||
|
) {
|
||||||
if (const auto& list = root->list(name)) {
|
if (const auto& list = root->list(name)) {
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
vec[i] = list->num(i);
|
vec[i] = list->num(i);
|
||||||
@ -35,8 +39,10 @@ namespace dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int n>
|
template <int n>
|
||||||
void get_vec(const dynamic::List_sptr& root, size_t index, glm::vec<n, float>& vec) {
|
void get_vec(
|
||||||
|
const dynamic::List_sptr& root, size_t index, glm::vec<n, float>& vec
|
||||||
|
) {
|
||||||
if (const auto& list = root->list(index)) {
|
if (const auto& list = root->list(index)) {
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
vec[i] = list->num(i);
|
vec[i] = list->num(i);
|
||||||
@ -44,27 +50,33 @@ namespace dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int n, int m>
|
template <int n, int m>
|
||||||
void get_mat(const dynamic::Map_sptr& root, const std::string& name, glm::mat<n, m, float>& mat) {
|
void get_mat(
|
||||||
|
const dynamic::Map_sptr& root,
|
||||||
|
const std::string& name,
|
||||||
|
glm::mat<n, m, float>& mat
|
||||||
|
) {
|
||||||
if (const auto& list = root->list(name)) {
|
if (const auto& list = root->list(name)) {
|
||||||
for (size_t y = 0; y < n; y++) {
|
for (size_t y = 0; y < n; y++) {
|
||||||
for (size_t x = 0; x < m; x++) {
|
for (size_t x = 0; x < m; x++) {
|
||||||
mat[y][x] = list->num(y*m+x);
|
mat[y][x] = list->num(y * m + x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int n, int m>
|
template <int n, int m>
|
||||||
void get_mat(const dynamic::List_sptr& root, size_t index, glm::mat<n, m, float>& mat) {
|
void get_mat(
|
||||||
|
const dynamic::List_sptr& root, size_t index, glm::mat<n, m, float>& mat
|
||||||
|
) {
|
||||||
if (const auto& list = root->list(index)) {
|
if (const auto& list = root->list(index)) {
|
||||||
for (size_t y = 0; y < n; y++) {
|
for (size_t y = 0; y < n; y++) {
|
||||||
for (size_t x = 0; x < m; x++) {
|
for (size_t x = 0; x < m; x++) {
|
||||||
mat[y][x] = list->num(y*m+x);
|
mat[y][x] = list->num(y * m + x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DATA_DYNAMIC_UTIL_HPP_
|
#endif // DATA_DYNAMIC_UTIL_HPP_
|
||||||
|
|||||||
@ -7,7 +7,8 @@ std::string NumberSetting::toString() const {
|
|||||||
case setting_format::simple:
|
case setting_format::simple:
|
||||||
return util::to_string(value);
|
return util::to_string(value);
|
||||||
case setting_format::percent:
|
case setting_format::percent:
|
||||||
return std::to_string(static_cast<integer_t>(round(value * 100))) + "%";
|
return std::to_string(static_cast<integer_t>(round(value * 100))) +
|
||||||
|
"%";
|
||||||
default:
|
default:
|
||||||
return "invalid format";
|
return "invalid format";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,15 +3,13 @@
|
|||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../delegates.hpp"
|
#include "../delegates.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
enum class setting_format {
|
enum class setting_format { simple, percent };
|
||||||
simple, percent
|
|
||||||
};
|
|
||||||
|
|
||||||
class Setting {
|
class Setting {
|
||||||
protected:
|
protected:
|
||||||
@ -20,7 +18,8 @@ public:
|
|||||||
Setting(setting_format format) : format(format) {
|
Setting(setting_format format) : format(format) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Setting() {}
|
virtual ~Setting() {
|
||||||
|
}
|
||||||
|
|
||||||
virtual void resetToDefault() = 0;
|
virtual void resetToDefault() = 0;
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ public:
|
|||||||
virtual std::string toString() const = 0;
|
virtual std::string toString() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
class ObservableSetting : public Setting {
|
class ObservableSetting : public Setting {
|
||||||
int nextid = 1;
|
int nextid = 1;
|
||||||
std::unordered_map<int, consumer<T>> observers;
|
std::unordered_map<int, consumer<T>> observers;
|
||||||
@ -40,9 +39,10 @@ protected:
|
|||||||
T value;
|
T value;
|
||||||
public:
|
public:
|
||||||
ObservableSetting(T value, setting_format format)
|
ObservableSetting(T value, setting_format format)
|
||||||
: Setting(format), initial(value), value(value) {}
|
: Setting(format), initial(value), value(value) {
|
||||||
|
}
|
||||||
|
|
||||||
observer_handler observe(consumer<T> callback, bool callOnStart=false) {
|
observer_handler observe(consumer<T> callback, bool callOnStart = false) {
|
||||||
const int id = nextid++;
|
const int id = nextid++;
|
||||||
observers.emplace(id, callback);
|
observers.emplace(id, callback);
|
||||||
if (callOnStart) {
|
if (callOnStart) {
|
||||||
@ -88,13 +88,12 @@ protected:
|
|||||||
public:
|
public:
|
||||||
NumberSetting(
|
NumberSetting(
|
||||||
number_t value,
|
number_t value,
|
||||||
number_t min=std::numeric_limits<number_t>::min(),
|
number_t min = std::numeric_limits<number_t>::min(),
|
||||||
number_t max=std::numeric_limits<number_t>::max(),
|
number_t max = std::numeric_limits<number_t>::max(),
|
||||||
setting_format format=setting_format::simple
|
setting_format format = setting_format::simple
|
||||||
) : ObservableSetting(value, format),
|
)
|
||||||
min(min),
|
: ObservableSetting(value, format), min(min), max(max) {
|
||||||
max(max)
|
}
|
||||||
{}
|
|
||||||
|
|
||||||
number_t& operator*() {
|
number_t& operator*() {
|
||||||
return value;
|
return value;
|
||||||
@ -130,13 +129,12 @@ protected:
|
|||||||
public:
|
public:
|
||||||
IntegerSetting(
|
IntegerSetting(
|
||||||
integer_t value,
|
integer_t value,
|
||||||
integer_t min=std::numeric_limits<integer_t>::min(),
|
integer_t min = std::numeric_limits<integer_t>::min(),
|
||||||
integer_t max=std::numeric_limits<integer_t>::max(),
|
integer_t max = std::numeric_limits<integer_t>::max(),
|
||||||
setting_format format=setting_format::simple
|
setting_format format = setting_format::simple
|
||||||
) : ObservableSetting(value, format),
|
)
|
||||||
min(min),
|
: ObservableSetting(value, format), min(min), max(max) {
|
||||||
max(max)
|
}
|
||||||
{}
|
|
||||||
|
|
||||||
integer_t getMin() const {
|
integer_t getMin() const {
|
||||||
return min;
|
return min;
|
||||||
@ -155,10 +153,9 @@ public:
|
|||||||
|
|
||||||
class FlagSetting : public ObservableSetting<bool> {
|
class FlagSetting : public ObservableSetting<bool> {
|
||||||
public:
|
public:
|
||||||
FlagSetting(
|
FlagSetting(bool value, setting_format format = setting_format::simple)
|
||||||
bool value,
|
: ObservableSetting(value, format) {
|
||||||
setting_format format=setting_format::simple
|
}
|
||||||
) : ObservableSetting(value, format) {}
|
|
||||||
|
|
||||||
void toggle() {
|
void toggle() {
|
||||||
set(!get());
|
set(!get());
|
||||||
@ -170,11 +167,12 @@ public:
|
|||||||
class StringSetting : public ObservableSetting<std::string> {
|
class StringSetting : public ObservableSetting<std::string> {
|
||||||
public:
|
public:
|
||||||
StringSetting(
|
StringSetting(
|
||||||
std::string value,
|
std::string value, setting_format format = setting_format::simple
|
||||||
setting_format format=setting_format::simple
|
)
|
||||||
) : ObservableSetting(value, format) {}
|
: ObservableSetting(value, format) {
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATA_SETTING_HPP_
|
#endif // DATA_SETTING_HPP_
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <chrono>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -20,15 +20,17 @@ LogMessage::~LogMessage() {
|
|||||||
Logger::Logger(std::string name) : name(std::move(name)) {
|
Logger::Logger(std::string name) : name(std::move(name)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::log(LogLevel level, const std::string& name, const std::string& message) {
|
void Logger::log(
|
||||||
|
LogLevel level, const std::string& name, const std::string& message
|
||||||
|
) {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case LogLevel::debug:
|
case LogLevel::debug:
|
||||||
# ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
return;
|
return;
|
||||||
# endif
|
#endif
|
||||||
ss << "[D]";
|
ss << "[D]";
|
||||||
break;
|
break;
|
||||||
case LogLevel::info:
|
case LogLevel::info:
|
||||||
@ -42,10 +44,13 @@ void Logger::log(LogLevel level, const std::string& name, const std::string& mes
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
time_t tm = std::time(nullptr);
|
time_t tm = std::time(nullptr);
|
||||||
auto ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch()) % 1000;
|
auto ms =
|
||||||
|
duration_cast<milliseconds>(system_clock::now().time_since_epoch()) %
|
||||||
|
1000;
|
||||||
ss << " " << std::put_time(std::localtime(&tm), "%Y/%m/%d %T");
|
ss << " " << std::put_time(std::localtime(&tm), "%Y/%m/%d %T");
|
||||||
ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
|
ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
|
||||||
ss << utcOffset << " [" << std::setfill(' ') << std::setw(moduleLen) << name << "] ";
|
ss << utcOffset << " [" << std::setfill(' ') << std::setw(moduleLen) << name
|
||||||
|
<< "] ";
|
||||||
ss << message;
|
ss << message;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
#ifndef DEBUG_LOGGER_HPP_
|
#ifndef DEBUG_LOGGER_HPP_
|
||||||
#define DEBUG_LOGGER_HPP_
|
#define DEBUG_LOGGER_HPP_
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace debug {
|
namespace debug {
|
||||||
enum class LogLevel {
|
enum class LogLevel { debug, info, warning, error };
|
||||||
debug, info, warning, error
|
|
||||||
};
|
|
||||||
|
|
||||||
class Logger;
|
class Logger;
|
||||||
|
|
||||||
@ -17,10 +15,12 @@ namespace debug {
|
|||||||
LogLevel level;
|
LogLevel level;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
public:
|
public:
|
||||||
LogMessage(Logger* logger, LogLevel level) : logger(logger), level(level) {}
|
LogMessage(Logger* logger, LogLevel level)
|
||||||
|
: logger(logger), level(level) {
|
||||||
|
}
|
||||||
~LogMessage();
|
~LogMessage();
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
LogMessage& operator<<(const T& x) {
|
LogMessage& operator<<(const T& x) {
|
||||||
ss << x;
|
ss << x;
|
||||||
return *this;
|
return *this;
|
||||||
@ -35,7 +35,9 @@ namespace debug {
|
|||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
static void log(LogLevel level, const std::string& name, const std::string& message);
|
static void log(
|
||||||
|
LogLevel level, const std::string& name, const std::string& message
|
||||||
|
);
|
||||||
public:
|
public:
|
||||||
static void init(const std::string& filename);
|
static void init(const std::string& filename);
|
||||||
static void flush();
|
static void flush();
|
||||||
@ -62,4 +64,4 @@ namespace debug {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DEBUG_LOGGER_HPP_
|
#endif // DEBUG_LOGGER_HPP_
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
#include "WorldConverter.hpp"
|
#include "WorldConverter.hpp"
|
||||||
|
|
||||||
#include "WorldFiles.hpp"
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "../content/ContentLUT.hpp"
|
#include "../content/ContentLUT.hpp"
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
@ -9,11 +12,7 @@
|
|||||||
#include "../objects/Player.hpp"
|
#include "../objects/Player.hpp"
|
||||||
#include "../util/ThreadPool.hpp"
|
#include "../util/ThreadPool.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
|
#include "WorldFiles.hpp"
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -23,7 +22,8 @@ class ConverterWorker : public util::Worker<convert_task, int> {
|
|||||||
std::shared_ptr<WorldConverter> converter;
|
std::shared_ptr<WorldConverter> converter;
|
||||||
public:
|
public:
|
||||||
ConverterWorker(std::shared_ptr<WorldConverter> converter)
|
ConverterWorker(std::shared_ptr<WorldConverter> converter)
|
||||||
: converter(std::move(converter)) {}
|
: converter(std::move(converter)) {
|
||||||
|
}
|
||||||
|
|
||||||
int operator()(const std::shared_ptr<convert_task>& task) override {
|
int operator()(const std::shared_ptr<convert_task>& task) override {
|
||||||
converter->convert(*task);
|
converter->convert(*task);
|
||||||
@ -35,16 +35,18 @@ WorldConverter::WorldConverter(
|
|||||||
const fs::path& folder,
|
const fs::path& folder,
|
||||||
const Content* content,
|
const Content* content,
|
||||||
std::shared_ptr<ContentLUT> lut
|
std::shared_ptr<ContentLUT> lut
|
||||||
) : wfile(std::make_unique<WorldFiles>(folder)),
|
)
|
||||||
lut(std::move(lut)),
|
: wfile(std::make_unique<WorldFiles>(folder)),
|
||||||
content(content)
|
lut(std::move(lut)),
|
||||||
{
|
content(content) {
|
||||||
fs::path regionsFolder = wfile->getRegions().getRegionsFolder(REGION_LAYER_VOXELS);
|
fs::path regionsFolder =
|
||||||
|
wfile->getRegions().getRegionsFolder(REGION_LAYER_VOXELS);
|
||||||
if (!fs::is_directory(regionsFolder)) {
|
if (!fs::is_directory(regionsFolder)) {
|
||||||
logger.error() << "nothing to convert";
|
logger.error() << "nothing to convert";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tasks.push(convert_task {convert_task_type::player, wfile->getPlayerFile()});
|
tasks.push(convert_task {convert_task_type::player, wfile->getPlayerFile()}
|
||||||
|
);
|
||||||
for (const auto& file : fs::directory_iterator(regionsFolder)) {
|
for (const auto& file : fs::directory_iterator(regionsFolder)) {
|
||||||
tasks.push(convert_task {convert_task_type::region, file.path()});
|
tasks.push(convert_task {convert_task_type::region, file.path()});
|
||||||
}
|
}
|
||||||
@ -70,7 +72,7 @@ std::shared_ptr<Task> WorldConverter::startTask(
|
|||||||
}
|
}
|
||||||
auto pool = std::make_shared<util::ThreadPool<convert_task, int>>(
|
auto pool = std::make_shared<util::ThreadPool<convert_task, int>>(
|
||||||
"converter-pool",
|
"converter-pool",
|
||||||
[=](){return std::make_shared<ConverterWorker>(converter);},
|
[=]() { return std::make_shared<ConverterWorker>(converter); },
|
||||||
[=](int&) {}
|
[=](int&) {}
|
||||||
);
|
);
|
||||||
auto& converterTasks = converter->tasks;
|
auto& converterTasks = converter->tasks;
|
||||||
@ -111,8 +113,7 @@ void WorldConverter::convertPlayer(const fs::path& file) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorldConverter::convert(const convert_task& task) const {
|
void WorldConverter::convert(const convert_task& task) const {
|
||||||
if (!fs::is_regular_file(task.file))
|
if (!fs::is_regular_file(task.file)) return;
|
||||||
return;
|
|
||||||
|
|
||||||
switch (task.type) {
|
switch (task.type) {
|
||||||
case convert_task_type::region:
|
case convert_task_type::region:
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#ifndef FILES_WORLD_CONVERTER_HPP_
|
#ifndef FILES_WORLD_CONVERTER_HPP_
|
||||||
#define FILES_WORLD_CONVERTER_HPP_
|
#define FILES_WORLD_CONVERTER_HPP_
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
#include <memory>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../delegates.hpp"
|
#include "../delegates.hpp"
|
||||||
#include "../interfaces/Task.hpp"
|
#include "../interfaces/Task.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -15,9 +15,7 @@ class Content;
|
|||||||
class ContentLUT;
|
class ContentLUT;
|
||||||
class WorldFiles;
|
class WorldFiles;
|
||||||
|
|
||||||
enum class convert_task_type {
|
enum class convert_task_type { region, player };
|
||||||
region, player
|
|
||||||
};
|
|
||||||
|
|
||||||
struct convert_task {
|
struct convert_task {
|
||||||
convert_task_type type;
|
convert_task_type type;
|
||||||
@ -63,4 +61,4 @@ public:
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILES_WORLD_CONVERTER_HPP_
|
#endif // FILES_WORLD_CONVERTER_HPP_
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
#include "WorldFiles.hpp"
|
#include "WorldFiles.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "../coders/byte_utils.hpp"
|
#include "../coders/byte_utils.hpp"
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
#include "../constants.hpp"
|
#include "../constants.hpp"
|
||||||
@ -11,11 +19,11 @@
|
|||||||
#include "../items/ItemDef.hpp"
|
#include "../items/ItemDef.hpp"
|
||||||
#include "../lighting/Lightmap.hpp"
|
#include "../lighting/Lightmap.hpp"
|
||||||
#include "../maths/voxmaths.hpp"
|
#include "../maths/voxmaths.hpp"
|
||||||
#include "../objects/Player.hpp"
|
|
||||||
#include "../objects/EntityDef.hpp"
|
#include "../objects/EntityDef.hpp"
|
||||||
|
#include "../objects/Player.hpp"
|
||||||
#include "../physics/Hitbox.hpp"
|
#include "../physics/Hitbox.hpp"
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../settings.hpp"
|
#include "../settings.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
#include "../util/data_io.hpp"
|
#include "../util/data_io.hpp"
|
||||||
#include "../voxels/Block.hpp"
|
#include "../voxels/Block.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
@ -23,24 +31,16 @@
|
|||||||
#include "../window/Camera.hpp"
|
#include "../window/Camera.hpp"
|
||||||
#include "../world/World.hpp"
|
#include "../world/World.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstring>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#define WORLD_FORMAT_MAGIC ".VOXWLD"
|
#define WORLD_FORMAT_MAGIC ".VOXWLD"
|
||||||
|
|
||||||
static debug::Logger logger("world-files");
|
static debug::Logger logger("world-files");
|
||||||
|
|
||||||
WorldFiles::WorldFiles(const fs::path& directory) : directory(directory), regions(directory) {
|
WorldFiles::WorldFiles(const fs::path& directory)
|
||||||
|
: directory(directory), regions(directory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldFiles::WorldFiles(const fs::path& directory, const DebugSettings& settings)
|
WorldFiles::WorldFiles(const fs::path& directory, const DebugSettings& settings)
|
||||||
: WorldFiles(directory)
|
: WorldFiles(directory) {
|
||||||
{
|
|
||||||
generatorTestMode = settings.generatorTestMode.get();
|
generatorTestMode = settings.generatorTestMode.get();
|
||||||
doWriteLights = settings.doWriteLights.get();
|
doWriteLights = settings.doWriteLights.get();
|
||||||
regions.generatorTestMode = generatorTestMode;
|
regions.generatorTestMode = generatorTestMode;
|
||||||
@ -55,23 +55,23 @@ void WorldFiles::createDirectories() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs::path WorldFiles::getPlayerFile() const {
|
fs::path WorldFiles::getPlayerFile() const {
|
||||||
return directory/fs::path("player.json");
|
return directory / fs::path("player.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path WorldFiles::getResourcesFile() const {
|
fs::path WorldFiles::getResourcesFile() const {
|
||||||
return directory/fs::path("resources.json");
|
return directory / fs::path("resources.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path WorldFiles::getWorldFile() const {
|
fs::path WorldFiles::getWorldFile() const {
|
||||||
return directory/fs::path(WORLD_FILE);
|
return directory / fs::path(WORLD_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path WorldFiles::getIndicesFile() const {
|
fs::path WorldFiles::getIndicesFile() const {
|
||||||
return directory/fs::path("indices.json");
|
return directory / fs::path("indices.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path WorldFiles::getPacksFile() const {
|
fs::path WorldFiles::getPacksFile() const {
|
||||||
return directory/fs::path("packs.list");
|
return directory / fs::path("packs.list");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldFiles::write(const World* world, const Content* content) {
|
void WorldFiles::write(const World* world, const Content* content) {
|
||||||
@ -99,8 +99,10 @@ void WorldFiles::writePacks(const std::vector<ContentPack>& packs) {
|
|||||||
files::write_string(packsFile, ss.str());
|
files::write_string(packsFile, ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
static void write_indices(const ContentUnitIndices<T>& indices, dynamic::List& list) {
|
static void write_indices(
|
||||||
|
const ContentUnitIndices<T>& indices, dynamic::List& list
|
||||||
|
) {
|
||||||
size_t count = indices.count();
|
size_t count = indices.count();
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
list.put(indices.get(i)->name);
|
list.put(indices.get(i)->name);
|
||||||
@ -131,9 +133,7 @@ bool WorldFiles::readWorldInfo(World* world) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void read_resources_data(
|
static void read_resources_data(
|
||||||
const Content* content,
|
const Content* content, const dynamic::List_sptr& list, ResourceType type
|
||||||
const dynamic::List_sptr& list,
|
|
||||||
ResourceType type
|
|
||||||
) {
|
) {
|
||||||
const auto& indices = content->getIndices(type);
|
const auto& indices = content->getIndices(type);
|
||||||
for (size_t i = 0; i < list->size(); i++) {
|
for (size_t i = 0; i < list->size(); i++) {
|
||||||
@ -169,12 +169,11 @@ bool WorldFiles::readResourcesData(const Content* content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void erase_pack_indices(dynamic::Map* root, const std::string& id) {
|
static void erase_pack_indices(dynamic::Map* root, const std::string& id) {
|
||||||
auto prefix = id+":";
|
auto prefix = id + ":";
|
||||||
auto blocks = root->list("blocks");
|
auto blocks = root->list("blocks");
|
||||||
for (uint i = 0; i < blocks->size(); i++) {
|
for (uint i = 0; i < blocks->size(); i++) {
|
||||||
auto name = blocks->str(i);
|
auto name = blocks->str(i);
|
||||||
if (name.find(prefix) != 0)
|
if (name.find(prefix) != 0) continue;
|
||||||
continue;
|
|
||||||
auto value = blocks->getValueWriteable(i);
|
auto value = blocks->getValueWriteable(i);
|
||||||
*value = CORE_AIR;
|
*value = CORE_AIR;
|
||||||
}
|
}
|
||||||
@ -182,8 +181,7 @@ static void erase_pack_indices(dynamic::Map* root, const std::string& id) {
|
|||||||
auto items = root->list("items");
|
auto items = root->list("items");
|
||||||
for (uint i = 0; i < items->size(); i++) {
|
for (uint i = 0; i < items->size(); i++) {
|
||||||
auto name = items->str(i);
|
auto name = items->str(i);
|
||||||
if (name.find(prefix) != 0)
|
if (name.find(prefix) != 0) continue;
|
||||||
continue;
|
|
||||||
auto value = items->getValueWriteable(i);
|
auto value = items->getValueWriteable(i);
|
||||||
*value = CORE_EMPTY;
|
*value = CORE_EMPTY;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
#ifndef FILES_WORLD_FILES_HPP_
|
#ifndef FILES_WORLD_FILES_HPP_
|
||||||
#define FILES_WORLD_FILES_HPP_
|
#define FILES_WORLD_FILES_HPP_
|
||||||
|
|
||||||
#include "WorldRegions.hpp"
|
|
||||||
|
|
||||||
#include "files.hpp"
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../content/ContentPack.hpp"
|
|
||||||
#include "../voxels/Chunk.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../content/ContentPack.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
#include "../voxels/Chunk.hpp"
|
||||||
|
#include "WorldRegions.hpp"
|
||||||
|
#include "files.hpp"
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include "glm/gtx/hash.hpp"
|
#include "glm/gtx/hash.hpp"
|
||||||
|
|
||||||
@ -41,8 +39,8 @@ class WorldFiles {
|
|||||||
void writeWorldInfo(const World* world);
|
void writeWorldInfo(const World* world);
|
||||||
void writeIndices(const ContentIndices* indices);
|
void writeIndices(const ContentIndices* indices);
|
||||||
public:
|
public:
|
||||||
WorldFiles(const fs::path &directory);
|
WorldFiles(const fs::path& directory);
|
||||||
WorldFiles(const fs::path &directory, const DebugSettings& settings);
|
WorldFiles(const fs::path& directory, const DebugSettings& settings);
|
||||||
~WorldFiles();
|
~WorldFiles();
|
||||||
|
|
||||||
fs::path getPlayerFile() const;
|
fs::path getPlayerFile() const;
|
||||||
@ -75,4 +73,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILES_WORLD_FILES_HPP_
|
#endif // FILES_WORLD_FILES_HPP_
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
#include "WorldRegions.hpp"
|
#include "WorldRegions.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../coders/byte_utils.hpp"
|
#include "../coders/byte_utils.hpp"
|
||||||
#include "../coders/rle.hpp"
|
#include "../coders/rle.hpp"
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
@ -7,10 +11,6 @@
|
|||||||
#include "../maths/voxmaths.hpp"
|
#include "../maths/voxmaths.hpp"
|
||||||
#include "../util/data_io.hpp"
|
#include "../util/data_io.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#define REGION_FORMAT_MAGIC ".VOXREG"
|
#define REGION_FORMAT_MAGIC ".VOXREG"
|
||||||
|
|
||||||
regfile::regfile(fs::path filename) : file(std::move(filename)) {
|
regfile::regfile(fs::path filename) : file(std::move(filename)) {
|
||||||
@ -20,13 +20,14 @@ regfile::regfile(fs::path filename) : file(std::move(filename)) {
|
|||||||
file.read(header, REGION_HEADER_SIZE);
|
file.read(header, REGION_HEADER_SIZE);
|
||||||
|
|
||||||
// avoid of use strcmp_s
|
// avoid of use strcmp_s
|
||||||
if (std::string(header, strlen(REGION_FORMAT_MAGIC)) != REGION_FORMAT_MAGIC) {
|
if (std::string(header, strlen(REGION_FORMAT_MAGIC)) !=
|
||||||
|
REGION_FORMAT_MAGIC) {
|
||||||
throw std::runtime_error("invalid region file magic number");
|
throw std::runtime_error("invalid region file magic number");
|
||||||
}
|
}
|
||||||
version = header[8];
|
version = header[8];
|
||||||
if (uint(version) > REGION_FORMAT_VERSION) {
|
if (uint(version) > REGION_FORMAT_VERSION) {
|
||||||
throw illegal_region_format(
|
throw illegal_region_format(
|
||||||
"region format "+std::to_string(version)+" is not supported"
|
"region format " + std::to_string(version) + " is not supported"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +40,7 @@ std::unique_ptr<ubyte[]> regfile::read(int index, uint32_t& length) {
|
|||||||
file.seekg(table_offset + index * 4);
|
file.seekg(table_offset + index * 4);
|
||||||
file.read(reinterpret_cast<char*>(&offset), 4);
|
file.read(reinterpret_cast<char*>(&offset), 4);
|
||||||
offset = dataio::read_int32_big(reinterpret_cast<const ubyte*>(&offset), 0);
|
offset = dataio::read_int32_big(reinterpret_cast<const ubyte*>(&offset), 0);
|
||||||
if (offset == 0){
|
if (offset == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +53,11 @@ std::unique_ptr<ubyte[]> regfile::read(int index, uint32_t& length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WorldRegion::WorldRegion()
|
WorldRegion::WorldRegion()
|
||||||
: chunksData(std::make_unique<std::unique_ptr<ubyte[]>[]>(REGION_CHUNKS_COUNT)),
|
: chunksData(
|
||||||
sizes(std::make_unique<uint32_t[]>(REGION_CHUNKS_COUNT))
|
std::make_unique<std::unique_ptr<ubyte[]>[]>(REGION_CHUNKS_COUNT)
|
||||||
{}
|
),
|
||||||
|
sizes(std::make_unique<uint32_t[]>(REGION_CHUNKS_COUNT)) {
|
||||||
|
}
|
||||||
|
|
||||||
WorldRegion::~WorldRegion() = default;
|
WorldRegion::~WorldRegion() = default;
|
||||||
|
|
||||||
@ -88,13 +91,14 @@ uint WorldRegion::getChunkDataSize(uint x, uint z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WorldRegions::WorldRegions(const fs::path& directory) : directory(directory) {
|
WorldRegions::WorldRegions(const fs::path& directory) : directory(directory) {
|
||||||
for (size_t i = 0; i < sizeof(layers)/sizeof(RegionsLayer); i++) {
|
for (size_t i = 0; i < sizeof(layers) / sizeof(RegionsLayer); i++) {
|
||||||
layers[i].layer = i;
|
layers[i].layer = i;
|
||||||
}
|
}
|
||||||
layers[REGION_LAYER_VOXELS].folder = directory/fs::path("regions");
|
layers[REGION_LAYER_VOXELS].folder = directory / fs::path("regions");
|
||||||
layers[REGION_LAYER_LIGHTS].folder = directory/fs::path("lights");
|
layers[REGION_LAYER_LIGHTS].folder = directory / fs::path("lights");
|
||||||
layers[REGION_LAYER_INVENTORIES].folder = directory/fs::path("inventories");
|
layers[REGION_LAYER_INVENTORIES].folder =
|
||||||
layers[REGION_LAYER_ENTITIES].folder = directory/fs::path("entities");
|
directory / fs::path("inventories");
|
||||||
|
layers[REGION_LAYER_ENTITIES].folder = directory / fs::path("entities");
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldRegions::~WorldRegions() = default;
|
WorldRegions::~WorldRegions() = default;
|
||||||
@ -121,7 +125,9 @@ WorldRegion* WorldRegions::getOrCreateRegion(int x, int z, int layer) {
|
|||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ubyte[]> WorldRegions::compress(const ubyte* src, size_t srclen, size_t& len) {
|
std::unique_ptr<ubyte[]> WorldRegions::compress(
|
||||||
|
const ubyte* src, size_t srclen, size_t& len
|
||||||
|
) {
|
||||||
auto buffer = bufferPool.get();
|
auto buffer = bufferPool.get();
|
||||||
auto bytes = buffer.get();
|
auto bytes = buffer.get();
|
||||||
|
|
||||||
@ -133,7 +139,9 @@ std::unique_ptr<ubyte[]> WorldRegions::compress(const ubyte* src, size_t srclen,
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ubyte[]> WorldRegions::decompress(const ubyte* src, size_t srclen, size_t dstlen) {
|
std::unique_ptr<ubyte[]> WorldRegions::decompress(
|
||||||
|
const ubyte* src, size_t srclen, size_t dstlen
|
||||||
|
) {
|
||||||
auto decompressed = std::make_unique<ubyte[]>(dstlen);
|
auto decompressed = std::make_unique<ubyte[]>(dstlen);
|
||||||
extrle::decode(src, srclen, decompressed.get());
|
extrle::decode(src, srclen, decompressed.get());
|
||||||
return decompressed;
|
return decompressed;
|
||||||
@ -158,7 +166,9 @@ std::unique_ptr<ubyte[]> WorldRegions::readChunkData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Read missing chunks data (null pointers) from region file
|
/// @brief Read missing chunks data (null pointers) from region file
|
||||||
void WorldRegions::fetchChunks(WorldRegion* region, int x, int z, regfile* file) {
|
void WorldRegions::fetchChunks(
|
||||||
|
WorldRegion* region, int x, int z, regfile* file
|
||||||
|
) {
|
||||||
auto* chunks = region->getChunks();
|
auto* chunks = region->getChunks();
|
||||||
uint32_t* sizes = region->getSizes();
|
uint32_t* sizes = region->getSizes();
|
||||||
|
|
||||||
@ -226,7 +236,8 @@ regfile_ptr WorldRegions::getRegFile(glm::ivec3 coord, bool create) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
regfile_ptr WorldRegions::createRegFile(glm::ivec3 coord) {
|
regfile_ptr WorldRegions::createRegFile(glm::ivec3 coord) {
|
||||||
fs::path file = layers[coord[2]].folder/getRegionFilename(coord[0], coord[1]);
|
fs::path file =
|
||||||
|
layers[coord[2]].folder / getRegionFilename(coord[0], coord[1]);
|
||||||
if (!fs::exists(file)) {
|
if (!fs::exists(file)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -261,8 +272,8 @@ fs::path WorldRegions::getRegionFilename(int x, int z) const {
|
|||||||
return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin");
|
return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRegions::writeRegion(int x, int z, int layer, WorldRegion* entry){
|
void WorldRegions::writeRegion(int x, int z, int layer, WorldRegion* entry) {
|
||||||
fs::path filename = layers[layer].folder/getRegionFilename(x, z);
|
fs::path filename = layers[layer].folder / getRegionFilename(x, z);
|
||||||
|
|
||||||
glm::ivec3 regcoord(x, z, layer);
|
glm::ivec3 regcoord(x, z, layer);
|
||||||
if (auto regfile = getRegFile(regcoord, false)) {
|
if (auto regfile = getRegFile(regcoord, false)) {
|
||||||
@ -275,26 +286,28 @@ void WorldRegions::writeRegion(int x, int z, int layer, WorldRegion* entry){
|
|||||||
|
|
||||||
char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC;
|
char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC;
|
||||||
header[8] = REGION_FORMAT_VERSION;
|
header[8] = REGION_FORMAT_VERSION;
|
||||||
header[9] = 0; // flags
|
header[9] = 0; // flags
|
||||||
std::ofstream file(filename, std::ios::out | std::ios::binary);
|
std::ofstream file(filename, std::ios::out | std::ios::binary);
|
||||||
file.write(header, REGION_HEADER_SIZE);
|
file.write(header, REGION_HEADER_SIZE);
|
||||||
|
|
||||||
size_t offset = REGION_HEADER_SIZE;
|
size_t offset = REGION_HEADER_SIZE;
|
||||||
char intbuf[4]{};
|
char intbuf[4] {};
|
||||||
uint offsets[REGION_CHUNKS_COUNT]{};
|
uint offsets[REGION_CHUNKS_COUNT] {};
|
||||||
|
|
||||||
auto* region = entry->getChunks();
|
auto* region = entry->getChunks();
|
||||||
uint32_t* sizes = entry->getSizes();
|
uint32_t* sizes = entry->getSizes();
|
||||||
|
|
||||||
for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) {
|
for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) {
|
||||||
ubyte* chunk = region[i].get();
|
ubyte* chunk = region[i].get();
|
||||||
if (chunk == nullptr){
|
if (chunk == nullptr) {
|
||||||
offsets[i] = 0;
|
offsets[i] = 0;
|
||||||
} else {
|
} else {
|
||||||
offsets[i] = offset;
|
offsets[i] = offset;
|
||||||
|
|
||||||
size_t compressedSize = sizes[i];
|
size_t compressedSize = sizes[i];
|
||||||
dataio::write_int32_big(compressedSize, reinterpret_cast<ubyte*>(intbuf), 0);
|
dataio::write_int32_big(
|
||||||
|
compressedSize, reinterpret_cast<ubyte*>(intbuf), 0
|
||||||
|
);
|
||||||
offset += 4 + compressedSize;
|
offset += 4 + compressedSize;
|
||||||
|
|
||||||
file.write(intbuf, 4);
|
file.write(intbuf, 4);
|
||||||
@ -302,13 +315,15 @@ void WorldRegions::writeRegion(int x, int z, int layer, WorldRegion* entry){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) {
|
for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) {
|
||||||
dataio::write_int32_big(offsets[i], reinterpret_cast<ubyte*>(intbuf), 0);
|
dataio::write_int32_big(
|
||||||
|
offsets[i], reinterpret_cast<ubyte*>(intbuf), 0
|
||||||
|
);
|
||||||
file.write(intbuf, 4);
|
file.write(intbuf, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRegions::writeRegions(int layer) {
|
void WorldRegions::writeRegions(int layer) {
|
||||||
for (auto& it : layers[layer].regions){
|
for (auto& it : layers[layer].regions) {
|
||||||
WorldRegion* region = it.second.get();
|
WorldRegion* region = it.second.get();
|
||||||
if (region->getChunks() == nullptr || !region->isUnsaved()) {
|
if (region->getChunks() == nullptr || !region->isUnsaved()) {
|
||||||
continue;
|
continue;
|
||||||
@ -318,7 +333,14 @@ void WorldRegions::writeRegions(int layer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRegions::put(int x, int z, int layer, std::unique_ptr<ubyte[]> data, size_t size, bool rle) {
|
void WorldRegions::put(
|
||||||
|
int x,
|
||||||
|
int z,
|
||||||
|
int layer,
|
||||||
|
std::unique_ptr<ubyte[]> data,
|
||||||
|
size_t size,
|
||||||
|
bool rle
|
||||||
|
) {
|
||||||
if (rle) {
|
if (rle) {
|
||||||
size_t compressedSize;
|
size_t compressedSize;
|
||||||
auto compressed = compress(data.get(), size, compressedSize);
|
auto compressed = compress(data.get(), size, compressedSize);
|
||||||
@ -333,7 +355,9 @@ void WorldRegions::put(int x, int z, int layer, std::unique_ptr<ubyte[]> data, s
|
|||||||
region->put(localX, localZ, data.release(), size);
|
region->put(localX, localZ, data.release(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<ubyte[]> write_inventories(Chunk* chunk, uint& datasize) {
|
static std::unique_ptr<ubyte[]> write_inventories(
|
||||||
|
Chunk* chunk, uint& datasize
|
||||||
|
) {
|
||||||
auto& inventories = chunk->inventories;
|
auto& inventories = chunk->inventories;
|
||||||
ByteBuilder builder;
|
ByteBuilder builder;
|
||||||
builder.putInt32(inventories.size());
|
builder.putInt32(inventories.size());
|
||||||
@ -352,7 +376,7 @@ static std::unique_ptr<ubyte[]> write_inventories(Chunk* chunk, uint& datasize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Store chunk data (voxels and lights) in region (existing or new)
|
/// @brief Store chunk data (voxels and lights) in region (existing or new)
|
||||||
void WorldRegions::put(Chunk* chunk, std::vector<ubyte> entitiesData){
|
void WorldRegions::put(Chunk* chunk, std::vector<ubyte> entitiesData) {
|
||||||
assert(chunk != nullptr);
|
assert(chunk != nullptr);
|
||||||
if (!chunk->flags.lighted) {
|
if (!chunk->flags.lighted) {
|
||||||
return;
|
return;
|
||||||
@ -365,20 +389,32 @@ void WorldRegions::put(Chunk* chunk, std::vector<ubyte> entitiesData){
|
|||||||
int regionX, regionZ, localX, localZ;
|
int regionX, regionZ, localX, localZ;
|
||||||
calc_reg_coords(chunk->x, chunk->z, regionX, regionZ, localX, localZ);
|
calc_reg_coords(chunk->x, chunk->z, regionX, regionZ, localX, localZ);
|
||||||
|
|
||||||
put(chunk->x, chunk->z, REGION_LAYER_VOXELS,
|
put(chunk->x,
|
||||||
chunk->encode(), CHUNK_DATA_LEN, true);
|
chunk->z,
|
||||||
|
REGION_LAYER_VOXELS,
|
||||||
|
chunk->encode(),
|
||||||
|
CHUNK_DATA_LEN,
|
||||||
|
true);
|
||||||
|
|
||||||
// Writing lights cache
|
// Writing lights cache
|
||||||
if (doWriteLights && chunk->flags.lighted) {
|
if (doWriteLights && chunk->flags.lighted) {
|
||||||
put(chunk->x, chunk->z, REGION_LAYER_LIGHTS,
|
put(chunk->x,
|
||||||
chunk->lightmap.encode(), LIGHTMAP_DATA_LEN, true);
|
chunk->z,
|
||||||
|
REGION_LAYER_LIGHTS,
|
||||||
|
chunk->lightmap.encode(),
|
||||||
|
LIGHTMAP_DATA_LEN,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
// Writing block inventories
|
// Writing block inventories
|
||||||
if (!chunk->inventories.empty()) {
|
if (!chunk->inventories.empty()) {
|
||||||
uint datasize;
|
uint datasize;
|
||||||
auto data = write_inventories(chunk, datasize);
|
auto data = write_inventories(chunk, datasize);
|
||||||
put(chunk->x, chunk->z, REGION_LAYER_INVENTORIES,
|
put(chunk->x,
|
||||||
std::move(data), datasize, false);
|
chunk->z,
|
||||||
|
REGION_LAYER_INVENTORIES,
|
||||||
|
std::move(data),
|
||||||
|
datasize,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
// Writing entities
|
// Writing entities
|
||||||
if (!entitiesData.empty()) {
|
if (!entitiesData.empty()) {
|
||||||
@ -386,12 +422,16 @@ void WorldRegions::put(Chunk* chunk, std::vector<ubyte> entitiesData){
|
|||||||
for (size_t i = 0; i < entitiesData.size(); i++) {
|
for (size_t i = 0; i < entitiesData.size(); i++) {
|
||||||
data[i] = entitiesData[i];
|
data[i] = entitiesData[i];
|
||||||
}
|
}
|
||||||
put(chunk->x, chunk->z, REGION_LAYER_ENTITIES,
|
put(chunk->x,
|
||||||
std::move(data), entitiesData.size(), false);
|
chunk->z,
|
||||||
|
REGION_LAYER_ENTITIES,
|
||||||
|
std::move(data),
|
||||||
|
entitiesData.size(),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ubyte[]> WorldRegions::getChunk(int x, int z){
|
std::unique_ptr<ubyte[]> WorldRegions::getChunk(int x, int z) {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
auto* data = getData(x, z, REGION_LAYER_VOXELS, size);
|
auto* data = getData(x, z, REGION_LAYER_VOXELS, size);
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
@ -433,7 +473,7 @@ chunk_inventories_map WorldRegions::fetchInventories(int x, int z) {
|
|||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic::Map_sptr WorldRegions::fetchEntities(int x, int z) {
|
dynamic::Map_sptr WorldRegions::fetchEntities(int x, int z) {
|
||||||
uint32_t bytesSize;
|
uint32_t bytesSize;
|
||||||
const ubyte* data = getData(x, z, REGION_LAYER_ENTITIES, bytesSize);
|
const ubyte* data = getData(x, z, REGION_LAYER_ENTITIES, bytesSize);
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
@ -444,7 +484,7 @@ chunk_inventories_map WorldRegions::fetchInventories(int x, int z) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRegions::processRegionVoxels(int x, int z, const regionproc& func) {
|
void WorldRegions::processRegionVoxels(int x, int z, const regionproc& func) {
|
||||||
if (getRegion(x, z, REGION_LAYER_VOXELS)) {
|
if (getRegion(x, z, REGION_LAYER_VOXELS)) {
|
||||||
@ -465,7 +505,12 @@ void WorldRegions::processRegionVoxels(int x, int z, const regionproc& func) {
|
|||||||
}
|
}
|
||||||
data = decompress(data.get(), length, CHUNK_DATA_LEN);
|
data = decompress(data.get(), length, CHUNK_DATA_LEN);
|
||||||
if (func(data.get())) {
|
if (func(data.get())) {
|
||||||
put(gx, gz, REGION_LAYER_VOXELS, std::move(data), CHUNK_DATA_LEN, true);
|
put(gx,
|
||||||
|
gz,
|
||||||
|
REGION_LAYER_VOXELS,
|
||||||
|
std::move(data),
|
||||||
|
CHUNK_DATA_LEN,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,7 +520,6 @@ fs::path WorldRegions::getRegionsFolder(int layer) const {
|
|||||||
return layers[layer].folder;
|
return layers[layer].folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WorldRegions::write() {
|
void WorldRegions::write() {
|
||||||
for (auto& layer : layers) {
|
for (auto& layer : layers) {
|
||||||
fs::create_directories(layer.folder);
|
fs::create_directories(layer.folder);
|
||||||
@ -483,14 +527,16 @@ void WorldRegions::write() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldRegions::parseRegionFilename(const std::string& name, int& x, int& z) {
|
bool WorldRegions::parseRegionFilename(
|
||||||
|
const std::string& name, int& x, int& z
|
||||||
|
) {
|
||||||
size_t sep = name.find('_');
|
size_t sep = name.find('_');
|
||||||
if (sep == std::string::npos || sep == 0 || sep == name.length()-1) {
|
if (sep == std::string::npos || sep == 0 || sep == name.length() - 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
x = std::stoi(name.substr(0, sep));
|
x = std::stoi(name.substr(0, sep));
|
||||||
z = std::stoi(name.substr(sep+1));
|
z = std::stoi(name.substr(sep + 1));
|
||||||
} catch (std::invalid_argument& err) {
|
} catch (std::invalid_argument& err) {
|
||||||
return false;
|
return false;
|
||||||
} catch (std::out_of_range& err) {
|
} catch (std::out_of_range& err) {
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
#ifndef FILES_WORLD_REGIONS_HPP_
|
#ifndef FILES_WORLD_REGIONS_HPP_
|
||||||
#define FILES_WORLD_REGIONS_HPP_
|
#define FILES_WORLD_REGIONS_HPP_
|
||||||
|
|
||||||
#include "files.hpp"
|
#include <condition_variable>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "../data/dynamic_fwd.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
#include "../util/BufferPool.hpp"
|
#include "../util/BufferPool.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
#include "../data/dynamic_fwd.hpp"
|
#include "files.hpp"
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <condition_variable>
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include "glm/gtx/hash.hpp"
|
#include "glm/gtx/hash.hpp"
|
||||||
|
|
||||||
@ -36,7 +35,8 @@ inline constexpr uint MAX_OPEN_REGION_FILES = 16;
|
|||||||
class illegal_region_format : public std::runtime_error {
|
class illegal_region_format : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
illegal_region_format(const std::string& message)
|
illegal_region_format(const std::string& message)
|
||||||
: std::runtime_error(message) {}
|
: std::runtime_error(message) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class WorldRegion {
|
class WorldRegion {
|
||||||
@ -83,14 +83,14 @@ class regfile_ptr {
|
|||||||
regfile* file;
|
regfile* file;
|
||||||
std::condition_variable* cv;
|
std::condition_variable* cv;
|
||||||
public:
|
public:
|
||||||
regfile_ptr(
|
regfile_ptr(regfile* file, std::condition_variable* cv)
|
||||||
regfile* file,
|
: file(file), cv(cv) {
|
||||||
std::condition_variable* cv
|
}
|
||||||
) : file(file), cv(cv) {}
|
|
||||||
|
|
||||||
regfile_ptr(const regfile_ptr&) = delete;
|
regfile_ptr(const regfile_ptr&) = delete;
|
||||||
|
|
||||||
regfile_ptr(std::nullptr_t) : file(nullptr), cv(nullptr) {}
|
regfile_ptr(std::nullptr_t) : file(nullptr), cv(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(std::nullptr_t) const {
|
bool operator==(std::nullptr_t) const {
|
||||||
return file == nullptr;
|
return file == nullptr;
|
||||||
@ -123,8 +123,7 @@ class WorldRegions {
|
|||||||
std::condition_variable regFilesCv;
|
std::condition_variable regFilesCv;
|
||||||
RegionsLayer layers[4] {};
|
RegionsLayer layers[4] {};
|
||||||
util::BufferPool<ubyte> bufferPool {
|
util::BufferPool<ubyte> bufferPool {
|
||||||
std::max(CHUNK_DATA_LEN, LIGHTMAP_DATA_LEN) * 2
|
std::max(CHUNK_DATA_LEN, LIGHTMAP_DATA_LEN) * 2};
|
||||||
};
|
|
||||||
|
|
||||||
WorldRegion* getRegion(int x, int z, int layer);
|
WorldRegion* getRegion(int x, int z, int layer);
|
||||||
WorldRegion* getOrCreateRegion(int x, int z, int layer);
|
WorldRegion* getOrCreateRegion(int x, int z, int layer);
|
||||||
@ -134,22 +133,28 @@ class WorldRegions {
|
|||||||
/// @param srclen length of the source buffer
|
/// @param srclen length of the source buffer
|
||||||
/// @param len (out argument) length of result buffer
|
/// @param len (out argument) length of result buffer
|
||||||
/// @return compressed bytes array
|
/// @return compressed bytes array
|
||||||
std::unique_ptr<ubyte[]> compress(const ubyte* src, size_t srclen, size_t& len);
|
std::unique_ptr<ubyte[]> compress(
|
||||||
|
const ubyte* src, size_t srclen, size_t& len
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Decompress buffer with extrle
|
/// @brief Decompress buffer with extrle
|
||||||
/// @param src compressed buffer
|
/// @param src compressed buffer
|
||||||
/// @param srclen length of compressed buffer
|
/// @param srclen length of compressed buffer
|
||||||
/// @param dstlen max expected length of source buffer
|
/// @param dstlen max expected length of source buffer
|
||||||
/// @return decompressed bytes array
|
/// @return decompressed bytes array
|
||||||
std::unique_ptr<ubyte[]> decompress(const ubyte* src, size_t srclen, size_t dstlen);
|
std::unique_ptr<ubyte[]> decompress(
|
||||||
|
const ubyte* src, size_t srclen, size_t dstlen
|
||||||
|
);
|
||||||
|
|
||||||
std::unique_ptr<ubyte[]> readChunkData(int x, int y, uint32_t& length, regfile* file);
|
std::unique_ptr<ubyte[]> readChunkData(
|
||||||
|
int x, int y, uint32_t& length, regfile* file
|
||||||
|
);
|
||||||
|
|
||||||
void fetchChunks(WorldRegion* region, int x, int y, regfile* file);
|
void fetchChunks(WorldRegion* region, int x, int y, regfile* file);
|
||||||
|
|
||||||
ubyte* getData(int x, int z, int layer, uint32_t& size);
|
ubyte* getData(int x, int z, int layer, uint32_t& size);
|
||||||
|
|
||||||
regfile_ptr getRegFile(glm::ivec3 coord, bool create=true);
|
regfile_ptr getRegFile(glm::ivec3 coord, bool create = true);
|
||||||
void closeRegFile(glm::ivec3 coord);
|
void closeRegFile(glm::ivec3 coord);
|
||||||
regfile_ptr useRegFile(glm::ivec3 coord);
|
regfile_ptr useRegFile(glm::ivec3 coord);
|
||||||
regfile_ptr createRegFile(glm::ivec3 coord);
|
regfile_ptr createRegFile(glm::ivec3 coord);
|
||||||
@ -181,7 +186,14 @@ public:
|
|||||||
/// @param data target data
|
/// @param data target data
|
||||||
/// @param size data size
|
/// @param size data size
|
||||||
/// @param rle compress with ext-RLE
|
/// @param rle compress with ext-RLE
|
||||||
void put(int x, int z, int layer, std::unique_ptr<ubyte[]> data, size_t size, bool rle);
|
void put(
|
||||||
|
int x,
|
||||||
|
int z,
|
||||||
|
int layer,
|
||||||
|
std::unique_ptr<ubyte[]> data,
|
||||||
|
size_t size,
|
||||||
|
bool rle
|
||||||
|
);
|
||||||
|
|
||||||
std::unique_ptr<ubyte[]> getChunk(int x, int z);
|
std::unique_ptr<ubyte[]> getChunk(int x, int z);
|
||||||
std::unique_ptr<light_t[]> getLights(int x, int z);
|
std::unique_ptr<light_t[]> getLights(int x, int z);
|
||||||
@ -202,4 +214,4 @@ public:
|
|||||||
static bool parseRegionFilename(const std::string& name, int& x, int& y);
|
static bool parseRegionFilename(const std::string& name, int& x, int& y);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILES_WORLD_REGIONS_HPP_
|
#endif // FILES_WORLD_REGIONS_HPP_
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#include "engine_paths.hpp"
|
#include "engine_paths.hpp"
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
#include <sstream>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stack>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../util/stringutil.hpp"
|
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
#include "WorldFiles.hpp"
|
#include "WorldFiles.hpp"
|
||||||
|
|
||||||
const fs::path SCREENSHOTS_FOLDER {"screenshots"};
|
const fs::path SCREENSHOTS_FOLDER {"screenshots"};
|
||||||
@ -16,7 +16,7 @@ const fs::path CONTROLS_FILE {"controls.toml"};
|
|||||||
const fs::path SETTINGS_FILE {"settings.toml"};
|
const fs::path SETTINGS_FILE {"settings.toml"};
|
||||||
|
|
||||||
void EnginePaths::prepare() {
|
void EnginePaths::prepare() {
|
||||||
fs::path contentFolder = userfiles/fs::path(CONTENT_FOLDER);
|
fs::path contentFolder = userfiles / fs::path(CONTENT_FOLDER);
|
||||||
if (!fs::is_directory(contentFolder)) {
|
if (!fs::is_directory(contentFolder)) {
|
||||||
fs::create_directories(contentFolder);
|
fs::create_directories(contentFolder);
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ fs::path EnginePaths::getResources() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getScreenshotFile(const std::string& ext) {
|
fs::path EnginePaths::getScreenshotFile(const std::string& ext) {
|
||||||
fs::path folder = userfiles/fs::path(SCREENSHOTS_FOLDER);
|
fs::path folder = userfiles / fs::path(SCREENSHOTS_FOLDER);
|
||||||
if (!fs::is_directory(folder)) {
|
if (!fs::is_directory(folder)) {
|
||||||
fs::create_directory(folder);
|
fs::create_directory(folder);
|
||||||
}
|
}
|
||||||
@ -44,17 +44,21 @@ fs::path EnginePaths::getScreenshotFile(const std::string& ext) {
|
|||||||
ss << std::put_time(&tm, format);
|
ss << std::put_time(&tm, format);
|
||||||
std::string datetimestr = ss.str();
|
std::string datetimestr = ss.str();
|
||||||
|
|
||||||
fs::path filename = folder/fs::u8path("screenshot-"+datetimestr+"."+ext);
|
fs::path filename =
|
||||||
|
folder / fs::u8path("screenshot-" + datetimestr + "." + ext);
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
while (fs::exists(filename)) {
|
while (fs::exists(filename)) {
|
||||||
filename = folder/fs::u8path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext);
|
filename = folder / fs::u8path(
|
||||||
|
"screenshot-" + datetimestr + "-" +
|
||||||
|
std::to_string(index) + "." + ext
|
||||||
|
);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getWorldsFolder() {
|
fs::path EnginePaths::getWorldsFolder() {
|
||||||
return userfiles/fs::path("worlds");
|
return userfiles / fs::path("worlds");
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getWorldFolder() {
|
fs::path EnginePaths::getWorldFolder() {
|
||||||
@ -62,45 +66,44 @@ fs::path EnginePaths::getWorldFolder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getWorldFolder(const std::string& name) {
|
fs::path EnginePaths::getWorldFolder(const std::string& name) {
|
||||||
return getWorldsFolder()/fs::path(name);
|
return getWorldsFolder() / fs::path(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getControlsFile() {
|
fs::path EnginePaths::getControlsFile() {
|
||||||
return userfiles/fs::path(CONTROLS_FILE);
|
return userfiles / fs::path(CONTROLS_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getSettingsFile() {
|
fs::path EnginePaths::getSettingsFile() {
|
||||||
return userfiles/fs::path(SETTINGS_FILE);
|
return userfiles / fs::path(SETTINGS_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<fs::path> EnginePaths::scanForWorlds() {
|
std::vector<fs::path> EnginePaths::scanForWorlds() {
|
||||||
std::vector<fs::path> folders;
|
std::vector<fs::path> folders;
|
||||||
|
|
||||||
fs::path folder = getWorldsFolder();
|
fs::path folder = getWorldsFolder();
|
||||||
if (!fs::is_directory(folder))
|
if (!fs::is_directory(folder)) return folders;
|
||||||
return folders;
|
|
||||||
|
|
||||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||||
if (!entry.is_directory()) {
|
if (!entry.is_directory()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const fs::path& worldFolder = entry.path();
|
const fs::path& worldFolder = entry.path();
|
||||||
fs::path worldFile = worldFolder/fs::u8path(WorldFiles::WORLD_FILE);
|
fs::path worldFile = worldFolder / fs::u8path(WorldFiles::WORLD_FILE);
|
||||||
if (!fs::is_regular_file(worldFile)) {
|
if (!fs::is_regular_file(worldFile)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
folders.push_back(worldFolder);
|
folders.push_back(worldFolder);
|
||||||
}
|
}
|
||||||
std::sort(folders.begin(), folders.end(), [](fs::path a, fs::path b) {
|
std::sort(folders.begin(), folders.end(), [](fs::path a, fs::path b) {
|
||||||
a = a/fs::u8path(WorldFiles::WORLD_FILE);
|
a = a / fs::u8path(WorldFiles::WORLD_FILE);
|
||||||
b = b/fs::u8path(WorldFiles::WORLD_FILE);
|
b = b / fs::u8path(WorldFiles::WORLD_FILE);
|
||||||
return fs::last_write_time(a) > fs::last_write_time(b);
|
return fs::last_write_time(a) > fs::last_write_time(b);
|
||||||
});
|
});
|
||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EnginePaths::isWorldNameUsed(const std::string& name) {
|
bool EnginePaths::isWorldNameUsed(const std::string& name) {
|
||||||
return fs::exists(EnginePaths::getWorldsFolder()/fs::u8path(name));
|
return fs::exists(EnginePaths::getWorldsFolder() / fs::u8path(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnginePaths::setUserfiles(fs::path folder) {
|
void EnginePaths::setUserfiles(fs::path folder) {
|
||||||
@ -125,8 +128,7 @@ static fs::path toCanonic(fs::path path) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
parts.push(path.filename().u8string());
|
parts.push(path.filename().u8string());
|
||||||
path = path.parent_path();
|
path = path.parent_path();
|
||||||
if (path.empty())
|
if (path.empty()) break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
path = fs::u8path("");
|
path = fs::u8path("");
|
||||||
while (!parts.empty()) {
|
while (!parts.empty()) {
|
||||||
@ -150,28 +152,28 @@ fs::path EnginePaths::resolve(const std::string& path, bool throwErr) {
|
|||||||
throw files_access_error("no entry point specified");
|
throw files_access_error("no entry point specified");
|
||||||
}
|
}
|
||||||
std::string prefix = path.substr(0, separator);
|
std::string prefix = path.substr(0, separator);
|
||||||
std::string filename = path.substr(separator+1);
|
std::string filename = path.substr(separator + 1);
|
||||||
filename = toCanonic(fs::u8path(filename)).u8string();
|
filename = toCanonic(fs::u8path(filename)).u8string();
|
||||||
|
|
||||||
if (prefix == "res" || prefix == "core") {
|
if (prefix == "res" || prefix == "core") {
|
||||||
return resources/fs::u8path(filename);
|
return resources / fs::u8path(filename);
|
||||||
}
|
}
|
||||||
if (prefix == "user") {
|
if (prefix == "user") {
|
||||||
return userfiles/fs::u8path(filename);
|
return userfiles / fs::u8path(filename);
|
||||||
}
|
}
|
||||||
if (prefix == "world") {
|
if (prefix == "world") {
|
||||||
return worldFolder/fs::u8path(filename);
|
return worldFolder / fs::u8path(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentPacks) {
|
if (contentPacks) {
|
||||||
for (auto& pack : *contentPacks) {
|
for (auto& pack : *contentPacks) {
|
||||||
if (pack.id == prefix) {
|
if (pack.id == prefix) {
|
||||||
return pack.folder/fs::u8path(filename);
|
return pack.folder / fs::u8path(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (throwErr) {
|
if (throwErr) {
|
||||||
throw files_access_error("unknown entry point '"+prefix+"'");
|
throw files_access_error("unknown entry point '" + prefix + "'");
|
||||||
}
|
}
|
||||||
return fs::path(filename);
|
return fs::path(filename);
|
||||||
}
|
}
|
||||||
@ -181,7 +183,7 @@ ResPaths::ResPaths(fs::path mainRoot, std::vector<PathsRoot> roots)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs::path ResPaths::find(const std::string& filename) const {
|
fs::path ResPaths::find(const std::string& filename) const {
|
||||||
for (int i = roots.size()-1; i >= 0; i--) {
|
for (int i = roots.size() - 1; i >= 0; i--) {
|
||||||
auto& root = roots[i];
|
auto& root = roots[i];
|
||||||
fs::path file = root.path / fs::u8path(filename);
|
fs::path file = root.path / fs::u8path(filename);
|
||||||
if (fs::exists(file)) {
|
if (fs::exists(file)) {
|
||||||
@ -192,7 +194,7 @@ fs::path ResPaths::find(const std::string& filename) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string ResPaths::findRaw(const std::string& filename) const {
|
std::string ResPaths::findRaw(const std::string& filename) const {
|
||||||
for (int i = roots.size()-1; i >= 0; i--) {
|
for (int i = roots.size() - 1; i >= 0; i--) {
|
||||||
auto& root = roots[i];
|
auto& root = roots[i];
|
||||||
if (fs::exists(root.path / fs::path(filename))) {
|
if (fs::exists(root.path / fs::path(filename))) {
|
||||||
return root.name + ":" + filename;
|
return root.name + ":" + filename;
|
||||||
@ -200,30 +202,29 @@ std::string ResPaths::findRaw(const std::string& filename) const {
|
|||||||
}
|
}
|
||||||
auto resDir = mainRoot;
|
auto resDir = mainRoot;
|
||||||
if (fs::exists(resDir / fs::path(filename))) {
|
if (fs::exists(resDir / fs::path(filename))) {
|
||||||
return "core:"+filename;
|
return "core:" + filename;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("could not to find file "+util::quote(filename));
|
throw std::runtime_error("could not to find file " + util::quote(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ResPaths::listdirRaw(const std::string& folderName) const {
|
std::vector<std::string> ResPaths::listdirRaw(const std::string& folderName
|
||||||
|
) const {
|
||||||
std::vector<std::string> entries;
|
std::vector<std::string> entries;
|
||||||
for (int i = roots.size()-1; i >= 0; i--) {
|
for (int i = roots.size() - 1; i >= 0; i--) {
|
||||||
auto& root = roots[i];
|
auto& root = roots[i];
|
||||||
fs::path folder = root.path / fs::u8path(folderName);
|
fs::path folder = root.path / fs::u8path(folderName);
|
||||||
if (!fs::is_directory(folder))
|
if (!fs::is_directory(folder)) continue;
|
||||||
continue;
|
|
||||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||||
auto name = entry.path().filename().u8string();
|
auto name = entry.path().filename().u8string();
|
||||||
entries.emplace_back(root.name+":"+folderName+"/"+name);
|
entries.emplace_back(root.name + ":" + folderName + "/" + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
fs::path folder = mainRoot / fs::u8path(folderName);
|
fs::path folder = mainRoot / fs::u8path(folderName);
|
||||||
if (!fs::is_directory(folder))
|
if (!fs::is_directory(folder)) return entries;
|
||||||
return entries;
|
|
||||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||||
auto name = entry.path().filename().u8string();
|
auto name = entry.path().filename().u8string();
|
||||||
entries.emplace_back("core:"+folderName+"/"+name);
|
entries.emplace_back("core:" + folderName + "/" + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entries;
|
return entries;
|
||||||
@ -231,19 +232,17 @@ std::vector<std::string> ResPaths::listdirRaw(const std::string& folderName) con
|
|||||||
|
|
||||||
std::vector<fs::path> ResPaths::listdir(const std::string& folderName) const {
|
std::vector<fs::path> ResPaths::listdir(const std::string& folderName) const {
|
||||||
std::vector<fs::path> entries;
|
std::vector<fs::path> entries;
|
||||||
for (int i = roots.size()-1; i >= 0; i--) {
|
for (int i = roots.size() - 1; i >= 0; i--) {
|
||||||
auto& root = roots[i];
|
auto& root = roots[i];
|
||||||
fs::path folder = root.path / fs::u8path(folderName);
|
fs::path folder = root.path / fs::u8path(folderName);
|
||||||
if (!fs::is_directory(folder))
|
if (!fs::is_directory(folder)) continue;
|
||||||
continue;
|
|
||||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||||
entries.push_back(entry.path());
|
entries.push_back(entry.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
fs::path folder = mainRoot / fs::u8path(folderName);
|
fs::path folder = mainRoot / fs::u8path(folderName);
|
||||||
if (!fs::is_directory(folder))
|
if (!fs::is_directory(folder)) return entries;
|
||||||
return entries;
|
|
||||||
for (const auto& entry : fs::directory_iterator(folder)) {
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
||||||
entries.push_back(entry.path());
|
entries.push_back(entry.path());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#ifndef FILES_ENGINE_PATHS_HPP_
|
#ifndef FILES_ENGINE_PATHS_HPP_
|
||||||
#define FILES_ENGINE_PATHS_HPP_
|
#define FILES_ENGINE_PATHS_HPP_
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdexcept>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include "../content/ContentPack.hpp"
|
#include "../content/ContentPack.hpp"
|
||||||
|
|
||||||
@ -12,7 +12,8 @@ namespace fs = std::filesystem;
|
|||||||
|
|
||||||
class files_access_error : public std::runtime_error {
|
class files_access_error : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
files_access_error(const std::string& msg) : std::runtime_error(msg) {}
|
files_access_error(const std::string& msg) : std::runtime_error(msg) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EnginePaths {
|
class EnginePaths {
|
||||||
@ -41,7 +42,7 @@ public:
|
|||||||
|
|
||||||
std::vector<fs::path> scanForWorlds();
|
std::vector<fs::path> scanForWorlds();
|
||||||
|
|
||||||
fs::path resolve(const std::string& path, bool throwErr=true);
|
fs::path resolve(const std::string& path, bool throwErr = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PathsRoot {
|
struct PathsRoot {
|
||||||
@ -53,10 +54,7 @@ class ResPaths {
|
|||||||
fs::path mainRoot;
|
fs::path mainRoot;
|
||||||
std::vector<PathsRoot> roots;
|
std::vector<PathsRoot> roots;
|
||||||
public:
|
public:
|
||||||
ResPaths(
|
ResPaths(fs::path mainRoot, std::vector<PathsRoot> roots);
|
||||||
fs::path mainRoot,
|
|
||||||
std::vector<PathsRoot> roots
|
|
||||||
);
|
|
||||||
|
|
||||||
fs::path find(const std::string& filename) const;
|
fs::path find(const std::string& filename) const;
|
||||||
std::string findRaw(const std::string& filename) const;
|
std::string findRaw(const std::string& filename) const;
|
||||||
@ -66,4 +64,4 @@ public:
|
|||||||
const fs::path& getMainRoot() const;
|
const fs::path& getMainRoot() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILES_ENGINE_PATHS_HPP_
|
#endif // FILES_ENGINE_PATHS_HPP_
|
||||||
|
|||||||
@ -1,24 +1,25 @@
|
|||||||
#include "files.hpp"
|
#include "files.hpp"
|
||||||
|
|
||||||
#include "../coders/commons.hpp"
|
#include <stdint.h>
|
||||||
#include "../coders/json.hpp"
|
|
||||||
#include "../coders/toml.hpp"
|
|
||||||
#include "../coders/gzip.hpp"
|
|
||||||
#include "../util/stringutil.hpp"
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "../coders/commons.hpp"
|
||||||
|
#include "../coders/gzip.hpp"
|
||||||
|
#include "../coders/json.hpp"
|
||||||
|
#include "../coders/toml.hpp"
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
files::rafile::rafile(const fs::path& filename)
|
files::rafile::rafile(const fs::path& filename)
|
||||||
: file(filename, std::ios::binary | std::ios::ate) {
|
: file(filename, std::ios::binary | std::ios::ate) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw std::runtime_error("could not to open file "+filename.string());
|
throw std::runtime_error("could not to open file " + filename.string());
|
||||||
}
|
}
|
||||||
filelength = file.tellg();
|
filelength = file.tellg();
|
||||||
file.seekg(0);
|
file.seekg(0);
|
||||||
@ -36,19 +37,21 @@ void files::rafile::read(char* buffer, std::streamsize size) {
|
|||||||
file.read(buffer, size);
|
file.read(buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool files::write_bytes(const fs::path& filename, const ubyte* data, size_t size) {
|
bool files::write_bytes(
|
||||||
|
const fs::path& filename, const ubyte* data, size_t size
|
||||||
|
) {
|
||||||
std::ofstream output(filename, std::ios::binary);
|
std::ofstream output(filename, std::ios::binary);
|
||||||
if (!output.is_open())
|
if (!output.is_open()) return false;
|
||||||
return false;
|
|
||||||
output.write((const char*)data, size);
|
output.write((const char*)data, size);
|
||||||
output.close();
|
output.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint files::append_bytes(const fs::path& filename, const ubyte* data, size_t size) {
|
uint files::append_bytes(
|
||||||
|
const fs::path& filename, const ubyte* data, size_t size
|
||||||
|
) {
|
||||||
std::ofstream output(filename, std::ios::binary | std::ios::app);
|
std::ofstream output(filename, std::ios::binary | std::ios::app);
|
||||||
if (!output.is_open())
|
if (!output.is_open()) return 0;
|
||||||
return 0;
|
|
||||||
uint position = output.tellp();
|
uint position = output.tellp();
|
||||||
output.write((const char*)data, size);
|
output.write((const char*)data, size);
|
||||||
output.close();
|
output.close();
|
||||||
@ -57,17 +60,17 @@ uint files::append_bytes(const fs::path& filename, const ubyte* data, size_t siz
|
|||||||
|
|
||||||
bool files::read(const fs::path& filename, char* data, size_t size) {
|
bool files::read(const fs::path& filename, char* data, size_t size) {
|
||||||
std::ifstream output(filename, std::ios::binary);
|
std::ifstream output(filename, std::ios::binary);
|
||||||
if (!output.is_open())
|
if (!output.is_open()) return false;
|
||||||
return false;
|
|
||||||
output.read(data, size);
|
output.read(data, size);
|
||||||
output.close();
|
output.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ubyte[]> files::read_bytes(const fs::path& filename, size_t& length) {
|
std::unique_ptr<ubyte[]> files::read_bytes(
|
||||||
|
const fs::path& filename, size_t& length
|
||||||
|
) {
|
||||||
std::ifstream input(filename, std::ios::binary);
|
std::ifstream input(filename, std::ios::binary);
|
||||||
if (!input.is_open())
|
if (!input.is_open()) return nullptr;
|
||||||
return nullptr;
|
|
||||||
input.seekg(0, std::ios_base::end);
|
input.seekg(0, std::ios_base::end);
|
||||||
length = input.tellg();
|
length = input.tellg();
|
||||||
input.seekg(0, std::ios_base::beg);
|
input.seekg(0, std::ios_base::beg);
|
||||||
@ -80,8 +83,7 @@ std::unique_ptr<ubyte[]> files::read_bytes(const fs::path& filename, size_t& len
|
|||||||
|
|
||||||
std::vector<ubyte> files::read_bytes(const fs::path& filename) {
|
std::vector<ubyte> files::read_bytes(const fs::path& filename) {
|
||||||
std::ifstream input(filename, std::ios::binary);
|
std::ifstream input(filename, std::ios::binary);
|
||||||
if (!input.is_open())
|
if (!input.is_open()) return {};
|
||||||
return {};
|
|
||||||
input.seekg(0, std::ios_base::end);
|
input.seekg(0, std::ios_base::end);
|
||||||
size_t length = input.tellg();
|
size_t length = input.tellg();
|
||||||
input.seekg(0, std::ios_base::beg);
|
input.seekg(0, std::ios_base::beg);
|
||||||
@ -95,10 +97,11 @@ std::vector<ubyte> files::read_bytes(const fs::path& filename) {
|
|||||||
|
|
||||||
std::string files::read_string(const fs::path& filename) {
|
std::string files::read_string(const fs::path& filename) {
|
||||||
size_t size;
|
size_t size;
|
||||||
std::unique_ptr<ubyte[]> bytes (read_bytes(filename, size));
|
std::unique_ptr<ubyte[]> bytes(read_bytes(filename, size));
|
||||||
if (bytes == nullptr) {
|
if (bytes == nullptr) {
|
||||||
throw std::runtime_error("could not to load file '"+
|
throw std::runtime_error(
|
||||||
filename.string()+"'");
|
"could not to load file '" + filename.string() + "'"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return std::string((const char*)bytes.get(), size);
|
return std::string((const char*)bytes.get(), size);
|
||||||
}
|
}
|
||||||
@ -112,11 +115,15 @@ bool files::write_string(const fs::path& filename, const std::string content) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool files::write_json(const fs::path& filename, const dynamic::Map* obj, bool nice) {
|
bool files::write_json(
|
||||||
|
const fs::path& filename, const dynamic::Map* obj, bool nice
|
||||||
|
) {
|
||||||
return files::write_string(filename, json::stringify(obj, nice, " "));
|
return files::write_string(filename, json::stringify(obj, nice, " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool files::write_binary_json(const fs::path& filename, const dynamic::Map* obj, bool compression) {
|
bool files::write_binary_json(
|
||||||
|
const fs::path& filename, const dynamic::Map* obj, bool compression
|
||||||
|
) {
|
||||||
auto bytes = json::to_binary(obj, compression);
|
auto bytes = json::to_binary(obj, compression);
|
||||||
return files::write_bytes(filename, bytes.data(), bytes.size());
|
return files::write_bytes(filename, bytes.data(), bytes.size());
|
||||||
}
|
}
|
||||||
@ -128,7 +135,7 @@ std::shared_ptr<dynamic::Map> files::read_json(const fs::path& filename) {
|
|||||||
|
|
||||||
std::shared_ptr<dynamic::Map> files::read_binary_json(const fs::path& file) {
|
std::shared_ptr<dynamic::Map> files::read_binary_json(const fs::path& file) {
|
||||||
size_t size;
|
size_t size;
|
||||||
std::unique_ptr<ubyte[]> bytes (files::read_bytes(file, size));
|
std::unique_ptr<ubyte[]> bytes(files::read_bytes(file, size));
|
||||||
return json::from_binary(bytes.get(), size);
|
return json::from_binary(bytes.get(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,16 +146,16 @@ std::shared_ptr<dynamic::Map> files::read_toml(const fs::path& file) {
|
|||||||
std::vector<std::string> files::read_list(const fs::path& filename) {
|
std::vector<std::string> files::read_list(const fs::path& filename) {
|
||||||
std::ifstream file(filename);
|
std::ifstream file(filename);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw std::runtime_error("could not to open file "+filename.u8string());
|
throw std::runtime_error(
|
||||||
|
"could not to open file " + filename.u8string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
util::trim(line);
|
util::trim(line);
|
||||||
if (line.length() == 0)
|
if (line.length() == 0) continue;
|
||||||
continue;
|
if (line[0] == '#') continue;
|
||||||
if (line[0] == '#')
|
|
||||||
continue;
|
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
#ifndef FILES_FILES_HPP_
|
#ifndef FILES_FILES_HPP_
|
||||||
#define FILES_FILES_HPP_
|
#define FILES_FILES_HPP_
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
|
||||||
#include <fstream>
|
|
||||||
#include <filesystem>
|
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@ -43,8 +44,11 @@ namespace files {
|
|||||||
bool write_string(const fs::path& filename, const std::string content);
|
bool write_string(const fs::path& filename, const std::string content);
|
||||||
|
|
||||||
/// @brief Write dynamic data to the JSON file
|
/// @brief Write dynamic data to the JSON file
|
||||||
/// @param nice if true, human readable format will be used, otherwise minimal
|
/// @param nice if true, human readable format will be used, otherwise
|
||||||
bool write_json(const fs::path& filename, const dynamic::Map* obj, bool nice=true);
|
/// minimal
|
||||||
|
bool write_json(
|
||||||
|
const fs::path& filename, const dynamic::Map* obj, bool nice = true
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Write dynamic data to the binary JSON file
|
/// @brief Write dynamic data to the binary JSON file
|
||||||
/// (see src/coders/binary_json_spec.md)
|
/// (see src/coders/binary_json_spec.md)
|
||||||
@ -52,7 +56,7 @@ namespace files {
|
|||||||
bool write_binary_json(
|
bool write_binary_json(
|
||||||
const fs::path& filename,
|
const fs::path& filename,
|
||||||
const dynamic::Map* obj,
|
const dynamic::Map* obj,
|
||||||
bool compressed=false
|
bool compressed = false
|
||||||
);
|
);
|
||||||
|
|
||||||
bool read(const fs::path&, char* data, size_t size);
|
bool read(const fs::path&, char* data, size_t size);
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
#include "settings_io.hpp"
|
#include "settings_io.hpp"
|
||||||
|
|
||||||
#include "../window/Events.hpp"
|
|
||||||
#include "../window/input.hpp"
|
|
||||||
#include "../coders/toml.hpp"
|
|
||||||
#include "../coders/json.hpp"
|
|
||||||
#include "../debug/Logger.hpp"
|
|
||||||
#include "../settings.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../coders/json.hpp"
|
||||||
|
#include "../coders/toml.hpp"
|
||||||
|
#include "../debug/Logger.hpp"
|
||||||
|
#include "../settings.hpp"
|
||||||
|
#include "../window/Events.hpp"
|
||||||
|
#include "../window/input.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("settings_io");
|
static debug::Logger logger("settings_io");
|
||||||
|
|
||||||
struct SectionsBuilder {
|
struct SectionsBuilder {
|
||||||
@ -19,16 +19,17 @@ struct SectionsBuilder {
|
|||||||
SectionsBuilder(
|
SectionsBuilder(
|
||||||
std::unordered_map<std::string, Setting*>& map,
|
std::unordered_map<std::string, Setting*>& map,
|
||||||
std::vector<Section>& sections
|
std::vector<Section>& sections
|
||||||
) : map(map), sections(sections) {
|
)
|
||||||
|
: map(map), sections(sections) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void section(std::string name) {
|
void section(std::string name) {
|
||||||
sections.push_back(Section {std::move(name), {}});
|
sections.push_back(Section {std::move(name), {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const std::string& name, Setting* setting, bool writeable=true) {
|
void add(const std::string& name, Setting* setting, bool writeable = true) {
|
||||||
Section& section = sections.at(sections.size()-1);
|
Section& section = sections.at(sections.size() - 1);
|
||||||
map[section.name+"."+name] = setting;
|
map[section.name + "." + name] = setting;
|
||||||
section.keys.push_back(name);
|
section.keys.push_back(name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -82,7 +83,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||||||
dynamic::Value SettingsHandler::getValue(const std::string& name) const {
|
dynamic::Value SettingsHandler::getValue(const std::string& name) const {
|
||||||
auto found = map.find(name);
|
auto found = map.find(name);
|
||||||
if (found == map.end()) {
|
if (found == map.end()) {
|
||||||
throw std::runtime_error("setting '"+name+"' does not exist");
|
throw std::runtime_error("setting '" + name + "' does not exist");
|
||||||
}
|
}
|
||||||
auto setting = found->second;
|
auto setting = found->second;
|
||||||
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
||||||
@ -94,14 +95,14 @@ dynamic::Value SettingsHandler::getValue(const std::string& name) const {
|
|||||||
} else if (auto string = dynamic_cast<StringSetting*>(setting)) {
|
} else if (auto string = dynamic_cast<StringSetting*>(setting)) {
|
||||||
return string->get();
|
return string->get();
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("type is not implemented for '"+name+"'");
|
throw std::runtime_error("type is not implemented for '" + name + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SettingsHandler::toString(const std::string& name) const {
|
std::string SettingsHandler::toString(const std::string& name) const {
|
||||||
auto found = map.find(name);
|
auto found = map.find(name);
|
||||||
if (found == map.end()) {
|
if (found == map.end()) {
|
||||||
throw std::runtime_error("setting '"+name+"' does not exist");
|
throw std::runtime_error("setting '" + name + "' does not exist");
|
||||||
}
|
}
|
||||||
auto setting = found->second;
|
auto setting = found->second;
|
||||||
return setting->toString();
|
return setting->toString();
|
||||||
@ -110,7 +111,7 @@ std::string SettingsHandler::toString(const std::string& name) const {
|
|||||||
Setting* SettingsHandler::getSetting(const std::string& name) const {
|
Setting* SettingsHandler::getSetting(const std::string& name) const {
|
||||||
auto found = map.find(name);
|
auto found = map.find(name);
|
||||||
if (found == map.end()) {
|
if (found == map.end()) {
|
||||||
throw std::runtime_error("setting '"+name+"' does not exist");
|
throw std::runtime_error("setting '" + name + "' does not exist");
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
@ -119,7 +120,7 @@ bool SettingsHandler::has(const std::string& name) const {
|
|||||||
return map.find(name) != map.end();
|
return map.find(name) != map.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
static void set_numeric_value(T* setting, const dynamic::Value& value) {
|
static void set_numeric_value(T* setting, const dynamic::Value& value) {
|
||||||
if (auto num = std::get_if<integer_t>(&value)) {
|
if (auto num = std::get_if<integer_t>(&value)) {
|
||||||
setting->set(*num);
|
setting->set(*num);
|
||||||
@ -132,10 +133,12 @@ static void set_numeric_value(T* setting, const dynamic::Value& value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsHandler::setValue(const std::string& name, const dynamic::Value& value) {
|
void SettingsHandler::setValue(
|
||||||
|
const std::string& name, const dynamic::Value& value
|
||||||
|
) {
|
||||||
auto found = map.find(name);
|
auto found = map.find(name);
|
||||||
if (found == map.end()) {
|
if (found == map.end()) {
|
||||||
throw std::runtime_error("setting '"+name+"' does not exist");
|
throw std::runtime_error("setting '" + name + "' does not exist");
|
||||||
}
|
}
|
||||||
auto setting = found->second;
|
auto setting = found->second;
|
||||||
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
||||||
@ -157,7 +160,9 @@ void SettingsHandler::setValue(const std::string& name, const dynamic::Value& va
|
|||||||
throw std::runtime_error("not implemented for type");
|
throw std::runtime_error("not implemented for type");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("type is not implement - setting '"+name+"'");
|
throw std::runtime_error(
|
||||||
|
"type is not implement - setting '" + name + "'"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef FILES_SETTINGS_IO_HPP_
|
#ifndef FILES_SETTINGS_IO_HPP_
|
||||||
#define FILES_SETTINGS_IO_HPP_
|
#define FILES_SETTINGS_IO_HPP_
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
|
||||||
class Setting;
|
class Setting;
|
||||||
struct EngineSettings;
|
struct EngineSettings;
|
||||||
@ -31,4 +31,4 @@ public:
|
|||||||
std::vector<Section>& getSections();
|
std::vector<Section>& getSections();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILES_SETTINGS_IO_HPP_
|
#endif // FILES_SETTINGS_IO_HPP_
|
||||||
|
|||||||
@ -40,15 +40,13 @@ void Inventories::remove(int64_t id) {
|
|||||||
|
|
||||||
std::shared_ptr<Inventory> Inventories::get(int64_t id) {
|
std::shared_ptr<Inventory> Inventories::get(int64_t id) {
|
||||||
auto found = map.find(id);
|
auto found = map.find(id);
|
||||||
if (found == map.end())
|
if (found == map.end()) return nullptr;
|
||||||
return nullptr;
|
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Inventory> Inventories::clone(int64_t id) {
|
std::shared_ptr<Inventory> Inventories::clone(int64_t id) {
|
||||||
auto original = get(id);
|
auto original = get(id);
|
||||||
if (original == nullptr)
|
if (original == nullptr) return nullptr;
|
||||||
return nullptr;
|
|
||||||
auto clone = std::make_shared<Inventory>(*original);
|
auto clone = std::make_shared<Inventory>(*original);
|
||||||
clone->setId(level.getWorld()->getNextInventoryId());
|
clone->setId(level.getWorld()->getNextInventoryId());
|
||||||
store(clone);
|
store(clone);
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#ifndef ITEMS_INVENTORIES_HPP_
|
#ifndef ITEMS_INVENTORIES_HPP_
|
||||||
#define ITEMS_INVENTORIES_HPP_
|
#define ITEMS_INVENTORIES_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "Inventory.hpp"
|
|
||||||
#include "../maths/util.hpp"
|
#include "../maths/util.hpp"
|
||||||
|
#include "Inventory.hpp"
|
||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
|
|
||||||
@ -41,4 +41,4 @@ public:
|
|||||||
const inventories_map& getMap() const;
|
const inventories_map& getMap() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ITEMS_INVENTORIES_HPP_
|
#endif // ITEMS_INVENTORIES_HPP_
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "Inventory.hpp"
|
#include "Inventory.hpp"
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
|
||||||
#include "../content/ContentLUT.hpp"
|
#include "../content/ContentLUT.hpp"
|
||||||
|
#include "../data/dynamic.hpp"
|
||||||
|
|
||||||
Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) {
|
Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) {
|
||||||
}
|
}
|
||||||
@ -35,11 +35,8 @@ size_t Inventory::findSlotByItem(itemid_t id, size_t begin, size_t end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Inventory::move(
|
void Inventory::move(
|
||||||
ItemStack& item,
|
ItemStack& item, const ContentIndices* indices, size_t begin, size_t end
|
||||||
const ContentIndices* indices,
|
) {
|
||||||
size_t begin,
|
|
||||||
size_t end)
|
|
||||||
{
|
|
||||||
end = std::min(slots.size(), end);
|
end = std::min(slots.size(), end);
|
||||||
for (size_t i = begin; i < end && !item.isEmpty(); i++) {
|
for (size_t i = begin; i < end && !item.isEmpty(); i++) {
|
||||||
ItemStack& slot = slots[i];
|
ItemStack& slot = slots[i];
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
#ifndef ITEMS_INVENTORY_HPP_
|
#ifndef ITEMS_INVENTORY_HPP_
|
||||||
#define ITEMS_INVENTORY_HPP_
|
#define ITEMS_INVENTORY_HPP_
|
||||||
|
|
||||||
#include "ItemStack.hpp"
|
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../interfaces/Serializable.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../interfaces/Serializable.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
#include "ItemStack.hpp"
|
||||||
|
|
||||||
namespace dynamic {
|
namespace dynamic {
|
||||||
class Map;
|
class Map;
|
||||||
@ -25,8 +24,8 @@ public:
|
|||||||
Inventory(const Inventory& orig);
|
Inventory(const Inventory& orig);
|
||||||
|
|
||||||
ItemStack& getSlot(size_t index);
|
ItemStack& getSlot(size_t index);
|
||||||
size_t findEmptySlot(size_t begin=0, size_t end=-1) const;
|
size_t findEmptySlot(size_t begin = 0, size_t end = -1) const;
|
||||||
size_t findSlotByItem(itemid_t id, size_t begin=0, size_t end=-1);
|
size_t findSlotByItem(itemid_t id, size_t begin = 0, size_t end = -1);
|
||||||
|
|
||||||
inline size_t size() const {
|
inline size_t size() const {
|
||||||
return slots.size();
|
return slots.size();
|
||||||
@ -35,8 +34,9 @@ public:
|
|||||||
void move(
|
void move(
|
||||||
ItemStack& item,
|
ItemStack& item,
|
||||||
const ContentIndices* indices,
|
const ContentIndices* indices,
|
||||||
size_t begin=0,
|
size_t begin = 0,
|
||||||
size_t end=-1);
|
size_t end = -1
|
||||||
|
);
|
||||||
|
|
||||||
/* deserializing inventory */
|
/* deserializing inventory */
|
||||||
void deserialize(dynamic::Map* src) override;
|
void deserialize(dynamic::Map* src) override;
|
||||||
@ -60,4 +60,4 @@ public:
|
|||||||
static const size_t npos;
|
static const size_t npos;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ITEMS_INVENTORY_HPP_
|
#endif // ITEMS_INVENTORY_HPP_
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "ItemDef.hpp"
|
#include "ItemDef.hpp"
|
||||||
|
|
||||||
#include "../util/stringutil.hpp"
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
ItemDef::ItemDef(const std::string& name) : name(name) {
|
ItemDef::ItemDef(const std::string& name) : name(name) {
|
||||||
|
|||||||
@ -1,22 +1,22 @@
|
|||||||
#ifndef CONTENT_ITEMS_ITEM_DEF_HPP_
|
#ifndef CONTENT_ITEMS_ITEM_DEF_HPP_
|
||||||
#define CONTENT_ITEMS_ITEM_DEF_HPP_
|
#define CONTENT_ITEMS_ITEM_DEF_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
struct item_funcs_set {
|
struct item_funcs_set {
|
||||||
bool init: 1;
|
bool init : 1;
|
||||||
bool on_use: 1;
|
bool on_use : 1;
|
||||||
bool on_use_on_block: 1;
|
bool on_use_on_block : 1;
|
||||||
bool on_block_break_by: 1;
|
bool on_block_break_by : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class item_icon_type {
|
enum class item_icon_type {
|
||||||
none, // invisible (core:empty) must not be rendered
|
none, // invisible (core:empty) must not be rendered
|
||||||
sprite, // textured quad: icon is `atlas_name:texture_name`
|
sprite, // textured quad: icon is `atlas_name:texture_name`
|
||||||
block, // block preview: icon is string block id
|
block, // block preview: icon is string block id
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ItemDef {
|
struct ItemDef {
|
||||||
@ -34,7 +34,7 @@ struct ItemDef {
|
|||||||
std::string icon = "blocks:notfound";
|
std::string icon = "blocks:notfound";
|
||||||
|
|
||||||
std::string placingBlock = "core:air";
|
std::string placingBlock = "core:air";
|
||||||
std::string scriptName = name.substr(name.find(':')+1);
|
std::string scriptName = name.substr(name.find(':') + 1);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
itemid_t id;
|
itemid_t id;
|
||||||
@ -47,4 +47,4 @@ struct ItemDef {
|
|||||||
ItemDef(const ItemDef&) = delete;
|
ItemDef(const ItemDef&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //CONTENT_ITEMS_ITEM_DEF_HPP_
|
#endif // CONTENT_ITEMS_ITEM_DEF_HPP_
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
#include "ItemStack.hpp"
|
#include "ItemStack.hpp"
|
||||||
|
|
||||||
#include "ItemDef.hpp"
|
|
||||||
#include "../content/Content.hpp"
|
#include "../content/Content.hpp"
|
||||||
|
#include "ItemDef.hpp"
|
||||||
|
|
||||||
ItemStack::ItemStack() : item(ITEM_EMPTY), count(0) {
|
ItemStack::ItemStack() : item(ITEM_EMPTY), count(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemStack::ItemStack(itemid_t item, itemcount_t count) : item(item), count(count) {
|
ItemStack::ItemStack(itemid_t item, itemcount_t count)
|
||||||
|
: item(item), count(count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemStack::set(const ItemStack& item) {
|
void ItemStack::set(const ItemStack& item) {
|
||||||
@ -26,13 +27,13 @@ bool ItemStack::accepts(const ItemStack& other) const {
|
|||||||
|
|
||||||
void ItemStack::move(ItemStack& item, const ContentIndices* indices) {
|
void ItemStack::move(ItemStack& item, const ContentIndices* indices) {
|
||||||
auto def = indices->items.get(item.getItemId());
|
auto def = indices->items.get(item.getItemId());
|
||||||
int count = std::min(item.count, def->stackSize-this->count);
|
int count = std::min(item.count, def->stackSize - this->count);
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
set(ItemStack(item.getItemId(), count));
|
set(ItemStack(item.getItemId(), count));
|
||||||
} else {
|
} else {
|
||||||
setCount(this->count + count);
|
setCount(this->count + count);
|
||||||
}
|
}
|
||||||
item.setCount(item.count-count);
|
item.setCount(item.count - count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemStack::setCount(itemcount_t count) {
|
void ItemStack::setCount(itemcount_t count) {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#ifndef ITEMS_ITEM_STACK_HPP_
|
#ifndef ITEMS_ITEM_STACK_HPP_
|
||||||
#define ITEMS_ITEM_STACK_HPP_
|
#define ITEMS_ITEM_STACK_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../constants.hpp"
|
#include "../constants.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
class ContentIndices;
|
class ContentIndices;
|
||||||
|
|
||||||
@ -37,4 +37,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ITEMS_ITEM_STACK_HPP_
|
#endif // ITEMS_ITEM_STACK_HPP_
|
||||||
|
|||||||
@ -1,18 +1,17 @@
|
|||||||
#include "BlocksController.hpp"
|
#include "BlocksController.hpp"
|
||||||
|
|
||||||
#include "../voxels/voxel.hpp"
|
#include "../content/Content.hpp"
|
||||||
|
#include "../items/Inventories.hpp"
|
||||||
|
#include "../items/Inventory.hpp"
|
||||||
|
#include "../lighting/Lighting.hpp"
|
||||||
|
#include "../maths/fastmaths.hpp"
|
||||||
|
#include "../util/timeutil.hpp"
|
||||||
#include "../voxels/Block.hpp"
|
#include "../voxels/Block.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
#include "../voxels/Chunks.hpp"
|
#include "../voxels/Chunks.hpp"
|
||||||
|
#include "../voxels/voxel.hpp"
|
||||||
#include "../world/Level.hpp"
|
#include "../world/Level.hpp"
|
||||||
#include "../world/World.hpp"
|
#include "../world/World.hpp"
|
||||||
#include "../content/Content.hpp"
|
|
||||||
#include "../lighting/Lighting.hpp"
|
|
||||||
#include "../util/timeutil.hpp"
|
|
||||||
#include "../maths/fastmaths.hpp"
|
|
||||||
#include "../items/Inventory.hpp"
|
|
||||||
#include "../items/Inventories.hpp"
|
|
||||||
|
|
||||||
#include "scripting/scripting.hpp"
|
#include "scripting/scripting.hpp"
|
||||||
|
|
||||||
BlocksController::BlocksController(Level* level, uint padding)
|
BlocksController::BlocksController(Level* level, uint padding)
|
||||||
@ -26,26 +25,32 @@ BlocksController::BlocksController(Level* level, uint padding)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlocksController::updateSides(int x, int y, int z) {
|
void BlocksController::updateSides(int x, int y, int z) {
|
||||||
updateBlock(x-1, y, z);
|
updateBlock(x - 1, y, z);
|
||||||
updateBlock(x+1, y, z);
|
updateBlock(x + 1, y, z);
|
||||||
updateBlock(x, y-1, z);
|
updateBlock(x, y - 1, z);
|
||||||
updateBlock(x, y+1, z);
|
updateBlock(x, y + 1, z);
|
||||||
updateBlock(x, y, z-1);
|
updateBlock(x, y, z - 1);
|
||||||
updateBlock(x, y, z+1);
|
updateBlock(x, y, z + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlocksController::breakBlock(Player* player, const Block* def, int x, int y, int z) {
|
void BlocksController::breakBlock(
|
||||||
|
Player* player, const Block* def, int x, int y, int z
|
||||||
|
) {
|
||||||
onBlockInteraction(
|
onBlockInteraction(
|
||||||
player, glm::ivec3(x, y, z), def, BlockInteraction::destruction);
|
player, glm::ivec3(x, y, z), def, BlockInteraction::destruction
|
||||||
|
);
|
||||||
chunks->set(x, y, z, 0, {});
|
chunks->set(x, y, z, 0, {});
|
||||||
lighting->onBlockSet(x, y, z, 0);
|
lighting->onBlockSet(x, y, z, 0);
|
||||||
scripting::on_block_broken(player, def, x, y, z);
|
scripting::on_block_broken(player, def, x, y, z);
|
||||||
updateSides(x, y, z);
|
updateSides(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlocksController::placeBlock(Player* player, const Block* def, blockstate state, int x, int y, int z) {
|
void BlocksController::placeBlock(
|
||||||
|
Player* player, const Block* def, blockstate state, int x, int y, int z
|
||||||
|
) {
|
||||||
onBlockInteraction(
|
onBlockInteraction(
|
||||||
player, glm::ivec3(x, y, z), def, BlockInteraction::placing);
|
player, glm::ivec3(x, y, z), def, BlockInteraction::placing
|
||||||
|
);
|
||||||
chunks->set(x, y, z, def->rt.id, state);
|
chunks->set(x, y, z, def->rt.id, state);
|
||||||
lighting->onBlockSet(x, y, z, def->rt.id);
|
lighting->onBlockSet(x, y, z, def->rt.id);
|
||||||
if (def->rt.funcsset.onplaced) {
|
if (def->rt.funcsset.onplaced) {
|
||||||
@ -56,12 +61,11 @@ void BlocksController::placeBlock(Player* player, const Block* def, blockstate s
|
|||||||
|
|
||||||
void BlocksController::updateBlock(int x, int y, int z) {
|
void BlocksController::updateBlock(int x, int y, int z) {
|
||||||
voxel* vox = chunks->get(x, y, z);
|
voxel* vox = chunks->get(x, y, z);
|
||||||
if (vox == nullptr)
|
if (vox == nullptr) return;
|
||||||
return;
|
|
||||||
auto def = level->content->getIndices()->blocks.get(vox->id);
|
auto def = level->content->getIndices()->blocks.get(vox->id);
|
||||||
if (def->grounded) {
|
if (def->grounded) {
|
||||||
const auto& vec = get_ground_direction(def, vox->state.rotation);
|
const auto& vec = get_ground_direction(def, vox->state.rotation);
|
||||||
if (!chunks->isSolidBlock(x+vec.x, y+vec.y, z+vec.z)) {
|
if (!chunks->isSolidBlock(x + vec.x, y + vec.y, z + vec.z)) {
|
||||||
breakBlock(nullptr, def, x, y, z);
|
breakBlock(nullptr, def, x, y, z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -88,8 +92,7 @@ void BlocksController::onBlocksTick(int tickid, int parts) {
|
|||||||
auto indices = content->getIndices();
|
auto indices = content->getIndices();
|
||||||
int tickRate = blocksTickClock.getTickRate();
|
int tickRate = blocksTickClock.getTickRate();
|
||||||
for (size_t id = 0; id < indices->blocks.count(); id++) {
|
for (size_t id = 0; id < indices->blocks.count(); id++) {
|
||||||
if ((id + tickid) % parts != 0)
|
if ((id + tickid) % parts != 0) continue;
|
||||||
continue;
|
|
||||||
auto def = indices->blocks.get(id);
|
auto def = indices->blocks.get(id);
|
||||||
auto interval = def->tickInterval;
|
auto interval = def->tickInterval;
|
||||||
if (def->rt.funcsset.onblockstick && tickid / parts % interval == 0) {
|
if (def->rt.funcsset.onblockstick && tickid / parts % interval == 0) {
|
||||||
@ -112,9 +115,7 @@ void BlocksController::randomTick(
|
|||||||
Block* block = indices->blocks.get(vox.id);
|
Block* block = indices->blocks.get(vox.id);
|
||||||
if (block->rt.funcsset.randupdate) {
|
if (block->rt.funcsset.randupdate) {
|
||||||
scripting::random_update_block(
|
scripting::random_update_block(
|
||||||
block,
|
block, chunk.x * CHUNK_W + bx, by, chunk.z * CHUNK_D + bz
|
||||||
chunk.x * CHUNK_W + bx, by,
|
|
||||||
chunk.z * CHUNK_D + bz
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,8 +128,8 @@ void BlocksController::randomTick(int tickid, int parts) {
|
|||||||
const int d = chunks->d;
|
const int d = chunks->d;
|
||||||
int segments = 4;
|
int segments = 4;
|
||||||
|
|
||||||
for (uint z = padding; z < d-padding; z++){
|
for (uint z = padding; z < d - padding; z++) {
|
||||||
for (uint x = padding; x < w-padding; x++){
|
for (uint x = padding; x < w - padding; x++) {
|
||||||
int index = z * w + x;
|
int index = z * w + x;
|
||||||
if ((index + tickid) % parts != 0) {
|
if ((index + tickid) % parts != 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -187,16 +188,15 @@ void BlocksController::unbindInventory(int x, int y, int z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlocksController::onBlockInteraction(
|
void BlocksController::onBlockInteraction(
|
||||||
Player* player,
|
Player* player, glm::ivec3 pos, const Block* def, BlockInteraction type
|
||||||
glm::ivec3 pos,
|
|
||||||
const Block* def,
|
|
||||||
BlockInteraction type
|
|
||||||
) {
|
) {
|
||||||
for (const auto& callback : blockInteractionCallbacks) {
|
for (const auto& callback : blockInteractionCallbacks) {
|
||||||
callback(player, pos, def, type);
|
callback(player, pos, def, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlocksController::listenBlockInteraction(const on_block_interaction& callback) {
|
void BlocksController::listenBlockInteraction(
|
||||||
|
const on_block_interaction& callback
|
||||||
|
) {
|
||||||
blockInteractionCallbacks.push_back(callback);
|
blockInteractionCallbacks.push_back(callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
#ifndef LOGIC_BLOCKS_CONTROLLER_HPP_
|
#ifndef LOGIC_BLOCKS_CONTROLLER_HPP_
|
||||||
#define LOGIC_BLOCKS_CONTROLLER_HPP_
|
#define LOGIC_BLOCKS_CONTROLLER_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../maths/fastmaths.hpp"
|
|
||||||
#include "../voxels/voxel.hpp"
|
|
||||||
#include "../util/Clock.hpp"
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "../maths/fastmaths.hpp"
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
#include "../util/Clock.hpp"
|
||||||
|
#include "../voxels/voxel.hpp"
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class Block;
|
class Block;
|
||||||
class Level;
|
class Level;
|
||||||
@ -17,22 +17,17 @@ class Chunks;
|
|||||||
class Lighting;
|
class Lighting;
|
||||||
class ContentIndices;
|
class ContentIndices;
|
||||||
|
|
||||||
enum class BlockInteraction {
|
enum class BlockInteraction { step, destruction, placing };
|
||||||
step,
|
|
||||||
destruction,
|
|
||||||
placing
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief Player argument is nullable
|
/// @brief Player argument is nullable
|
||||||
using on_block_interaction = std::function<void(
|
using on_block_interaction = std::function<
|
||||||
Player*, glm::ivec3, const Block*, BlockInteraction type
|
void(Player*, glm::ivec3, const Block*, BlockInteraction type)>;
|
||||||
)>;
|
|
||||||
|
|
||||||
/// BlocksController manages block updates and data (inventories, metadata)
|
/// BlocksController manages block updates and data (inventories, metadata)
|
||||||
class BlocksController {
|
class BlocksController {
|
||||||
Level* level;
|
Level* level;
|
||||||
Chunks* chunks;
|
Chunks* chunks;
|
||||||
Lighting* lighting;
|
Lighting* lighting;
|
||||||
util::Clock randTickClock;
|
util::Clock randTickClock;
|
||||||
util::Clock blocksTickClock;
|
util::Clock blocksTickClock;
|
||||||
util::Clock worldTickClock;
|
util::Clock worldTickClock;
|
||||||
@ -46,10 +41,14 @@ public:
|
|||||||
void updateBlock(int x, int y, int z);
|
void updateBlock(int x, int y, int z);
|
||||||
|
|
||||||
void breakBlock(Player* player, const Block* def, int x, int y, int z);
|
void breakBlock(Player* player, const Block* def, int x, int y, int z);
|
||||||
void placeBlock(Player* player, const Block* def, blockstate state, int x, int y, int z);
|
void placeBlock(
|
||||||
|
Player* player, const Block* def, blockstate state, int x, int y, int z
|
||||||
|
);
|
||||||
|
|
||||||
void update(float delta);
|
void update(float delta);
|
||||||
void randomTick(const Chunk& chunk, int segments, const ContentIndices* indices);
|
void randomTick(
|
||||||
|
const Chunk& chunk, int segments, const ContentIndices* indices
|
||||||
|
);
|
||||||
void randomTick(int tickid, int parts);
|
void randomTick(int tickid, int parts);
|
||||||
void onBlocksTick(int tickid, int parts);
|
void onBlocksTick(int tickid, int parts);
|
||||||
int64_t createBlockInventory(int x, int y, int z);
|
int64_t createBlockInventory(int x, int y, int z);
|
||||||
@ -57,14 +56,11 @@ public:
|
|||||||
void unbindInventory(int x, int y, int z);
|
void unbindInventory(int x, int y, int z);
|
||||||
|
|
||||||
void onBlockInteraction(
|
void onBlockInteraction(
|
||||||
Player* player,
|
Player* player, glm::ivec3 pos, const Block* def, BlockInteraction type
|
||||||
glm::ivec3 pos,
|
|
||||||
const Block* def,
|
|
||||||
BlockInteraction type
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// @brief Add block interaction callback
|
/// @brief Add block interaction callback
|
||||||
void listenBlockInteraction(const on_block_interaction& callback);
|
void listenBlockInteraction(const on_block_interaction& callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOGIC_BLOCKS_CONTROLLER_HPP_
|
#endif // LOGIC_BLOCKS_CONTROLLER_HPP_
|
||||||
|
|||||||
@ -1,33 +1,36 @@
|
|||||||
#include "ChunksController.hpp"
|
#include "ChunksController.hpp"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "../content/Content.hpp"
|
#include "../content/Content.hpp"
|
||||||
|
#include "../files/WorldFiles.hpp"
|
||||||
|
#include "../graphics/core/Mesh.hpp"
|
||||||
|
#include "../lighting/Lighting.hpp"
|
||||||
|
#include "../maths/voxmaths.hpp"
|
||||||
|
#include "../util/timeutil.hpp"
|
||||||
#include "../voxels/Block.hpp"
|
#include "../voxels/Block.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
#include "../voxels/Chunks.hpp"
|
#include "../voxels/Chunks.hpp"
|
||||||
#include "../voxels/ChunksStorage.hpp"
|
#include "../voxels/ChunksStorage.hpp"
|
||||||
#include "../voxels/WorldGenerator.hpp"
|
#include "../voxels/WorldGenerator.hpp"
|
||||||
#include "../world/WorldGenerators.hpp"
|
|
||||||
#include "../graphics/core/Mesh.hpp"
|
|
||||||
#include "../lighting/Lighting.hpp"
|
|
||||||
#include "../files/WorldFiles.hpp"
|
|
||||||
#include "../world/Level.hpp"
|
#include "../world/Level.hpp"
|
||||||
#include "../world/World.hpp"
|
#include "../world/World.hpp"
|
||||||
#include "../maths/voxmaths.hpp"
|
#include "../world/WorldGenerators.hpp"
|
||||||
#include "../util/timeutil.hpp"
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
const uint MAX_WORK_PER_FRAME = 128;
|
const uint MAX_WORK_PER_FRAME = 128;
|
||||||
const uint MIN_SURROUNDING = 9;
|
const uint MIN_SURROUNDING = 9;
|
||||||
|
|
||||||
ChunksController::ChunksController(Level* level, uint padding)
|
ChunksController::ChunksController(Level* level, uint padding)
|
||||||
: level(level),
|
: level(level),
|
||||||
chunks(level->chunks.get()),
|
chunks(level->chunks.get()),
|
||||||
lighting(level->lighting.get()),
|
lighting(level->lighting.get()),
|
||||||
padding(padding),
|
padding(padding),
|
||||||
generator(WorldGenerators::createGenerator(level->getWorld()->getGenerator(), level->content)) {
|
generator(WorldGenerators::createGenerator(
|
||||||
|
level->getWorld()->getGenerator(), level->content
|
||||||
|
)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunksController::~ChunksController() = default;
|
ChunksController::~ChunksController() = default;
|
||||||
@ -48,18 +51,18 @@ void ChunksController::update(int64_t maxDuration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChunksController::loadVisible(){
|
bool ChunksController::loadVisible() {
|
||||||
const int w = chunks->w;
|
const int w = chunks->w;
|
||||||
const int d = chunks->d;
|
const int d = chunks->d;
|
||||||
|
|
||||||
int nearX = 0;
|
int nearX = 0;
|
||||||
int nearZ = 0;
|
int nearZ = 0;
|
||||||
int minDistance = ((w-padding*2)/2)*((w-padding*2)/2);
|
int minDistance = ((w - padding * 2) / 2) * ((w - padding * 2) / 2);
|
||||||
for (uint z = padding; z < d-padding; z++){
|
for (uint z = padding; z < d - padding; z++) {
|
||||||
for (uint x = padding; x < w-padding; x++){
|
for (uint x = padding; x < w - padding; x++) {
|
||||||
int index = z * w + x;
|
int index = z * w + x;
|
||||||
auto& chunk = chunks->chunks[index];
|
auto& chunk = chunks->chunks[index];
|
||||||
if (chunk != nullptr){
|
if (chunk != nullptr) {
|
||||||
if (chunk->flags.loaded && !chunk->flags.lighted) {
|
if (chunk->flags.loaded && !chunk->flags.lighted) {
|
||||||
if (buildLights(chunk)) {
|
if (buildLights(chunk)) {
|
||||||
return true;
|
return true;
|
||||||
@ -70,7 +73,7 @@ bool ChunksController::loadVisible(){
|
|||||||
int lx = x - w / 2;
|
int lx = x - w / 2;
|
||||||
int lz = z - d / 2;
|
int lz = z - d / 2;
|
||||||
int distance = (lx * lx + lz * lz);
|
int distance = (lx * lx + lz * lz);
|
||||||
if (distance < minDistance){
|
if (distance < minDistance) {
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
nearX = x;
|
nearX = x;
|
||||||
nearZ = z;
|
nearZ = z;
|
||||||
@ -85,16 +88,15 @@ bool ChunksController::loadVisible(){
|
|||||||
|
|
||||||
const int ox = chunks->ox;
|
const int ox = chunks->ox;
|
||||||
const int oz = chunks->oz;
|
const int oz = chunks->oz;
|
||||||
createChunk(nearX+ox, nearZ+oz);
|
createChunk(nearX + ox, nearZ + oz);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChunksController::buildLights(const std::shared_ptr<Chunk>& chunk) {
|
bool ChunksController::buildLights(const std::shared_ptr<Chunk>& chunk) {
|
||||||
int surrounding = 0;
|
int surrounding = 0;
|
||||||
for (int oz = -1; oz <= 1; oz++){
|
for (int oz = -1; oz <= 1; oz++) {
|
||||||
for (int ox = -1; ox <= 1; ox++){
|
for (int ox = -1; ox <= 1; ox++) {
|
||||||
if (chunks->getChunk(chunk->x+ox, chunk->z+oz))
|
if (chunks->getChunk(chunk->x + ox, chunk->z + oz)) surrounding++;
|
||||||
surrounding++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (surrounding == MIN_SURROUNDING) {
|
if (surrounding == MIN_SURROUNDING) {
|
||||||
@ -115,18 +117,13 @@ void ChunksController::createChunk(int x, int z) {
|
|||||||
auto& chunkFlags = chunk->flags;
|
auto& chunkFlags = chunk->flags;
|
||||||
|
|
||||||
if (!chunkFlags.loaded) {
|
if (!chunkFlags.loaded) {
|
||||||
generator->generate(
|
generator->generate(chunk->voxels, x, z, level->getWorld()->getSeed());
|
||||||
chunk->voxels, x, z,
|
|
||||||
level->getWorld()->getSeed()
|
|
||||||
);
|
|
||||||
chunkFlags.unsaved = true;
|
chunkFlags.unsaved = true;
|
||||||
}
|
}
|
||||||
chunk->updateHeights();
|
chunk->updateHeights();
|
||||||
|
|
||||||
if (!chunkFlags.loadedLights) {
|
if (!chunkFlags.loadedLights) {
|
||||||
Lighting::prebuildSkyLight(
|
Lighting::prebuildSkyLight(chunk.get(), level->content->getIndices());
|
||||||
chunk.get(), level->content->getIndices()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
chunkFlags.loaded = true;
|
chunkFlags.loaded = true;
|
||||||
chunkFlags.ready = true;
|
chunkFlags.ready = true;
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
#ifndef VOXELS_CHUNKSCONTROLLER_HPP_
|
#ifndef VOXELS_CHUNKSCONTROLLER_HPP_
|
||||||
#define VOXELS_CHUNKSCONTROLLER_HPP_
|
#define VOXELS_CHUNKSCONTROLLER_HPP_
|
||||||
|
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
class Chunk;
|
class Chunk;
|
||||||
class Chunks;
|
class Chunks;
|
||||||
@ -31,4 +32,4 @@ public:
|
|||||||
void update(int64_t maxDuration);
|
void update(int64_t maxDuration);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VOXELS_CHUNKSCONTROLLER_HPP_
|
#endif // VOXELS_CHUNKSCONTROLLER_HPP_
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#include "CommandsInterpreter.hpp"
|
#include "CommandsInterpreter.hpp"
|
||||||
|
|
||||||
#include "../coders/commons.hpp"
|
|
||||||
#include "../util/stringutil.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../coders/commons.hpp"
|
||||||
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
using namespace cmd;
|
using namespace cmd;
|
||||||
|
|
||||||
inline bool is_cmd_identifier_part(char c, bool allowColon) {
|
inline bool is_cmd_identifier_part(char c, bool allowColon) {
|
||||||
@ -31,7 +31,7 @@ class CommandParser : BasicParser {
|
|||||||
while (hasNext() && is_cmd_identifier_part(source[pos], allowColon)) {
|
while (hasNext() && is_cmd_identifier_part(source[pos], allowColon)) {
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
return std::string(source.substr(start, pos-start));
|
return std::string(source.substr(start, pos - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<std::string, ArgType> types {
|
std::unordered_map<std::string, ArgType> types {
|
||||||
@ -43,7 +43,7 @@ class CommandParser : BasicParser {
|
|||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
CommandParser(std::string_view filename, std::string_view source)
|
CommandParser(std::string_view filename, std::string_view source)
|
||||||
: BasicParser(filename, source) {
|
: BasicParser(filename, source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgType parseType() {
|
ArgType parseType() {
|
||||||
@ -55,7 +55,7 @@ public:
|
|||||||
if (found != types.end()) {
|
if (found != types.end()) {
|
||||||
return found->second;
|
return found->second;
|
||||||
} else {
|
} else {
|
||||||
throw error("unknown type "+util::quote(name));
|
throw error("unknown type " + util::quote(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ public:
|
|||||||
if (is_digit(c)) {
|
if (is_digit(c)) {
|
||||||
return parseNumber(1);
|
return parseNumber(1);
|
||||||
}
|
}
|
||||||
throw error("invalid character '"+std::string({c})+"'");
|
throw error("invalid character '" + std::string({c}) + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string parseEnum() {
|
std::string parseEnum() {
|
||||||
@ -92,10 +92,10 @@ public:
|
|||||||
if (peek() == ']') {
|
if (peek() == ']') {
|
||||||
throw error("empty enumeration is not allowed");
|
throw error("empty enumeration is not allowed");
|
||||||
}
|
}
|
||||||
auto enumvalue = "|"+std::string(readUntil(']'))+"|";
|
auto enumvalue = "|" + std::string(readUntil(']')) + "|";
|
||||||
size_t offset = enumvalue.find(' ');
|
size_t offset = enumvalue.find(' ');
|
||||||
if (offset != std::string::npos) {
|
if (offset != std::string::npos) {
|
||||||
goBack(enumvalue.length()-offset);
|
goBack(enumvalue.length() - offset);
|
||||||
throw error("use '|' as separator, not a space");
|
throw error("use '|' as separator, not a space");
|
||||||
}
|
}
|
||||||
nextChar();
|
nextChar();
|
||||||
@ -156,16 +156,18 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Command(
|
return Command(
|
||||||
name, std::move(args), std::move(kwargs),
|
name,
|
||||||
std::string(description), std::move(executor)
|
std::move(args),
|
||||||
|
std::move(kwargs),
|
||||||
|
std::string(description),
|
||||||
|
std::move(executor)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline parsing_error argumentError(
|
inline parsing_error argumentError(
|
||||||
const std::string& argname,
|
const std::string& argname, const std::string& message
|
||||||
const std::string& message
|
|
||||||
) {
|
) {
|
||||||
return error("argument "+util::quote(argname)+": "+message);
|
return error("argument " + util::quote(argname) + ": " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline parsing_error typeError(
|
inline parsing_error typeError(
|
||||||
@ -174,12 +176,14 @@ public:
|
|||||||
const dynamic::Value& value
|
const dynamic::Value& value
|
||||||
) {
|
) {
|
||||||
return argumentError(
|
return argumentError(
|
||||||
argname, expected+" expected, got "+dynamic::type_name(value)
|
argname, expected + " expected, got " + dynamic::type_name(value)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline bool typeCheck(Argument* arg, const dynamic::Value& value, const std::string& tname) {
|
inline bool typeCheck(
|
||||||
|
Argument* arg, const dynamic::Value& value, const std::string& tname
|
||||||
|
) {
|
||||||
if (!std::holds_alternative<T>(value)) {
|
if (!std::holds_alternative<T>(value)) {
|
||||||
if (arg->optional) {
|
if (arg->optional) {
|
||||||
return false;
|
return false;
|
||||||
@ -211,9 +215,12 @@ public:
|
|||||||
case ArgType::enumvalue: {
|
case ArgType::enumvalue: {
|
||||||
if (auto* string = std::get_if<std::string>(&value)) {
|
if (auto* string = std::get_if<std::string>(&value)) {
|
||||||
auto& enumname = arg->enumname;
|
auto& enumname = arg->enumname;
|
||||||
if (enumname.find("|"+*string+"|") == std::string::npos) {
|
if (enumname.find("|" + *string + "|") ==
|
||||||
throw error("argument "+util::quote(arg->name)+
|
std::string::npos) {
|
||||||
": invalid enumeration value");
|
throw error(
|
||||||
|
"argument " + util::quote(arg->name) +
|
||||||
|
": invalid enumeration value"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (arg->optional) {
|
if (arg->optional) {
|
||||||
@ -245,7 +252,9 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic::Value fetchOrigin(CommandsInterpreter* interpreter, Argument* arg) {
|
dynamic::Value fetchOrigin(
|
||||||
|
CommandsInterpreter* interpreter, Argument* arg
|
||||||
|
) {
|
||||||
if (dynamic::is_numeric(arg->origin)) {
|
if (dynamic::is_numeric(arg->origin)) {
|
||||||
return arg->origin;
|
return arg->origin;
|
||||||
} else if (auto string = std::get_if<std::string>(&arg->origin)) {
|
} else if (auto string = std::get_if<std::string>(&arg->origin)) {
|
||||||
@ -255,9 +264,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
dynamic::Value applyRelative(
|
dynamic::Value applyRelative(
|
||||||
Argument* arg,
|
Argument* arg, dynamic::Value value, const dynamic::Value& origin
|
||||||
dynamic::Value value,
|
|
||||||
const dynamic::Value& origin
|
|
||||||
) {
|
) {
|
||||||
if (origin.index() == 0) {
|
if (origin.index() == 0) {
|
||||||
return value;
|
return value;
|
||||||
@ -266,14 +273,17 @@ public:
|
|||||||
if (arg->type == ArgType::number) {
|
if (arg->type == ArgType::number) {
|
||||||
return dynamic::get_number(origin) + dynamic::get_number(value);
|
return dynamic::get_number(origin) + dynamic::get_number(value);
|
||||||
} else {
|
} else {
|
||||||
return dynamic::get_integer(origin) + dynamic::get_integer(value);
|
return dynamic::get_integer(origin) +
|
||||||
|
dynamic::get_integer(value);
|
||||||
}
|
}
|
||||||
} catch (std::runtime_error& err) {
|
} catch (std::runtime_error& err) {
|
||||||
throw argumentError(arg->name, err.what());
|
throw argumentError(arg->name, err.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic::Value parseRelativeValue(CommandsInterpreter* interpreter, Argument* arg) {
|
dynamic::Value parseRelativeValue(
|
||||||
|
CommandsInterpreter* interpreter, Argument* arg
|
||||||
|
) {
|
||||||
if (arg->type != ArgType::number && arg->type != ArgType::integer) {
|
if (arg->type != ArgType::number && arg->type != ArgType::integer) {
|
||||||
throw error("'~' operator is only allowed for numeric arguments");
|
throw error("'~' operator is only allowed for numeric arguments");
|
||||||
}
|
}
|
||||||
@ -290,17 +300,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline dynamic::Value performKeywordArg(
|
inline dynamic::Value performKeywordArg(
|
||||||
CommandsInterpreter* interpreter, Command* command, const std::string& key
|
CommandsInterpreter* interpreter,
|
||||||
|
Command* command,
|
||||||
|
const std::string& key
|
||||||
) {
|
) {
|
||||||
if (auto arg = command->getArgument(key)) {
|
if (auto arg = command->getArgument(key)) {
|
||||||
nextChar();
|
nextChar();
|
||||||
auto value = peek() == '~'
|
auto value = peek() == '~' ? parseRelativeValue(interpreter, arg)
|
||||||
? parseRelativeValue(interpreter, arg)
|
: parseValue();
|
||||||
: parseValue();
|
|
||||||
typeCheck(arg, value);
|
typeCheck(arg, value);
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
throw error("unknown keyword "+util::quote(key));
|
throw error("unknown keyword " + util::quote(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +320,7 @@ public:
|
|||||||
std::string name = parseIdentifier(true);
|
std::string name = parseIdentifier(true);
|
||||||
auto command = repo->get(name);
|
auto command = repo->get(name);
|
||||||
if (command == nullptr) {
|
if (command == nullptr) {
|
||||||
throw error("unknown command "+util::quote(name));
|
throw error("unknown command " + util::quote(name));
|
||||||
}
|
}
|
||||||
auto args = dynamic::create_list();
|
auto args = dynamic::create_list();
|
||||||
auto kwargs = dynamic::create_map();
|
auto kwargs = dynamic::create_map();
|
||||||
@ -336,7 +347,9 @@ public:
|
|||||||
// keyword argument
|
// keyword argument
|
||||||
if (!relative && hasNext() && peek() == '=') {
|
if (!relative && hasNext() && peek() == '=') {
|
||||||
auto key = std::get<std::string>(value);
|
auto key = std::get<std::string>(value);
|
||||||
kwargs->put(key, performKeywordArg(interpreter, command, key));
|
kwargs->put(
|
||||||
|
key, performKeywordArg(interpreter, command, key)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,14 +377,15 @@ public:
|
|||||||
} while (!typeCheck(arg, value));
|
} while (!typeCheck(arg, value));
|
||||||
|
|
||||||
if (relative) {
|
if (relative) {
|
||||||
value = applyRelative(arg, value, fetchOrigin(interpreter, arg));
|
value =
|
||||||
|
applyRelative(arg, value, fetchOrigin(interpreter, arg));
|
||||||
}
|
}
|
||||||
args->put(value);
|
args->put(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (auto arg = command->getArgument(arg_index++)) {
|
while (auto arg = command->getArgument(arg_index++)) {
|
||||||
if (!arg->optional) {
|
if (!arg->optional) {
|
||||||
throw error("missing argument "+util::quote(arg->name));
|
throw error("missing argument " + util::quote(arg->name));
|
||||||
} else {
|
} else {
|
||||||
if (auto string = std::get_if<std::string>(&arg->def)) {
|
if (auto string = std::get_if<std::string>(&arg->def)) {
|
||||||
if ((*string)[0] == '$') {
|
if ((*string)[0] == '$') {
|
||||||
@ -386,8 +400,13 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Command Command::create(std::string_view scheme, std::string_view description, executor_func executor) {
|
Command Command::create(
|
||||||
return CommandParser("<string>", scheme).parseScheme(std::move(executor), description);
|
std::string_view scheme,
|
||||||
|
std::string_view description,
|
||||||
|
executor_func executor
|
||||||
|
) {
|
||||||
|
return CommandParser("<string>", scheme)
|
||||||
|
.parseScheme(std::move(executor), description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandsRepository::add(
|
void CommandsRepository::add(
|
||||||
|
|||||||
@ -1,26 +1,30 @@
|
|||||||
#ifndef LOGIC_COMMANDS_INTERPRETER_HPP_
|
#ifndef LOGIC_COMMANDS_INTERPRETER_HPP_
|
||||||
#define LOGIC_COMMANDS_INTERPRETER_HPP_
|
#define LOGIC_COMMANDS_INTERPRETER_HPP_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace cmd {
|
namespace cmd {
|
||||||
enum class ArgType {
|
enum class ArgType { number, integer, enumvalue, selector, string };
|
||||||
number, integer, enumvalue, selector, string
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::string argtype_name(ArgType type) {
|
inline std::string argtype_name(ArgType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ArgType::number: return "number";
|
case ArgType::number:
|
||||||
case ArgType::integer: return "integer";
|
return "number";
|
||||||
case ArgType::enumvalue: return "enumeration";
|
case ArgType::integer:
|
||||||
case ArgType::selector: return "selector";
|
return "integer";
|
||||||
case ArgType::string: return "string";
|
case ArgType::enumvalue:
|
||||||
default: return "<unknown>";
|
return "enumeration";
|
||||||
|
case ArgType::selector:
|
||||||
|
return "selector";
|
||||||
|
case ArgType::string:
|
||||||
|
return "string";
|
||||||
|
default:
|
||||||
|
return "<unknown>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,14 +42,12 @@ namespace cmd {
|
|||||||
|
|
||||||
struct Prompt {
|
struct Prompt {
|
||||||
Command* command;
|
Command* command;
|
||||||
dynamic::List_sptr args; // positional arguments list
|
dynamic::List_sptr args; // positional arguments list
|
||||||
dynamic::Map_sptr kwargs; // keyword arguments table
|
dynamic::Map_sptr kwargs; // keyword arguments table
|
||||||
};
|
};
|
||||||
|
|
||||||
using executor_func = std::function<dynamic::Value(
|
using executor_func = std::function<dynamic::Value(
|
||||||
CommandsInterpreter*,
|
CommandsInterpreter*, dynamic::List_sptr args, dynamic::Map_sptr kwargs
|
||||||
dynamic::List_sptr args,
|
|
||||||
dynamic::Map_sptr kwargs
|
|
||||||
)>;
|
)>;
|
||||||
|
|
||||||
class Command {
|
class Command {
|
||||||
@ -63,15 +65,16 @@ namespace cmd {
|
|||||||
std::unordered_map<std::string, Argument> kwargs,
|
std::unordered_map<std::string, Argument> kwargs,
|
||||||
std::string description,
|
std::string description,
|
||||||
executor_func executor
|
executor_func executor
|
||||||
) : name(name),
|
)
|
||||||
args(std::move(args)),
|
: name(name),
|
||||||
kwargs(std::move(kwargs)),
|
args(std::move(args)),
|
||||||
description(description),
|
kwargs(std::move(kwargs)),
|
||||||
executor(executor) {}
|
description(description),
|
||||||
|
executor(executor) {
|
||||||
|
}
|
||||||
|
|
||||||
Argument* getArgument(size_t index) {
|
Argument* getArgument(size_t index) {
|
||||||
if (index >= args.size())
|
if (index >= args.size()) return nullptr;
|
||||||
return nullptr;
|
|
||||||
return &args[index];
|
return &args[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +86,9 @@ namespace cmd {
|
|||||||
return &found->second;
|
return &found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic::Value execute(CommandsInterpreter* interpreter, const Prompt& prompt) {
|
dynamic::Value execute(
|
||||||
|
CommandsInterpreter* interpreter, const Prompt& prompt
|
||||||
|
) {
|
||||||
return executor(interpreter, prompt.args, prompt.kwargs);
|
return executor(interpreter, prompt.args, prompt.kwargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,9 +109,7 @@ namespace cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Command create(
|
static Command create(
|
||||||
std::string_view scheme,
|
std::string_view scheme, std::string_view description, executor_func
|
||||||
std::string_view description,
|
|
||||||
executor_func
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,9 +117,7 @@ namespace cmd {
|
|||||||
std::unordered_map<std::string, Command> commands;
|
std::unordered_map<std::string, Command> commands;
|
||||||
public:
|
public:
|
||||||
void add(
|
void add(
|
||||||
std::string_view scheme,
|
std::string_view scheme, std::string_view description, executor_func
|
||||||
std::string_view description,
|
|
||||||
executor_func
|
|
||||||
);
|
);
|
||||||
Command* get(const std::string& name);
|
Command* get(const std::string& name);
|
||||||
|
|
||||||
@ -129,12 +130,15 @@ namespace cmd {
|
|||||||
std::unique_ptr<CommandsRepository> repository;
|
std::unique_ptr<CommandsRepository> repository;
|
||||||
std::unordered_map<std::string, dynamic::Value> variables;
|
std::unordered_map<std::string, dynamic::Value> variables;
|
||||||
public:
|
public:
|
||||||
CommandsInterpreter() : repository(std::make_unique<CommandsRepository>()) {}
|
CommandsInterpreter()
|
||||||
|
: repository(std::make_unique<CommandsRepository>()) {
|
||||||
|
}
|
||||||
|
|
||||||
CommandsInterpreter(const CommandsInterpreter&) = delete;
|
CommandsInterpreter(const CommandsInterpreter&) = delete;
|
||||||
|
|
||||||
CommandsInterpreter(std::unique_ptr<CommandsRepository> repository)
|
CommandsInterpreter(std::unique_ptr<CommandsRepository> repository)
|
||||||
: repository(std::move(repository)){}
|
: repository(std::move(repository)) {
|
||||||
|
}
|
||||||
|
|
||||||
Prompt parse(std::string_view text);
|
Prompt parse(std::string_view text);
|
||||||
|
|
||||||
@ -156,4 +160,4 @@ namespace cmd {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LOGIC_COMMANDS_INTERPRETER_HPP_
|
#endif // LOGIC_COMMANDS_INTERPRETER_HPP_
|
||||||
|
|||||||
@ -1,27 +1,27 @@
|
|||||||
#include "EngineController.hpp"
|
#include "EngineController.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "../coders/commons.hpp"
|
#include "../coders/commons.hpp"
|
||||||
#include "../content/ContentLUT.hpp"
|
#include "../content/ContentLUT.hpp"
|
||||||
#include "../debug/Logger.hpp"
|
#include "../debug/Logger.hpp"
|
||||||
#include "../engine.hpp"
|
#include "../engine.hpp"
|
||||||
#include "../files/WorldFiles.hpp"
|
|
||||||
#include "../files/WorldConverter.hpp"
|
#include "../files/WorldConverter.hpp"
|
||||||
|
#include "../files/WorldFiles.hpp"
|
||||||
#include "../frontend/locale.hpp"
|
#include "../frontend/locale.hpp"
|
||||||
#include "../frontend/screens/MenuScreen.hpp"
|
|
||||||
#include "../frontend/screens/LevelScreen.hpp"
|
|
||||||
#include "../frontend/menu.hpp"
|
#include "../frontend/menu.hpp"
|
||||||
|
#include "../frontend/screens/LevelScreen.hpp"
|
||||||
|
#include "../frontend/screens/MenuScreen.hpp"
|
||||||
#include "../graphics/ui/elements/Menu.hpp"
|
#include "../graphics/ui/elements/Menu.hpp"
|
||||||
#include "../graphics/ui/gui_util.hpp"
|
#include "../graphics/ui/gui_util.hpp"
|
||||||
#include "../interfaces/Task.hpp"
|
#include "../interfaces/Task.hpp"
|
||||||
#include "../util/stringutil.hpp"
|
#include "../util/stringutil.hpp"
|
||||||
#include "../world/World.hpp"
|
|
||||||
#include "../world/Level.hpp"
|
#include "../world/Level.hpp"
|
||||||
|
#include "../world/World.hpp"
|
||||||
#include "LevelController.hpp"
|
#include "LevelController.hpp"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
static debug::Logger logger("engine-control");
|
static debug::Logger logger("engine-control");
|
||||||
@ -31,11 +31,15 @@ EngineController::EngineController(Engine* engine) : engine(engine) {
|
|||||||
|
|
||||||
void EngineController::deleteWorld(const std::string& name) {
|
void EngineController::deleteWorld(const std::string& name) {
|
||||||
fs::path folder = engine->getPaths()->getWorldFolder(name);
|
fs::path folder = engine->getPaths()->getWorldFolder(name);
|
||||||
guiutil::confirm(engine->getGUI(), langs::get(L"delete-confirm", L"world")+
|
guiutil::confirm(
|
||||||
L" ("+util::str2wstr_utf8(folder.u8string())+L")", [=]() {
|
engine->getGUI(),
|
||||||
logger.info() << "deleting " << folder.u8string();
|
langs::get(L"delete-confirm", L"world") + L" (" +
|
||||||
fs::remove_all(folder);
|
util::str2wstr_utf8(folder.u8string()) + L")",
|
||||||
});
|
[=]() {
|
||||||
|
logger.info() << "deleting " << folder.u8string();
|
||||||
|
fs::remove_all(folder);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Task> create_converter(
|
std::shared_ptr<Task> create_converter(
|
||||||
@ -43,16 +47,20 @@ std::shared_ptr<Task> create_converter(
|
|||||||
const fs::path& folder,
|
const fs::path& folder,
|
||||||
const Content* content,
|
const Content* content,
|
||||||
const std::shared_ptr<ContentLUT>& lut,
|
const std::shared_ptr<ContentLUT>& lut,
|
||||||
const runnable& postRunnable)
|
const runnable& postRunnable
|
||||||
{
|
) {
|
||||||
return WorldConverter::startTask(folder, content, lut, [=](){
|
return WorldConverter::startTask(
|
||||||
auto menu = engine->getGUI()->getMenu();
|
folder,
|
||||||
menu->reset();
|
content,
|
||||||
menu->setPage("main", false);
|
lut,
|
||||||
engine->getGUI()->postRunnable([=]() {
|
[=]() {
|
||||||
postRunnable();
|
auto menu = engine->getGUI()->getMenu();
|
||||||
});
|
menu->reset();
|
||||||
}, true);
|
menu->setPage("main", false);
|
||||||
|
engine->getGUI()->postRunnable([=]() { postRunnable(); });
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_convert_request(
|
void show_convert_request(
|
||||||
@ -62,15 +70,23 @@ void show_convert_request(
|
|||||||
const fs::path& folder,
|
const fs::path& folder,
|
||||||
const runnable& postRunnable
|
const runnable& postRunnable
|
||||||
) {
|
) {
|
||||||
guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"), [=]() {
|
guiutil::confirm(
|
||||||
auto converter = create_converter(engine, folder, content, lut, postRunnable);
|
engine->getGUI(),
|
||||||
menus::show_process_panel(engine, converter, L"Converting world...");
|
langs::get(L"world.convert-request"),
|
||||||
}, L"", langs::get(L"Cancel"));
|
[=]() {
|
||||||
|
auto converter =
|
||||||
|
create_converter(engine, folder, content, lut, postRunnable);
|
||||||
|
menus::show_process_panel(
|
||||||
|
engine, converter, L"Converting world..."
|
||||||
|
);
|
||||||
|
},
|
||||||
|
L"",
|
||||||
|
langs::get(L"Cancel")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_content_missing(
|
static void show_content_missing(
|
||||||
Engine* engine,
|
Engine* engine, const std::shared_ptr<ContentLUT>& lut
|
||||||
const std::shared_ptr<ContentLUT>& lut
|
|
||||||
) {
|
) {
|
||||||
using namespace dynamic;
|
using namespace dynamic;
|
||||||
auto root = create_map();
|
auto root = create_map();
|
||||||
@ -97,11 +113,13 @@ static void loadWorld(Engine* engine, const fs::path& folder) {
|
|||||||
auto& settings = engine->getSettings();
|
auto& settings = engine->getSettings();
|
||||||
|
|
||||||
auto level = World::load(folder, settings, content, packs);
|
auto level = World::load(folder, settings, content, packs);
|
||||||
engine->setScreen(std::make_shared<LevelScreen>(engine, std::move(level)));
|
engine->setScreen(
|
||||||
|
std::make_shared<LevelScreen>(engine, std::move(level))
|
||||||
|
);
|
||||||
} catch (const world_load_error& error) {
|
} catch (const world_load_error& error) {
|
||||||
guiutil::alert(
|
guiutil::alert(
|
||||||
engine->getGUI(), langs::get(L"Error")+L": "+
|
engine->getGUI(),
|
||||||
util::str2wstr_utf8(error.what())
|
langs::get(L"Error") + L": " + util::str2wstr_utf8(error.what())
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -109,25 +127,33 @@ static void loadWorld(Engine* engine, const fs::path& folder) {
|
|||||||
|
|
||||||
void EngineController::openWorld(const std::string& name, bool confirmConvert) {
|
void EngineController::openWorld(const std::string& name, bool confirmConvert) {
|
||||||
auto paths = engine->getPaths();
|
auto paths = engine->getPaths();
|
||||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
auto folder = paths->getWorldsFolder() / fs::u8path(name);
|
||||||
if (!loadWorldContent(engine, folder)) {
|
if (!loadWorldContent(engine, folder)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* content = engine->getContent();
|
auto* content = engine->getContent();
|
||||||
|
|
||||||
std::shared_ptr<ContentLUT> lut (World::checkIndices(folder, content));
|
std::shared_ptr<ContentLUT> lut(World::checkIndices(folder, content));
|
||||||
if (lut) {
|
if (lut) {
|
||||||
if (lut->hasMissingContent()) {
|
if (lut->hasMissingContent()) {
|
||||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||||
show_content_missing(engine, lut);
|
show_content_missing(engine, lut);
|
||||||
} else {
|
} else {
|
||||||
if (confirmConvert) {
|
if (confirmConvert) {
|
||||||
menus::show_process_panel(engine, create_converter(engine, folder, content, lut, [=]() {
|
menus::show_process_panel(
|
||||||
openWorld(name, false);
|
engine,
|
||||||
}), L"Converting world...");
|
create_converter(
|
||||||
|
engine,
|
||||||
|
folder,
|
||||||
|
content,
|
||||||
|
lut,
|
||||||
|
[=]() { openWorld(name, false); }
|
||||||
|
),
|
||||||
|
L"Converting world..."
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
show_convert_request(engine, content, lut, folder, [=](){
|
show_convert_request(engine, content, lut, folder, [=]() {
|
||||||
openWorld(name, false);
|
openWorld(name, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -159,16 +185,19 @@ void EngineController::createWorld(
|
|||||||
uint64_t seed = str2seed(seedstr);
|
uint64_t seed = str2seed(seedstr);
|
||||||
|
|
||||||
EnginePaths* paths = engine->getPaths();
|
EnginePaths* paths = engine->getPaths();
|
||||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
auto folder = paths->getWorldsFolder() / fs::u8path(name);
|
||||||
|
|
||||||
if (!menus::call(engine, [this, paths, folder]() {
|
if (!menus::call(engine, [this, paths, folder]() {
|
||||||
engine->loadContent();
|
engine->loadContent();
|
||||||
paths->setWorldFolder(folder);
|
paths->setWorldFolder(folder);
|
||||||
})) {
|
})) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto level = World::create(
|
auto level = World::create(
|
||||||
name, generatorID, folder, seed,
|
name,
|
||||||
|
generatorID,
|
||||||
|
folder,
|
||||||
|
seed,
|
||||||
engine->getSettings(),
|
engine->getSettings(),
|
||||||
engine->getContent(),
|
engine->getContent(),
|
||||||
engine->getContentPacks()
|
engine->getContentPacks()
|
||||||
@ -208,7 +237,8 @@ void EngineController::reconfigPacks(
|
|||||||
try {
|
try {
|
||||||
auto manager = engine->createPacksManager(fs::path(""));
|
auto manager = engine->createPacksManager(fs::path(""));
|
||||||
manager.scan();
|
manager.scan();
|
||||||
std::vector<std::string> names = PacksManager::getNames(engine->getContentPacks());
|
std::vector<std::string> names =
|
||||||
|
PacksManager::getNames(engine->getContentPacks());
|
||||||
for (const auto& id : packsToAdd) {
|
for (const auto& id : packsToAdd) {
|
||||||
names.push_back(id);
|
names.push_back(id);
|
||||||
}
|
}
|
||||||
@ -219,7 +249,9 @@ void EngineController::reconfigPacks(
|
|||||||
names = manager.assembly(names);
|
names = manager.assembly(names);
|
||||||
engine->getContentPacks() = manager.getAll(names);
|
engine->getContentPacks() = manager.getAll(names);
|
||||||
} catch (const contentpack_error& err) {
|
} catch (const contentpack_error& err) {
|
||||||
throw std::runtime_error(std::string(err.what())+" ["+err.getPackId()+"]");
|
throw std::runtime_error(
|
||||||
|
std::string(err.what()) + " [" + err.getPackId() + "]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto world = controller->getLevel()->getWorld();
|
auto world = controller->getLevel()->getWorld();
|
||||||
@ -245,9 +277,9 @@ void EngineController::reconfigPacks(
|
|||||||
if (hasIndices) {
|
if (hasIndices) {
|
||||||
guiutil::confirm(
|
guiutil::confirm(
|
||||||
engine->getGUI(),
|
engine->getGUI(),
|
||||||
langs::get(L"remove-confirm", L"pack")+
|
langs::get(L"remove-confirm", L"pack") + L" (" +
|
||||||
L" ("+util::str2wstr_utf8(ss.str())+L")",
|
util::str2wstr_utf8(ss.str()) + L")",
|
||||||
[=]() {removeFunc();}
|
[=]() { removeFunc(); }
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
removeFunc();
|
removeFunc();
|
||||||
|
|||||||
@ -37,4 +37,4 @@ public:
|
|||||||
void reopenWorld(World* world);
|
void reopenWorld(World* world);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOGIC_ENGINE_CONTROLLER_HPP_
|
#endif // LOGIC_ENGINE_CONTROLLER_HPP_
|
||||||
|
|||||||
@ -1,34 +1,43 @@
|
|||||||
#include "LevelController.hpp"
|
#include "LevelController.hpp"
|
||||||
|
|
||||||
#include "../settings.hpp"
|
|
||||||
#include "../files/WorldFiles.hpp"
|
|
||||||
#include "../debug/Logger.hpp"
|
|
||||||
#include "../world/Level.hpp"
|
|
||||||
#include "../world/World.hpp"
|
|
||||||
#include "../physics/Hitbox.hpp"
|
|
||||||
#include "../objects/Entities.hpp"
|
|
||||||
|
|
||||||
#include "scripting/scripting.hpp"
|
|
||||||
#include "../interfaces/Object.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "../debug/Logger.hpp"
|
||||||
|
#include "../files/WorldFiles.hpp"
|
||||||
|
#include "../interfaces/Object.hpp"
|
||||||
|
#include "../objects/Entities.hpp"
|
||||||
|
#include "../physics/Hitbox.hpp"
|
||||||
|
#include "../settings.hpp"
|
||||||
|
#include "../world/Level.hpp"
|
||||||
|
#include "../world/World.hpp"
|
||||||
|
#include "scripting/scripting.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("level-control");
|
static debug::Logger logger("level-control");
|
||||||
|
|
||||||
LevelController::LevelController(EngineSettings& settings, std::unique_ptr<Level> level)
|
LevelController::LevelController(
|
||||||
: settings(settings), level(std::move(level)),
|
EngineSettings& settings, std::unique_ptr<Level> level
|
||||||
blocks(std::make_unique<BlocksController>(this->level.get(), settings.chunks.padding.get())),
|
)
|
||||||
chunks(std::make_unique<ChunksController>(this->level.get(), settings.chunks.padding.get())),
|
: settings(settings),
|
||||||
player(std::make_unique<PlayerController>(this->level.get(), settings, blocks.get())) {
|
level(std::move(level)),
|
||||||
|
blocks(std::make_unique<BlocksController>(
|
||||||
|
this->level.get(), settings.chunks.padding.get()
|
||||||
|
)),
|
||||||
|
chunks(std::make_unique<ChunksController>(
|
||||||
|
this->level.get(), settings.chunks.padding.get()
|
||||||
|
)),
|
||||||
|
player(std::make_unique<PlayerController>(
|
||||||
|
this->level.get(), settings, blocks.get()
|
||||||
|
)) {
|
||||||
scripting::on_world_load(this);
|
scripting::on_world_load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelController::update(float delta, bool input, bool pause) {
|
void LevelController::update(float delta, bool input, bool pause) {
|
||||||
glm::vec3 position = player->getPlayer()->getPosition();
|
glm::vec3 position = player->getPlayer()->getPosition();
|
||||||
level->loadMatrix(position.x, position.z,
|
level->loadMatrix(
|
||||||
settings.chunks.loadDistance.get() +
|
position.x,
|
||||||
settings.chunks.padding.get() * 2);
|
position.z,
|
||||||
|
settings.chunks.loadDistance.get() + settings.chunks.padding.get() * 2
|
||||||
|
);
|
||||||
chunks->update(settings.chunks.loadSpeed.get());
|
chunks->update(settings.chunks.loadSpeed.get());
|
||||||
|
|
||||||
if (!pause) {
|
if (!pause) {
|
||||||
@ -50,8 +59,10 @@ void LevelController::update(float delta, bool input, bool pause) {
|
|||||||
auto& objects = level->objects;
|
auto& objects = level->objects;
|
||||||
objects.erase(
|
objects.erase(
|
||||||
std::remove_if(
|
std::remove_if(
|
||||||
objects.begin(), objects.end(),
|
objects.begin(),
|
||||||
[](auto obj) { return obj == nullptr; }),
|
objects.end(),
|
||||||
|
[](auto obj) { return obj == nullptr; }
|
||||||
|
),
|
||||||
objects.end()
|
objects.end()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "PlayerController.hpp"
|
|
||||||
#include "BlocksController.hpp"
|
#include "BlocksController.hpp"
|
||||||
#include "ChunksController.hpp"
|
#include "ChunksController.hpp"
|
||||||
|
#include "PlayerController.hpp"
|
||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
class Player;
|
class Player;
|
||||||
@ -25,11 +25,7 @@ public:
|
|||||||
/// @param delta time elapsed since the last update
|
/// @param delta time elapsed since the last update
|
||||||
/// @param input is user input allowed to be handled
|
/// @param input is user input allowed to be handled
|
||||||
/// @param pause is world and player simulation paused
|
/// @param pause is world and player simulation paused
|
||||||
void update(
|
void update(float delta, bool input, bool pause);
|
||||||
float delta,
|
|
||||||
bool input,
|
|
||||||
bool pause
|
|
||||||
);
|
|
||||||
|
|
||||||
void saveWorld();
|
void saveWorld();
|
||||||
|
|
||||||
@ -42,4 +38,4 @@ public:
|
|||||||
PlayerController* getPlayerController();
|
PlayerController* getPlayerController();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOGIC_LEVEL_CONTROLLER_HPP_
|
#endif // LOGIC_LEVEL_CONTROLLER_HPP_
|
||||||
|
|||||||
@ -1,31 +1,30 @@
|
|||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "PlayerController.hpp"
|
#include "PlayerController.hpp"
|
||||||
#include "BlocksController.hpp"
|
|
||||||
#include "scripting/scripting.hpp"
|
|
||||||
|
|
||||||
#include "../objects/Player.hpp"
|
|
||||||
#include "../objects/Entities.hpp"
|
|
||||||
#include "../physics/PhysicsSolver.hpp"
|
|
||||||
#include "../physics/Hitbox.hpp"
|
|
||||||
#include "../lighting/Lighting.hpp"
|
|
||||||
#include "../world/Level.hpp"
|
|
||||||
#include "../content/Content.hpp"
|
|
||||||
#include "../voxels/Block.hpp"
|
|
||||||
#include "../voxels/voxel.hpp"
|
|
||||||
#include "../voxels/Chunks.hpp"
|
|
||||||
#include "../window/Camera.hpp"
|
|
||||||
#include "../window/Window.hpp"
|
|
||||||
#include "../window/Events.hpp"
|
|
||||||
#include "../window/input.hpp"
|
|
||||||
#include "../items/ItemDef.hpp"
|
|
||||||
#include "../items/ItemStack.hpp"
|
|
||||||
#include "../items/Inventory.hpp"
|
|
||||||
#include "../core_defs.hpp"
|
|
||||||
#include "../settings.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "../content/Content.hpp"
|
||||||
|
#include "../core_defs.hpp"
|
||||||
|
#include "../items/Inventory.hpp"
|
||||||
|
#include "../items/ItemDef.hpp"
|
||||||
|
#include "../items/ItemStack.hpp"
|
||||||
|
#include "../lighting/Lighting.hpp"
|
||||||
|
#include "../objects/Entities.hpp"
|
||||||
|
#include "../objects/Player.hpp"
|
||||||
|
#include "../physics/Hitbox.hpp"
|
||||||
|
#include "../physics/PhysicsSolver.hpp"
|
||||||
|
#include "../settings.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
|
#include "../voxels/Chunks.hpp"
|
||||||
|
#include "../voxels/voxel.hpp"
|
||||||
|
#include "../window/Camera.hpp"
|
||||||
|
#include "../window/Events.hpp"
|
||||||
|
#include "../window/Window.hpp"
|
||||||
|
#include "../window/input.hpp"
|
||||||
|
#include "../world/Level.hpp"
|
||||||
|
#include "BlocksController.hpp"
|
||||||
|
#include "scripting/scripting.hpp"
|
||||||
|
|
||||||
const float STEPS_SPEED = 2.2f;
|
const float STEPS_SPEED = 2.2f;
|
||||||
const float CAM_SHAKE_OFFSET = 0.0075f;
|
const float CAM_SHAKE_OFFSET = 0.0075f;
|
||||||
@ -38,11 +37,13 @@ const float RUN_ZOOM = 1.1f;
|
|||||||
const float C_ZOOM = 0.1f;
|
const float C_ZOOM = 0.1f;
|
||||||
const float CROUCH_SHIFT_Y = -0.2f;
|
const float CROUCH_SHIFT_Y = -0.2f;
|
||||||
|
|
||||||
CameraControl::CameraControl(const std::shared_ptr<Player>& player, const CameraSettings& settings)
|
CameraControl::CameraControl(
|
||||||
: player(player),
|
const std::shared_ptr<Player>& player, const CameraSettings& settings
|
||||||
camera(player->camera),
|
)
|
||||||
settings(settings),
|
: player(player),
|
||||||
offset(0.0f, 0.7f, 0.0f) {
|
camera(player->camera),
|
||||||
|
settings(settings),
|
||||||
|
offset(0.0f, 0.7f, 0.0f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraControl::refresh() {
|
void CameraControl::refresh() {
|
||||||
@ -52,9 +53,9 @@ void CameraControl::refresh() {
|
|||||||
void CameraControl::updateMouse(PlayerInput& input) {
|
void CameraControl::updateMouse(PlayerInput& input) {
|
||||||
glm::vec3& cam = player->cam;
|
glm::vec3& cam = player->cam;
|
||||||
|
|
||||||
float sensitivity = (input.zoom
|
float sensitivity =
|
||||||
? settings.sensitivity.get() / 4.f
|
(input.zoom ? settings.sensitivity.get() / 4.f
|
||||||
: settings.sensitivity.get());
|
: settings.sensitivity.get());
|
||||||
|
|
||||||
auto d = glm::degrees(Events::delta / (float)Window::height * sensitivity);
|
auto d = glm::degrees(Events::delta / (float)Window::height * sensitivity);
|
||||||
cam.x -= d.x;
|
cam.x -= d.x;
|
||||||
@ -62,29 +63,31 @@ void CameraControl::updateMouse(PlayerInput& input) {
|
|||||||
|
|
||||||
if (cam.y < -89.9f) {
|
if (cam.y < -89.9f) {
|
||||||
cam.y = -89.9f;
|
cam.y = -89.9f;
|
||||||
}
|
} else if (cam.y > 89.9f) {
|
||||||
else if (cam.y > 89.9f) {
|
|
||||||
cam.y = 89.9f;
|
cam.y = 89.9f;
|
||||||
}
|
}
|
||||||
if (cam.x > 180.f) {
|
if (cam.x > 180.f) {
|
||||||
cam.x -= 360.f;
|
cam.x -= 360.f;
|
||||||
}
|
} else if (cam.x < -180.f) {
|
||||||
else if (cam.x < -180.f) {
|
|
||||||
cam.x += 360.f;
|
cam.x += 360.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
camera->rotation = glm::mat4(1.0f);
|
camera->rotation = glm::mat4(1.0f);
|
||||||
camera->rotate(glm::radians(cam.y), glm::radians(cam.x), glm::radians(cam.z));
|
camera->rotate(
|
||||||
|
glm::radians(cam.y), glm::radians(cam.x), glm::radians(cam.z)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 CameraControl::updateCameraShaking(const Hitbox& hitbox, float delta) {
|
glm::vec3 CameraControl::updateCameraShaking(
|
||||||
|
const Hitbox& hitbox, float delta
|
||||||
|
) {
|
||||||
glm::vec3 offset {};
|
glm::vec3 offset {};
|
||||||
const float k = CAM_SHAKE_DELTA_K;
|
const float k = CAM_SHAKE_DELTA_K;
|
||||||
const float ov = CAM_SHAKE_OFFSET_Y;
|
const float ov = CAM_SHAKE_OFFSET_Y;
|
||||||
const glm::vec3& vel = hitbox.velocity;
|
const glm::vec3& vel = hitbox.velocity;
|
||||||
|
|
||||||
interpVel = interpVel * (1.0f - delta * 5) + vel * delta * 0.1f;
|
interpVel = interpVel * (1.0f - delta * 5) + vel * delta * 0.1f;
|
||||||
if (hitbox.grounded && interpVel.y < 0.0f){
|
if (hitbox.grounded && interpVel.y < 0.0f) {
|
||||||
interpVel.y *= -30.0f;
|
interpVel.y *= -30.0f;
|
||||||
}
|
}
|
||||||
shake = shake * (1.0f - delta * k);
|
shake = shake * (1.0f - delta * k);
|
||||||
@ -104,20 +107,20 @@ glm::vec3 CameraControl::updateCameraShaking(const Hitbox& hitbox, float delta)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraControl::updateFovEffects(const Hitbox& hitbox,
|
void CameraControl::updateFovEffects(
|
||||||
PlayerInput input, float delta) {
|
const Hitbox& hitbox, PlayerInput input, float delta
|
||||||
|
) {
|
||||||
bool crouch = input.shift && hitbox.grounded && !input.sprint;
|
bool crouch = input.shift && hitbox.grounded && !input.sprint;
|
||||||
|
|
||||||
float dt = fmin(1.0f, delta * ZOOM_SPEED);
|
float dt = fmin(1.0f, delta * ZOOM_SPEED);
|
||||||
float zoomValue = 1.0f;
|
float zoomValue = 1.0f;
|
||||||
if (crouch){
|
if (crouch) {
|
||||||
offset += glm::vec3(0.f, CROUCH_SHIFT_Y, 0.f);
|
offset += glm::vec3(0.f, CROUCH_SHIFT_Y, 0.f);
|
||||||
zoomValue = CROUCH_ZOOM;
|
zoomValue = CROUCH_ZOOM;
|
||||||
} else if (input.sprint){
|
} else if (input.sprint) {
|
||||||
zoomValue = RUN_ZOOM;
|
zoomValue = RUN_ZOOM;
|
||||||
}
|
}
|
||||||
if (input.zoom)
|
if (input.zoom) zoomValue *= C_ZOOM;
|
||||||
zoomValue *= C_ZOOM;
|
|
||||||
camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt);
|
camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,17 +128,14 @@ void CameraControl::updateFovEffects(const Hitbox& hitbox,
|
|||||||
// more extensible but uglier
|
// more extensible but uglier
|
||||||
void CameraControl::switchCamera() {
|
void CameraControl::switchCamera() {
|
||||||
const std::vector<std::shared_ptr<Camera>> playerCameras {
|
const std::vector<std::shared_ptr<Camera>> playerCameras {
|
||||||
camera, player->tpCamera, player->spCamera
|
camera, player->tpCamera, player->spCamera};
|
||||||
};
|
|
||||||
|
|
||||||
auto index = std::distance(
|
auto index = std::distance(
|
||||||
playerCameras.begin(),
|
playerCameras.begin(),
|
||||||
std::find_if(
|
std::find_if(
|
||||||
playerCameras.begin(),
|
playerCameras.begin(),
|
||||||
playerCameras.end(),
|
playerCameras.end(),
|
||||||
[=](auto ptr) {
|
[=](auto ptr) { return ptr.get() == player->currentCamera.get(); }
|
||||||
return ptr.get() == player->currentCamera.get();
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (static_cast<size_t>(index) != playerCameras.size()) {
|
if (static_cast<size_t>(index) != playerCameras.size()) {
|
||||||
@ -150,11 +150,11 @@ void CameraControl::update(PlayerInput input, float delta, Chunks* chunks) {
|
|||||||
offset = glm::vec3(0.0f, 0.0f, 0.0f);
|
offset = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
if (auto hitbox = player->getHitbox()) {
|
if (auto hitbox = player->getHitbox()) {
|
||||||
offset.y += hitbox->halfsize.y * (0.7f/0.9f);
|
offset.y += hitbox->halfsize.y * (0.7f / 0.9f);
|
||||||
if (settings.shaking.get() && !input.cheat) {
|
if (settings.shaking.get() && !input.cheat) {
|
||||||
offset += updateCameraShaking(*hitbox, delta);
|
offset += updateCameraShaking(*hitbox, delta);
|
||||||
}
|
}
|
||||||
if (settings.fovEffects.get()){
|
if (settings.fovEffects.get()) {
|
||||||
updateFovEffects(*hitbox, input, delta);
|
updateFovEffects(*hitbox, input, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,20 +168,20 @@ void CameraControl::update(PlayerInput input, float delta, Chunks* chunks) {
|
|||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
if (player->currentCamera == spCamera) {
|
if (player->currentCamera == spCamera) {
|
||||||
spCamera->position = chunks->rayCastToObstacle(
|
spCamera->position =
|
||||||
camera->position, camera->front, 3.0f) - 0.4f * camera->front;
|
chunks->rayCastToObstacle(camera->position, camera->front, 3.0f) -
|
||||||
|
0.4f * camera->front;
|
||||||
spCamera->dir = -camera->dir;
|
spCamera->dir = -camera->dir;
|
||||||
spCamera->front = -camera->front;
|
spCamera->front = -camera->front;
|
||||||
}
|
} else if (player->currentCamera == tpCamera) {
|
||||||
else if (player->currentCamera == tpCamera) {
|
tpCamera->position =
|
||||||
tpCamera->position = chunks->rayCastToObstacle(
|
chunks->rayCastToObstacle(camera->position, -camera->front, 3.0f) +
|
||||||
camera->position, -camera->front, 3.0f) + 0.4f * camera->front;
|
0.4f * camera->front;
|
||||||
tpCamera->dir = camera->dir;
|
tpCamera->dir = camera->dir;
|
||||||
tpCamera->front = camera->front;
|
tpCamera->front = camera->front;
|
||||||
}
|
}
|
||||||
if (player->currentCamera == spCamera ||
|
if (player->currentCamera == spCamera ||
|
||||||
player->currentCamera == tpCamera ||
|
player->currentCamera == tpCamera || player->currentCamera == camera) {
|
||||||
player->currentCamera == camera) {
|
|
||||||
player->currentCamera->setFov(glm::radians(settings.fov.get()));
|
player->currentCamera->setFov(glm::radians(settings.fov.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,12 +190,12 @@ PlayerController::PlayerController(
|
|||||||
Level* level,
|
Level* level,
|
||||||
const EngineSettings& settings,
|
const EngineSettings& settings,
|
||||||
BlocksController* blocksController
|
BlocksController* blocksController
|
||||||
) : level(level),
|
)
|
||||||
player(level->getObject<Player>(0)),
|
: level(level),
|
||||||
camControl(player, settings.camera),
|
player(level->getObject<Player>(0)),
|
||||||
blocksController(blocksController)
|
camControl(player, settings.camera),
|
||||||
{}
|
blocksController(blocksController) {
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerController::onFootstep(const Hitbox& hitbox) {
|
void PlayerController::onFootstep(const Hitbox& hitbox) {
|
||||||
auto pos = hitbox.position;
|
auto pos = hitbox.position;
|
||||||
@ -203,17 +203,17 @@ void PlayerController::onFootstep(const Hitbox& hitbox) {
|
|||||||
|
|
||||||
for (int offsetZ = -1; offsetZ <= 1; offsetZ++) {
|
for (int offsetZ = -1; offsetZ <= 1; offsetZ++) {
|
||||||
for (int offsetX = -1; offsetX <= 1; offsetX++) {
|
for (int offsetX = -1; offsetX <= 1; offsetX++) {
|
||||||
int x = std::floor(pos.x+half.x*offsetX);
|
int x = std::floor(pos.x + half.x * offsetX);
|
||||||
int y = std::floor(pos.y-half.y*1.1f);
|
int y = std::floor(pos.y - half.y * 1.1f);
|
||||||
int z = std::floor(pos.z+half.z*offsetZ);
|
int z = std::floor(pos.z + half.z * offsetZ);
|
||||||
auto vox = level->chunks->get(x, y, z);
|
auto vox = level->chunks->get(x, y, z);
|
||||||
if (vox) {
|
if (vox) {
|
||||||
auto def = level->content->getIndices()->blocks.get(vox->id);
|
auto def = level->content->getIndices()->blocks.get(vox->id);
|
||||||
if (!def->obstacle)
|
if (!def->obstacle) continue;
|
||||||
continue;
|
|
||||||
blocksController->onBlockInteraction(
|
blocksController->onBlockInteraction(
|
||||||
player.get(),
|
player.get(),
|
||||||
glm::ivec3(x, y, z), def,
|
glm::ivec3(x, y, z),
|
||||||
|
def,
|
||||||
BlockInteraction::step
|
BlockInteraction::step
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -298,23 +298,30 @@ void PlayerController::updatePlayer(float delta) {
|
|||||||
player->updateInput(input, delta);
|
player->updateInput(input, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int determine_rotation(Block* def, const glm::ivec3& norm, glm::vec3& camDir) {
|
static int determine_rotation(
|
||||||
if (def && def->rotatable){
|
Block* def, const glm::ivec3& norm, glm::vec3& camDir
|
||||||
|
) {
|
||||||
|
if (def && def->rotatable) {
|
||||||
const std::string& name = def->rotations.name;
|
const std::string& name = def->rotations.name;
|
||||||
if (name == "pipe") {
|
if (name == "pipe") {
|
||||||
if (norm.x < 0.0f) return BLOCK_DIR_WEST;
|
if (norm.x < 0.0f)
|
||||||
else if (norm.x > 0.0f) return BLOCK_DIR_EAST;
|
return BLOCK_DIR_WEST;
|
||||||
else if (norm.y > 0.0f) return BLOCK_DIR_UP;
|
else if (norm.x > 0.0f)
|
||||||
else if (norm.y < 0.0f) return BLOCK_DIR_DOWN;
|
return BLOCK_DIR_EAST;
|
||||||
else if (norm.z > 0.0f) return BLOCK_DIR_NORTH;
|
else if (norm.y > 0.0f)
|
||||||
else if (norm.z < 0.0f) return BLOCK_DIR_SOUTH;
|
return BLOCK_DIR_UP;
|
||||||
}
|
else if (norm.y < 0.0f)
|
||||||
else if (name == "pane") {
|
return BLOCK_DIR_DOWN;
|
||||||
if (abs(camDir.x) > abs(camDir.z)){
|
else if (norm.z > 0.0f)
|
||||||
|
return BLOCK_DIR_NORTH;
|
||||||
|
else if (norm.z < 0.0f)
|
||||||
|
return BLOCK_DIR_SOUTH;
|
||||||
|
} else if (name == "pane") {
|
||||||
|
if (abs(camDir.x) > abs(camDir.z)) {
|
||||||
if (camDir.x > 0.0f) return BLOCK_DIR_EAST;
|
if (camDir.x > 0.0f) return BLOCK_DIR_EAST;
|
||||||
if (camDir.x < 0.0f) return BLOCK_DIR_WEST;
|
if (camDir.x < 0.0f) return BLOCK_DIR_WEST;
|
||||||
}
|
}
|
||||||
if (abs(camDir.x) < abs(camDir.z)){
|
if (abs(camDir.x) < abs(camDir.z)) {
|
||||||
if (camDir.z > 0.0f) return BLOCK_DIR_SOUTH;
|
if (camDir.z > 0.0f) return BLOCK_DIR_SOUTH;
|
||||||
if (camDir.z < 0.0f) return BLOCK_DIR_NORTH;
|
if (camDir.z < 0.0f) return BLOCK_DIR_NORTH;
|
||||||
}
|
}
|
||||||
@ -323,9 +330,10 @@ static int determine_rotation(Block* def, const glm::ivec3& norm, glm::vec3& cam
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pick_block(ContentIndices* indices, Chunks* chunks, Player* player,
|
static void pick_block(
|
||||||
int x, int y, int z) {
|
ContentIndices* indices, Chunks* chunks, Player* player, int x, int y, int z
|
||||||
auto block = indices->blocks.get(chunks->get(x,y,z)->id);
|
) {
|
||||||
|
auto block = indices->blocks.get(chunks->get(x, y, z)->id);
|
||||||
itemid_t id = block->rt.pickingItem;
|
itemid_t id = block->rt.pickingItem;
|
||||||
auto inventory = player->getInventory();
|
auto inventory = player->getInventory();
|
||||||
size_t slotid = inventory->findSlotByItem(id, 0, 10);
|
size_t slotid = inventory->findSlotByItem(id, 0, 10);
|
||||||
@ -350,10 +358,7 @@ voxel* PlayerController::updateSelection(float maxDistance) {
|
|||||||
glm::ivec3 iend;
|
glm::ivec3 iend;
|
||||||
glm::ivec3 norm;
|
glm::ivec3 norm;
|
||||||
voxel* vox = chunks->rayCast(
|
voxel* vox = chunks->rayCast(
|
||||||
camera->position,
|
camera->position, camera->front, maxDistance, end, norm, iend
|
||||||
camera->front,
|
|
||||||
maxDistance,
|
|
||||||
end, norm, iend
|
|
||||||
);
|
);
|
||||||
if (vox) {
|
if (vox) {
|
||||||
maxDistance = glm::distance(camera->position, end);
|
maxDistance = glm::distance(camera->position, end);
|
||||||
@ -362,9 +367,11 @@ voxel* PlayerController::updateSelection(float maxDistance) {
|
|||||||
selection.entity = ENTITY_NONE;
|
selection.entity = ENTITY_NONE;
|
||||||
selection.actualPosition = iend;
|
selection.actualPosition = iend;
|
||||||
if (auto result = level->entities->rayCast(
|
if (auto result = level->entities->rayCast(
|
||||||
camera->position, camera->front, maxDistance, player->getEntity())) {
|
camera->position, camera->front, maxDistance, player->getEntity()
|
||||||
|
)) {
|
||||||
selection.entity = result->entity;
|
selection.entity = result->entity;
|
||||||
selection.hitPosition = camera->position + camera->front * result->distance;
|
selection.hitPosition =
|
||||||
|
camera->position + camera->front * result->distance;
|
||||||
selection.position = selection.hitPosition;
|
selection.position = selection.hitPosition;
|
||||||
selection.actualPosition = selection.position;
|
selection.actualPosition = selection.position;
|
||||||
selection.normal = result->normal;
|
selection.normal = result->normal;
|
||||||
@ -413,19 +420,21 @@ void PlayerController::processRightClick(Block* def, Block* target) {
|
|||||||
state.rotation = determine_rotation(def, selection.normal, camera->dir);
|
state.rotation = determine_rotation(def, selection.normal, camera->dir);
|
||||||
|
|
||||||
if (!input.shift && target->rt.funcsset.oninteract) {
|
if (!input.shift && target->rt.funcsset.oninteract) {
|
||||||
if (scripting::on_block_interact(player.get(), target, selection.position)) {
|
if (scripting::on_block_interact(
|
||||||
|
player.get(), target, selection.position
|
||||||
|
)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto coord = selection.actualPosition;
|
auto coord = selection.actualPosition;
|
||||||
if (!target->replaceable){
|
if (!target->replaceable) {
|
||||||
coord += selection.normal;
|
coord += selection.normal;
|
||||||
} else if (def->rotations.name == BlockRotProfile::PIPE_NAME) {
|
} else if (def->rotations.name == BlockRotProfile::PIPE_NAME) {
|
||||||
state.rotation = BLOCK_DIR_UP;
|
state.rotation = BLOCK_DIR_UP;
|
||||||
}
|
}
|
||||||
blockid_t chosenBlock = def->rt.id;
|
blockid_t chosenBlock = def->rt.id;
|
||||||
|
|
||||||
AABB blockAABB(coord, coord+1);
|
AABB blockAABB(coord, coord + 1);
|
||||||
bool blocked = level->entities->hasBlockingInside(blockAABB);
|
bool blocked = level->entities->hasBlockingInside(blockAABB);
|
||||||
|
|
||||||
if (def->obstacle && blocked) {
|
if (def->obstacle && blocked) {
|
||||||
@ -440,17 +449,22 @@ void PlayerController::processRightClick(Block* def, Block* target) {
|
|||||||
}
|
}
|
||||||
if (def->grounded) {
|
if (def->grounded) {
|
||||||
const auto& vec = get_ground_direction(def, state.rotation);
|
const auto& vec = get_ground_direction(def, state.rotation);
|
||||||
if (!chunks->isSolidBlock(coord.x+vec.x, coord.y+vec.y, coord.z+vec.z)) {
|
if (!chunks->isSolidBlock(
|
||||||
|
coord.x + vec.x, coord.y + vec.y, coord.z + vec.z
|
||||||
|
)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chosenBlock != vox->id && chosenBlock) {
|
if (chosenBlock != vox->id && chosenBlock) {
|
||||||
blocksController->placeBlock(
|
blocksController->placeBlock(
|
||||||
player.get(), def, state, coord.x, coord.y, coord.z);
|
player.get(), def, state, coord.x, coord.y, coord.z
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::updateEntityInteraction(entityid_t eid, bool lclick, bool rclick) {
|
void PlayerController::updateEntityInteraction(
|
||||||
|
entityid_t eid, bool lclick, bool rclick
|
||||||
|
) {
|
||||||
auto entityOpt = level->entities->get(eid);
|
auto entityOpt = level->entities->get(eid);
|
||||||
if (!entityOpt.has_value()) {
|
if (!entityOpt.has_value()) {
|
||||||
return;
|
return;
|
||||||
@ -470,8 +484,10 @@ void PlayerController::updateInteraction() {
|
|||||||
const auto& selection = player->selection;
|
const auto& selection = player->selection;
|
||||||
|
|
||||||
bool xkey = Events::pressed(keycode::X);
|
bool xkey = Events::pressed(keycode::X);
|
||||||
bool lclick = Events::jactive(BIND_PLAYER_ATTACK) || (xkey && Events::active(BIND_PLAYER_ATTACK));
|
bool lclick = Events::jactive(BIND_PLAYER_ATTACK) ||
|
||||||
bool rclick = Events::jactive(BIND_PLAYER_BUILD) || (xkey && Events::active(BIND_PLAYER_BUILD));
|
(xkey && Events::active(BIND_PLAYER_ATTACK));
|
||||||
|
bool rclick = Events::jactive(BIND_PLAYER_BUILD) ||
|
||||||
|
(xkey && Events::active(BIND_PLAYER_BUILD));
|
||||||
float maxDistance = xkey ? 200.0f : 10.0f;
|
float maxDistance = xkey ? 200.0f : 10.0f;
|
||||||
|
|
||||||
auto inventory = player->getInventory();
|
auto inventory = player->getInventory();
|
||||||
@ -491,13 +507,17 @@ void PlayerController::updateInteraction() {
|
|||||||
|
|
||||||
auto iend = selection.position;
|
auto iend = selection.position;
|
||||||
if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
|
if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
|
||||||
if (scripting::on_item_break_block(player.get(), item, iend.x, iend.y, iend.z)) {
|
if (scripting::on_item_break_block(
|
||||||
|
player.get(), item, iend.x, iend.y, iend.z
|
||||||
|
)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto target = indices->blocks.get(vox->id);
|
auto target = indices->blocks.get(vox->id);
|
||||||
if (lclick && target->breakable){
|
if (lclick && target->breakable) {
|
||||||
blocksController->breakBlock(player.get(), target, iend.x, iend.y, iend.z);
|
blocksController->breakBlock(
|
||||||
|
player.get(), target, iend.x, iend.y, iend.z
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (rclick && !input.shift) {
|
if (rclick && !input.shift) {
|
||||||
bool preventDefault = false;
|
bool preventDefault = false;
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#ifndef PLAYER_CONTROL_HPP_
|
#ifndef PLAYER_CONTROL_HPP_
|
||||||
#define PLAYER_CONTROL_HPP_
|
#define PLAYER_CONTROL_HPP_
|
||||||
|
|
||||||
#include "../objects/Player.hpp"
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
#include "../objects/Player.hpp"
|
||||||
|
|
||||||
class Camera;
|
class Camera;
|
||||||
class Level;
|
class Level;
|
||||||
@ -32,14 +32,14 @@ class CameraControl {
|
|||||||
/// @brief Update field-of-view effects
|
/// @brief Update field-of-view effects
|
||||||
/// @param input player inputs
|
/// @param input player inputs
|
||||||
/// @param delta delta time
|
/// @param delta delta time
|
||||||
void updateFovEffects(const Hitbox& hitbox, PlayerInput input,
|
void updateFovEffects(const Hitbox& hitbox, PlayerInput input, float delta);
|
||||||
float delta);
|
|
||||||
|
|
||||||
/// @brief Switch active player camera
|
/// @brief Switch active player camera
|
||||||
void switchCamera();
|
void switchCamera();
|
||||||
public:
|
public:
|
||||||
CameraControl(const std::shared_ptr<Player>& player,
|
CameraControl(
|
||||||
const CameraSettings& settings);
|
const std::shared_ptr<Player>& player, const CameraSettings& settings
|
||||||
|
);
|
||||||
void updateMouse(PlayerInput& input);
|
void updateMouse(PlayerInput& input);
|
||||||
void update(PlayerInput input, float delta, Chunks* chunks);
|
void update(PlayerInput input, float delta, Chunks* chunks);
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#ifndef LOGIC_SCRIPTING_API_LUA_HPP_
|
#ifndef LOGIC_SCRIPTING_API_LUA_HPP_
|
||||||
#define LOGIC_SCRIPTING_API_LUA_HPP_
|
#define LOGIC_SCRIPTING_API_LUA_HPP_
|
||||||
|
|
||||||
#include "lua_util.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "lua_util.hpp"
|
||||||
|
|
||||||
/// Definitions can be found in local .cpp files
|
/// Definitions can be found in local .cpp files
|
||||||
/// having same names as declarations
|
/// having same names as declarations
|
||||||
@ -15,34 +15,34 @@
|
|||||||
/// int l_function_name(lua::State* L);
|
/// int l_function_name(lua::State* L);
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
extern const luaL_Reg audiolib [];
|
extern const luaL_Reg audiolib[];
|
||||||
extern const luaL_Reg blocklib [];
|
extern const luaL_Reg blocklib[];
|
||||||
extern const luaL_Reg cameralib [];
|
extern const luaL_Reg cameralib[];
|
||||||
extern const luaL_Reg consolelib [];
|
extern const luaL_Reg consolelib[];
|
||||||
extern const luaL_Reg corelib [];
|
extern const luaL_Reg corelib[];
|
||||||
extern const luaL_Reg entitylib [];
|
extern const luaL_Reg entitylib[];
|
||||||
extern const luaL_Reg filelib [];
|
extern const luaL_Reg filelib[];
|
||||||
extern const luaL_Reg guilib [];
|
extern const luaL_Reg guilib[];
|
||||||
extern const luaL_Reg hudlib [];
|
extern const luaL_Reg hudlib[];
|
||||||
extern const luaL_Reg inputlib [];
|
extern const luaL_Reg inputlib[];
|
||||||
extern const luaL_Reg inventorylib [];
|
extern const luaL_Reg inventorylib[];
|
||||||
extern const luaL_Reg itemlib [];
|
extern const luaL_Reg itemlib[];
|
||||||
extern const luaL_Reg jsonlib [];
|
extern const luaL_Reg jsonlib[];
|
||||||
extern const luaL_Reg mat4lib [];
|
extern const luaL_Reg mat4lib[];
|
||||||
extern const luaL_Reg packlib [];
|
extern const luaL_Reg packlib[];
|
||||||
extern const luaL_Reg playerlib [];
|
extern const luaL_Reg playerlib[];
|
||||||
extern const luaL_Reg quatlib []; // quat.cpp
|
extern const luaL_Reg quatlib[]; // quat.cpp
|
||||||
extern const luaL_Reg timelib [];
|
extern const luaL_Reg timelib[];
|
||||||
extern const luaL_Reg tomllib [];
|
extern const luaL_Reg tomllib[];
|
||||||
extern const luaL_Reg vec2lib []; // vecn.cpp
|
extern const luaL_Reg vec2lib[]; // vecn.cpp
|
||||||
extern const luaL_Reg vec3lib []; // vecn.cpp
|
extern const luaL_Reg vec3lib[]; // vecn.cpp
|
||||||
extern const luaL_Reg vec4lib []; // vecn.cpp
|
extern const luaL_Reg vec4lib[]; // vecn.cpp
|
||||||
extern const luaL_Reg worldlib [];
|
extern const luaL_Reg worldlib[];
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
extern const luaL_Reg skeletonlib [];
|
extern const luaL_Reg skeletonlib[];
|
||||||
extern const luaL_Reg rigidbodylib [];
|
extern const luaL_Reg rigidbodylib[];
|
||||||
extern const luaL_Reg transformlib [];
|
extern const luaL_Reg transformlib[];
|
||||||
|
|
||||||
// Lua Overrides
|
// Lua Overrides
|
||||||
extern int l_print(lua::State* L);
|
extern int l_print(lua::State* L);
|
||||||
@ -55,23 +55,24 @@ namespace lua {
|
|||||||
} else {
|
} else {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"invalid number of arguments (" + std::to_string(a) +
|
"invalid number of arguments (" + std::to_string(a) +
|
||||||
" expected)");
|
" expected)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]] inline uint check_argc(lua::State* L, int a, int b) {
|
||||||
inline uint check_argc(lua::State* L, int a, int b) {
|
|
||||||
int argc = lua::gettop(L);
|
int argc = lua::gettop(L);
|
||||||
if (argc == a || argc == b) {
|
if (argc == a || argc == b) {
|
||||||
return static_cast<uint>(argc);
|
return static_cast<uint>(argc);
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"invalid number of arguments (" + std::to_string(a) + " or " +
|
"invalid number of arguments (" + std::to_string(a) + " or " +
|
||||||
std::to_string(b) + " expected)");
|
std::to_string(b) + " expected)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_libs_extends(lua::State* L);
|
void initialize_libs_extends(lua::State* L);
|
||||||
|
|
||||||
#endif // LOGIC_SCRIPTING_API_LUA_HPP_
|
#endif // LOGIC_SCRIPTING_API_LUA_HPP_
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "libentity.hpp"
|
|
||||||
|
|
||||||
#include "../../../util/stringutil.hpp"
|
#include "../../../util/stringutil.hpp"
|
||||||
|
#include "libentity.hpp"
|
||||||
|
|
||||||
static int l_get_vel(lua::State* L) {
|
static int l_get_vel(lua::State* L) {
|
||||||
if (auto entity = get_entity(L, 1)) {
|
if (auto entity = get_entity(L, 1)) {
|
||||||
@ -60,7 +59,9 @@ static int l_set_gravity_scale(lua::State* L) {
|
|||||||
|
|
||||||
static int l_is_vdamping(lua::State* L) {
|
static int l_is_vdamping(lua::State* L) {
|
||||||
if (auto entity = get_entity(L, 1)) {
|
if (auto entity = get_entity(L, 1)) {
|
||||||
return lua::pushboolean(L, entity->getRigidbody().hitbox.verticalDamping);
|
return lua::pushboolean(
|
||||||
|
L, entity->getRigidbody().hitbox.verticalDamping
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -95,7 +96,9 @@ static int l_set_crouching(lua::State* L) {
|
|||||||
|
|
||||||
static int l_get_body_type(lua::State* L) {
|
static int l_get_body_type(lua::State* L) {
|
||||||
if (auto entity = get_entity(L, 1)) {
|
if (auto entity = get_entity(L, 1)) {
|
||||||
return lua::pushstring(L, to_string(entity->getRigidbody().hitbox.type));
|
return lua::pushstring(
|
||||||
|
L, to_string(entity->getRigidbody().hitbox.type)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -106,7 +109,8 @@ static int l_set_body_type(lua::State* L) {
|
|||||||
entity->getRigidbody().hitbox.type = *type;
|
entity->getRigidbody().hitbox.type = *type;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"unknown body type "+util::quote(lua::tostring(L, 2)));
|
"unknown body type " + util::quote(lua::tostring(L, 2))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -126,7 +130,7 @@ static int l_set_linear_damping(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg rigidbodylib [] = {
|
const luaL_Reg rigidbodylib[] = {
|
||||||
{"is_enabled", lua::wrap<l_is_enabled>},
|
{"is_enabled", lua::wrap<l_is_enabled>},
|
||||||
{"set_enabled", lua::wrap<l_set_enabled>},
|
{"set_enabled", lua::wrap<l_set_enabled>},
|
||||||
{"get_vel", lua::wrap<l_get_vel>},
|
{"get_vel", lua::wrap<l_get_vel>},
|
||||||
@ -144,5 +148,4 @@ const luaL_Reg rigidbodylib [] = {
|
|||||||
{"set_crouching", lua::wrap<l_set_crouching>},
|
{"set_crouching", lua::wrap<l_set_crouching>},
|
||||||
{"get_body_type", lua::wrap<l_get_body_type>},
|
{"get_body_type", lua::wrap<l_get_body_type>},
|
||||||
{"set_body_type", lua::wrap<l_set_body_type>},
|
{"set_body_type", lua::wrap<l_set_body_type>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
|
#include "../../../objects/rigging.hpp"
|
||||||
#include "libentity.hpp"
|
#include "libentity.hpp"
|
||||||
|
|
||||||
#include "../../../objects/rigging.hpp"
|
static int index_range_check(
|
||||||
|
const rigging::Skeleton& skeleton, lua::Integer index
|
||||||
static int index_range_check(const rigging::Skeleton& skeleton, lua::Integer index) {
|
) {
|
||||||
if (static_cast<size_t>(index) >= skeleton.pose.matrices.size()) {
|
if (static_cast<size_t>(index) >= skeleton.pose.matrices.size()) {
|
||||||
throw std::runtime_error("index out of range [0, " +
|
throw std::runtime_error(
|
||||||
std::to_string(skeleton.pose.matrices.size()) +
|
"index out of range [0, " +
|
||||||
"]");
|
std::to_string(skeleton.pose.matrices.size()) + "]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return static_cast<int>(index);
|
return static_cast<int>(index);
|
||||||
}
|
}
|
||||||
@ -60,7 +62,8 @@ static int l_set_matrix(lua::State* L) {
|
|||||||
static int l_get_texture(lua::State* L) {
|
static int l_get_texture(lua::State* L) {
|
||||||
if (auto entity = get_entity(L, 1)) {
|
if (auto entity = get_entity(L, 1)) {
|
||||||
auto& skeleton = entity->getSkeleton();
|
auto& skeleton = entity->getSkeleton();
|
||||||
skeleton.textures[lua::require_string(L, 2)] = lua::require_string(L, 3);
|
skeleton.textures[lua::require_string(L, 2)] =
|
||||||
|
lua::require_string(L, 3);
|
||||||
const auto& found = skeleton.textures.find(lua::require_string(L, 2));
|
const auto& found = skeleton.textures.find(lua::require_string(L, 2));
|
||||||
if (found != skeleton.textures.end()) {
|
if (found != skeleton.textures.end()) {
|
||||||
return lua::pushstring(L, found->second);
|
return lua::pushstring(L, found->second);
|
||||||
@ -72,7 +75,8 @@ static int l_get_texture(lua::State* L) {
|
|||||||
static int l_set_texture(lua::State* L) {
|
static int l_set_texture(lua::State* L) {
|
||||||
if (auto entity = get_entity(L, 1)) {
|
if (auto entity = get_entity(L, 1)) {
|
||||||
auto& skeleton = entity->getSkeleton();
|
auto& skeleton = entity->getSkeleton();
|
||||||
skeleton.textures[lua::require_string(L, 2)] = lua::require_string(L, 3);
|
skeleton.textures[lua::require_string(L, 2)] =
|
||||||
|
lua::require_string(L, 3);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -128,7 +132,7 @@ static int l_set_color(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg skeletonlib [] = {
|
const luaL_Reg skeletonlib[] = {
|
||||||
{"get_model", lua::wrap<l_get_model>},
|
{"get_model", lua::wrap<l_get_model>},
|
||||||
{"set_model", lua::wrap<l_set_model>},
|
{"set_model", lua::wrap<l_set_model>},
|
||||||
{"get_matrix", lua::wrap<l_get_matrix>},
|
{"get_matrix", lua::wrap<l_get_matrix>},
|
||||||
@ -140,5 +144,4 @@ const luaL_Reg skeletonlib [] = {
|
|||||||
{"set_visible", lua::wrap<l_set_visible>},
|
{"set_visible", lua::wrap<l_set_visible>},
|
||||||
{"get_color", lua::wrap<l_get_color>},
|
{"get_color", lua::wrap<l_get_color>},
|
||||||
{"set_color", lua::wrap<l_set_color>},
|
{"set_color", lua::wrap<l_set_color>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|||||||
@ -44,12 +44,11 @@ static int l_set_rot(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg transformlib [] = {
|
const luaL_Reg transformlib[] = {
|
||||||
{"get_pos", lua::wrap<l_get_pos>},
|
{"get_pos", lua::wrap<l_get_pos>},
|
||||||
{"set_pos", lua::wrap<l_set_pos>},
|
{"set_pos", lua::wrap<l_set_pos>},
|
||||||
{"get_size", lua::wrap<l_get_size>},
|
{"get_size", lua::wrap<l_get_size>},
|
||||||
{"set_size", lua::wrap<l_set_size>},
|
{"set_size", lua::wrap<l_set_size>},
|
||||||
{"get_rot", lua::wrap<l_get_rot>},
|
{"get_rot", lua::wrap<l_get_rot>},
|
||||||
{"set_rot", lua::wrap<l_set_rot>},
|
{"set_rot", lua::wrap<l_set_rot>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include "api_lua.hpp"
|
|
||||||
|
|
||||||
#include "../../../audio/audio.hpp"
|
#include "../../../audio/audio.hpp"
|
||||||
#include "../../../engine.hpp"
|
#include "../../../engine.hpp"
|
||||||
|
#include "api_lua.hpp"
|
||||||
|
|
||||||
inline const char* DEFAULT_CHANNEL = "regular";
|
inline const char* DEFAULT_CHANNEL = "regular";
|
||||||
|
|
||||||
@ -39,9 +38,7 @@ inline audio::speakerid_t play_sound(
|
|||||||
return audio::play(
|
return audio::play(
|
||||||
sound,
|
sound,
|
||||||
glm::vec3(
|
glm::vec3(
|
||||||
static_cast<float>(x),
|
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||||
static_cast<float>(y),
|
|
||||||
static_cast<float>(z)
|
|
||||||
),
|
),
|
||||||
relative,
|
relative,
|
||||||
volume,
|
volume,
|
||||||
@ -70,9 +67,7 @@ inline audio::speakerid_t play_stream(
|
|||||||
return audio::play_stream(
|
return audio::play_stream(
|
||||||
paths->find(filename),
|
paths->find(filename),
|
||||||
glm::vec3(
|
glm::vec3(
|
||||||
static_cast<float>(x),
|
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||||
static_cast<float>(y),
|
|
||||||
static_cast<float>(z)
|
|
||||||
),
|
),
|
||||||
relative,
|
relative,
|
||||||
volume,
|
volume,
|
||||||
@ -92,8 +87,9 @@ inline audio::speakerid_t play_stream(
|
|||||||
/// channel: string = "regular",
|
/// channel: string = "regular",
|
||||||
/// loop: bool = false)
|
/// loop: bool = false)
|
||||||
static int l_audio_play_stream(lua::State* L) {
|
static int l_audio_play_stream(lua::State* L) {
|
||||||
return lua::pushinteger(L, static_cast<lua::Integer>(
|
return lua::pushinteger(
|
||||||
play_stream(
|
L,
|
||||||
|
static_cast<lua::Integer>(play_stream(
|
||||||
lua::tostring(L, 1),
|
lua::tostring(L, 1),
|
||||||
false,
|
false,
|
||||||
lua::tonumber(L, 2),
|
lua::tonumber(L, 2),
|
||||||
@ -103,8 +99,8 @@ static int l_audio_play_stream(lua::State* L) {
|
|||||||
lua::tonumber(L, 6),
|
lua::tonumber(L, 6),
|
||||||
lua::toboolean(L, 8),
|
lua::toboolean(L, 8),
|
||||||
extract_channel_index(L, 7)
|
extract_channel_index(L, 7)
|
||||||
)
|
))
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief audio.play_stream_2d(
|
/// @brief audio.play_stream_2d(
|
||||||
@ -114,17 +110,20 @@ static int l_audio_play_stream(lua::State* L) {
|
|||||||
/// channel: string = "regular",
|
/// channel: string = "regular",
|
||||||
/// loop: bool = false)
|
/// loop: bool = false)
|
||||||
static int l_audio_play_stream_2d(lua::State* L) {
|
static int l_audio_play_stream_2d(lua::State* L) {
|
||||||
return lua::pushinteger(L, static_cast<lua::Integer>(
|
return lua::pushinteger(
|
||||||
play_stream(
|
L,
|
||||||
|
static_cast<lua::Integer>(play_stream(
|
||||||
lua::tostring(L, 1),
|
lua::tostring(L, 1),
|
||||||
true,
|
true,
|
||||||
0.0, 0.0, 0.0,
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
lua::tonumber(L, 2),
|
lua::tonumber(L, 2),
|
||||||
lua::tonumber(L, 3),
|
lua::tonumber(L, 3),
|
||||||
lua::toboolean(L, 5),
|
lua::toboolean(L, 5),
|
||||||
extract_channel_index(L, 4)
|
extract_channel_index(L, 4)
|
||||||
)
|
))
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief audio.play_sound(
|
/// @brief audio.play_sound(
|
||||||
@ -137,8 +136,9 @@ static int l_audio_play_stream_2d(lua::State* L) {
|
|||||||
/// channel: string = "regular",
|
/// channel: string = "regular",
|
||||||
/// loop: bool = false)
|
/// loop: bool = false)
|
||||||
static int l_audio_play_sound(lua::State* L) {
|
static int l_audio_play_sound(lua::State* L) {
|
||||||
return lua::pushinteger(L, static_cast<lua::Integer>(
|
return lua::pushinteger(
|
||||||
play_sound(
|
L,
|
||||||
|
static_cast<lua::Integer>(play_sound(
|
||||||
lua::tostring(L, 1),
|
lua::tostring(L, 1),
|
||||||
false,
|
false,
|
||||||
lua::tonumber(L, 2),
|
lua::tonumber(L, 2),
|
||||||
@ -148,8 +148,8 @@ static int l_audio_play_sound(lua::State* L) {
|
|||||||
lua::tonumber(L, 6),
|
lua::tonumber(L, 6),
|
||||||
lua::toboolean(L, 8),
|
lua::toboolean(L, 8),
|
||||||
extract_channel_index(L, 7)
|
extract_channel_index(L, 7)
|
||||||
)
|
))
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief audio.play_sound_2d(
|
/// @brief audio.play_sound_2d(
|
||||||
@ -159,17 +159,20 @@ static int l_audio_play_sound(lua::State* L) {
|
|||||||
/// channel: string = "regular",
|
/// channel: string = "regular",
|
||||||
/// loop: bool = false)
|
/// loop: bool = false)
|
||||||
static int l_audio_play_sound_2d(lua::State* L) {
|
static int l_audio_play_sound_2d(lua::State* L) {
|
||||||
return lua::pushinteger(L, static_cast<lua::Integer>(
|
return lua::pushinteger(
|
||||||
play_sound(
|
L,
|
||||||
|
static_cast<lua::Integer>(play_sound(
|
||||||
lua::tostring(L, 1),
|
lua::tostring(L, 1),
|
||||||
true,
|
true,
|
||||||
0.0, 0.0, 0.0,
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
lua::tonumber(L, 2),
|
lua::tonumber(L, 2),
|
||||||
lua::tonumber(L, 3),
|
lua::tonumber(L, 3),
|
||||||
lua::toboolean(L, 5),
|
lua::toboolean(L, 5),
|
||||||
extract_channel_index(L, 4)
|
extract_channel_index(L, 4)
|
||||||
)
|
))
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief audio.stop(speakerid: integer) -> nil
|
/// @brief audio.stop(speakerid: integer) -> nil
|
||||||
@ -235,7 +238,8 @@ static int l_audio_set_time(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief audio.set_position(speakerid: integer, x: number, y: number, z: number) -> nil
|
/// @brief audio.set_position(speakerid: integer, x: number, y: number, z:
|
||||||
|
/// number) -> nil
|
||||||
static int l_audio_set_position(lua::State* L) {
|
static int l_audio_set_position(lua::State* L) {
|
||||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||||
if (speaker != nullptr) {
|
if (speaker != nullptr) {
|
||||||
@ -243,15 +247,14 @@ static int l_audio_set_position(lua::State* L) {
|
|||||||
auto y = lua::tonumber(L, 3);
|
auto y = lua::tonumber(L, 3);
|
||||||
auto z = lua::tonumber(L, 4);
|
auto z = lua::tonumber(L, 4);
|
||||||
speaker->setPosition(glm::vec3(
|
speaker->setPosition(glm::vec3(
|
||||||
static_cast<float>(x),
|
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||||
static_cast<float>(y),
|
|
||||||
static_cast<float>(z)
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief audio.set_velocity(speakerid: integer, x: number, y: number, z: number) -> nil
|
/// @brief audio.set_velocity(speakerid: integer, x: number, y: number, z:
|
||||||
|
/// number) -> nil
|
||||||
static int l_audio_set_velocity(lua::State* L) {
|
static int l_audio_set_velocity(lua::State* L) {
|
||||||
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
auto speaker = audio::get_speaker(lua::tointeger(L, 1));
|
||||||
if (speaker != nullptr) {
|
if (speaker != nullptr) {
|
||||||
@ -259,9 +262,7 @@ static int l_audio_set_velocity(lua::State* L) {
|
|||||||
auto y = lua::tonumber(L, 3);
|
auto y = lua::tonumber(L, 3);
|
||||||
auto z = lua::tonumber(L, 4);
|
auto z = lua::tonumber(L, 4);
|
||||||
speaker->setVelocity(glm::vec3(
|
speaker->setVelocity(glm::vec3(
|
||||||
static_cast<float>(x),
|
static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)
|
||||||
static_cast<float>(y),
|
|
||||||
static_cast<float>(z)
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -358,7 +359,7 @@ static int l_audio_count_streams(lua::State* L) {
|
|||||||
return lua::pushinteger(L, audio::count_streams());
|
return lua::pushinteger(L, audio::count_streams());
|
||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg audiolib [] = {
|
const luaL_Reg audiolib[] = {
|
||||||
{"play_sound", lua::wrap<l_audio_play_sound>},
|
{"play_sound", lua::wrap<l_audio_play_sound>},
|
||||||
{"play_sound_2d", lua::wrap<l_audio_play_sound_2d>},
|
{"play_sound_2d", lua::wrap<l_audio_play_sound_2d>},
|
||||||
{"play_stream", lua::wrap<l_audio_play_stream>},
|
{"play_stream", lua::wrap<l_audio_play_stream>},
|
||||||
@ -383,5 +384,4 @@ const luaL_Reg audiolib [] = {
|
|||||||
{"get_velocity", lua::wrap<l_audio_get_velocity>},
|
{"get_velocity", lua::wrap<l_audio_get_velocity>},
|
||||||
{"count_speakers", lua::wrap<l_audio_count_speakers>},
|
{"count_speakers", lua::wrap<l_audio_count_speakers>},
|
||||||
{"count_streams", lua::wrap<l_audio_count_streams>},
|
{"count_streams", lua::wrap<l_audio_count_streams>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
#include "api_lua.hpp"
|
|
||||||
|
|
||||||
#include "../../../world/Level.hpp"
|
|
||||||
#include "../../../voxels/Chunks.hpp"
|
|
||||||
#include "../../../voxels/Chunk.hpp"
|
|
||||||
#include "../../../voxels/Block.hpp"
|
|
||||||
#include "../../../voxels/voxel.hpp"
|
|
||||||
#include "../../../lighting/Lighting.hpp"
|
|
||||||
#include "../../../content/Content.hpp"
|
#include "../../../content/Content.hpp"
|
||||||
|
#include "../../../lighting/Lighting.hpp"
|
||||||
#include "../../../logic/BlocksController.hpp"
|
#include "../../../logic/BlocksController.hpp"
|
||||||
#include "../../../logic/LevelController.hpp"
|
#include "../../../logic/LevelController.hpp"
|
||||||
|
#include "../../../voxels/Block.hpp"
|
||||||
|
#include "../../../voxels/Chunk.hpp"
|
||||||
|
#include "../../../voxels/Chunks.hpp"
|
||||||
|
#include "../../../voxels/voxel.hpp"
|
||||||
|
#include "../../../world/Level.hpp"
|
||||||
|
#include "api_lua.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|
||||||
@ -80,7 +79,9 @@ static int l_seek_origin(lua::State* L) {
|
|||||||
auto z = lua::tointeger(L, 3);
|
auto z = lua::tointeger(L, 3);
|
||||||
auto vox = level->chunks->get(x, y, z);
|
auto vox = level->chunks->get(x, y, z);
|
||||||
auto def = indices->blocks.get(vox->id);
|
auto def = indices->blocks.get(vox->id);
|
||||||
return lua::pushivec3_stack(L, level->chunks->seekOrigin({x, y, z}, def, vox->state));
|
return lua::pushivec3_stack(
|
||||||
|
L, level->chunks->seekOrigin({x, y, z}, def, vox->state)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_set(lua::State* L) {
|
static int l_set(lua::State* L) {
|
||||||
@ -97,7 +98,7 @@ static int l_set(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
level->chunks->set(x, y, z, id, int2blockstate(state));
|
level->chunks->set(x, y, z, id, int2blockstate(state));
|
||||||
level->lighting->onBlockSet(x,y,z, id);
|
level->lighting->onBlockSet(x, y, z, id);
|
||||||
if (!noupdate) {
|
if (!noupdate) {
|
||||||
blocks->updateSides(x, y, z);
|
blocks->updateSides(x, y, z);
|
||||||
}
|
}
|
||||||
@ -265,7 +266,7 @@ static int l_get_textures(lua::State* L) {
|
|||||||
lua::createtable(L, 6, 0);
|
lua::createtable(L, 6, 0);
|
||||||
for (size_t i = 0; i < 6; i++) {
|
for (size_t i = 0; i < 6; i++) {
|
||||||
lua::pushstring(L, def->textureFaces[i]);
|
lua::pushstring(L, def->textureFaces[i]);
|
||||||
lua::rawseti(L, i+1);
|
lua::rawseti(L, i + 1);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -323,11 +324,14 @@ static int l_place(lua::State* L) {
|
|||||||
}
|
}
|
||||||
const auto def = level->content->getIndices()->blocks.get(id);
|
const auto def = level->content->getIndices()->blocks.get(id);
|
||||||
if (def == nullptr) {
|
if (def == nullptr) {
|
||||||
throw std::runtime_error("there is no block with index "+std::to_string(id));
|
throw std::runtime_error(
|
||||||
|
"there is no block with index " + std::to_string(id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
auto player = level->getObject<Player>(playerid);
|
auto player = level->getObject<Player>(playerid);
|
||||||
controller->getBlocksController()->placeBlock(
|
controller->getBlocksController()->placeBlock(
|
||||||
player ? player.get() : nullptr, def, int2blockstate(state), x, y, z);
|
player ? player.get() : nullptr, def, int2blockstate(state), x, y, z
|
||||||
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +347,8 @@ static int l_destruct(lua::State* L) {
|
|||||||
const auto def = level->content->getIndices()->blocks.get(voxel->id);
|
const auto def = level->content->getIndices()->blocks.get(voxel->id);
|
||||||
auto player = level->getObject<Player>(playerid);
|
auto player = level->getObject<Player>(playerid);
|
||||||
controller->getBlocksController()->breakBlock(
|
controller->getBlocksController()->breakBlock(
|
||||||
player ? player.get() : nullptr, def, x, y, z);
|
player ? player.get() : nullptr, def, x, y, z
|
||||||
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +359,9 @@ static int l_raycast(lua::State* L) {
|
|||||||
glm::vec3 end;
|
glm::vec3 end;
|
||||||
glm::ivec3 normal;
|
glm::ivec3 normal;
|
||||||
glm::ivec3 iend;
|
glm::ivec3 iend;
|
||||||
if (auto voxel = level->chunks->rayCast(start, dir, maxDistance, end, normal, iend)) {
|
if (auto voxel = level->chunks->rayCast(
|
||||||
|
start, dir, maxDistance, end, normal, iend
|
||||||
|
)) {
|
||||||
if (lua::gettop(L) >= 4) {
|
if (lua::gettop(L) >= 4) {
|
||||||
lua::pushvalue(L, 4);
|
lua::pushvalue(L, 4);
|
||||||
} else {
|
} else {
|
||||||
@ -386,9 +393,15 @@ static int l_compose_state(lua::State* L) {
|
|||||||
}
|
}
|
||||||
blockstate state {};
|
blockstate state {};
|
||||||
|
|
||||||
lua::rawgeti(L, 1, 1); state.rotation = lua::tointeger(L, -1); lua::pop(L);
|
lua::rawgeti(L, 1, 1);
|
||||||
lua::rawgeti(L, 2, 1); state.segment = lua::tointeger(L, -1); lua::pop(L);
|
state.rotation = lua::tointeger(L, -1);
|
||||||
lua::rawgeti(L, 3, 1); state.userbits = lua::tointeger(L, -1); lua::pop(L);
|
lua::pop(L);
|
||||||
|
lua::rawgeti(L, 2, 1);
|
||||||
|
state.segment = lua::tointeger(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
lua::rawgeti(L, 3, 1);
|
||||||
|
state.userbits = lua::tointeger(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
|
||||||
return lua::pushinteger(L, blockstate2int(state));
|
return lua::pushinteger(L, blockstate2int(state));
|
||||||
}
|
}
|
||||||
@ -409,7 +422,7 @@ static int l_decompose_state(lua::State* L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg blocklib [] = {
|
const luaL_Reg blocklib[] = {
|
||||||
{"index", lua::wrap<l_index>},
|
{"index", lua::wrap<l_index>},
|
||||||
{"name", lua::wrap<l_get_def>},
|
{"name", lua::wrap<l_get_def>},
|
||||||
{"material", lua::wrap<l_material>},
|
{"material", lua::wrap<l_material>},
|
||||||
@ -442,5 +455,4 @@ const luaL_Reg blocklib [] = {
|
|||||||
{"raycast", lua::wrap<l_raycast>},
|
{"raycast", lua::wrap<l_raycast>},
|
||||||
{"compose_state", lua::wrap<l_compose_state>},
|
{"compose_state", lua::wrap<l_compose_state>},
|
||||||
{"decompose_state", lua::wrap<l_decompose_state>},
|
{"decompose_state", lua::wrap<l_decompose_state>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user