refactor: add ContentControl class
This commit is contained in:
parent
7262119f5b
commit
331734792d
@ -25,7 +25,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
static debug::Logger logger("assets-loader");
|
||||
|
||||
AssetsLoader::AssetsLoader(Engine& engine, Assets& assets, const ResPaths* paths)
|
||||
AssetsLoader::AssetsLoader(Engine& engine, Assets& assets, const ResPaths& paths)
|
||||
: engine(engine), assets(assets), paths(paths) {
|
||||
addLoader(AssetType::SHADER, assetload::shader);
|
||||
addLoader(AssetType::TEXTURE, assetload::texture);
|
||||
@ -200,7 +200,7 @@ void AssetsLoader::processPreloadConfig(const io::path& file) {
|
||||
}
|
||||
|
||||
void AssetsLoader::processPreloadConfigs(const Content* content) {
|
||||
auto preloadFile = paths->getMainRoot() / "preload.json";
|
||||
io::path preloadFile = "res:preload.json";
|
||||
if (io::exists(preloadFile)) {
|
||||
processPreloadConfig(preloadFile);
|
||||
}
|
||||
@ -212,7 +212,7 @@ void AssetsLoader::processPreloadConfigs(const Content* content) {
|
||||
continue;
|
||||
}
|
||||
const auto& pack = entry.second;
|
||||
auto preloadFile = pack->getInfo().folder / "preload.json";
|
||||
preloadFile = pack->getInfo().folder / "preload.json";
|
||||
if (io::exists(preloadFile)) {
|
||||
processPreloadConfig(preloadFile);
|
||||
}
|
||||
@ -301,7 +301,7 @@ Engine& AssetsLoader::getEngine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
const ResPaths* AssetsLoader::getPaths() const {
|
||||
const ResPaths& AssetsLoader::getPaths() const {
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ struct AtlasCfg : AssetCfg {
|
||||
|
||||
using aloader_func = std::function<
|
||||
assetload::
|
||||
postfunc(AssetsLoader*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
|
||||
postfunc(AssetsLoader*, const ResPaths&, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
|
||||
|
||||
struct aloader_entry {
|
||||
AssetType tag;
|
||||
@ -72,7 +72,7 @@ class AssetsLoader {
|
||||
std::map<AssetType, aloader_func> loaders;
|
||||
std::queue<aloader_entry> entries;
|
||||
std::set<std::pair<AssetType, std::string>> enqueued;
|
||||
const ResPaths* paths;
|
||||
const ResPaths& paths;
|
||||
|
||||
void tryAddSound(const std::string& name);
|
||||
|
||||
@ -83,7 +83,7 @@ class AssetsLoader {
|
||||
void processPreloadConfig(const io::path& file);
|
||||
void processPreloadConfigs(const Content* content);
|
||||
public:
|
||||
AssetsLoader(Engine& engine, Assets& assets, const ResPaths* paths);
|
||||
AssetsLoader(Engine& engine, Assets& assets, const ResPaths& paths);
|
||||
void addLoader(AssetType tag, aloader_func func);
|
||||
|
||||
/// @brief Enqueue asset load
|
||||
@ -105,7 +105,7 @@ public:
|
||||
|
||||
std::shared_ptr<Task> startTask(runnable onDone);
|
||||
|
||||
const ResPaths* getPaths() const;
|
||||
const ResPaths& getPaths() const;
|
||||
aloader_func getLoader(AssetType tag);
|
||||
|
||||
/// @brief Enqueue core and content assets
|
||||
|
||||
@ -34,7 +34,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
static bool load_animation(
|
||||
Assets* assets,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& atlasName,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
@ -43,14 +43,14 @@ static bool load_animation(
|
||||
|
||||
assetload::postfunc assetload::texture(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
auto actualFile = paths->find(filename + ".png");
|
||||
auto actualFile = paths.find(filename + ".png");
|
||||
try {
|
||||
std::shared_ptr<ImageData> image(imageio::read(actualFile).release());
|
||||
std::shared_ptr<ImageData> image(imageio::read(actualFile));
|
||||
return [name, image, actualFile](auto assets) {
|
||||
assets->store(Texture::from(image.get()), name);
|
||||
};
|
||||
@ -62,13 +62,13 @@ assetload::postfunc assetload::texture(
|
||||
|
||||
assetload::postfunc assetload::shader(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
io::path vertexFile = paths->find(filename + ".glslv");
|
||||
io::path fragmentFile = paths->find(filename + ".glslf");
|
||||
io::path vertexFile = paths.find(filename + ".glslv");
|
||||
io::path fragmentFile = paths.find(filename + ".glslf");
|
||||
|
||||
std::string vertexSource = io::read_string(vertexFile);
|
||||
std::string fragmentSource = io::read_string(fragmentFile);
|
||||
@ -104,14 +104,14 @@ static bool append_atlas(AtlasBuilder& atlas, const io::path& file) {
|
||||
|
||||
assetload::postfunc assetload::atlas(
|
||||
AssetsLoader* loader,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& config
|
||||
) {
|
||||
auto atlasConfig = std::dynamic_pointer_cast<AtlasCfg>(config);
|
||||
if (atlasConfig && atlasConfig->type == AtlasType::SEPARATE) {
|
||||
for (const auto& file : paths->listdir(directory)) {
|
||||
for (const auto& file : paths.listdir(directory)) {
|
||||
if (!imageio::is_read_supported(file.extension()))
|
||||
continue;
|
||||
loader->add(
|
||||
@ -123,7 +123,7 @@ assetload::postfunc assetload::atlas(
|
||||
return [](auto){};
|
||||
}
|
||||
AtlasBuilder builder;
|
||||
for (const auto& file : paths->listdir(directory)) {
|
||||
for (const auto& file : paths.listdir(directory)) {
|
||||
if (!imageio::is_read_supported(file.extension())) continue;
|
||||
if (!append_atlas(builder, file)) continue;
|
||||
}
|
||||
@ -140,7 +140,7 @@ assetload::postfunc assetload::atlas(
|
||||
|
||||
assetload::postfunc assetload::font(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
@ -148,7 +148,7 @@ assetload::postfunc assetload::font(
|
||||
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
|
||||
for (size_t i = 0; i <= 1024; i++) {
|
||||
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
|
||||
auto file = paths->find(pagefile);
|
||||
auto file = paths.find(pagefile);
|
||||
if (io::exists(file)) {
|
||||
pages->push_back(imageio::read(file));
|
||||
} else if (i == 0) {
|
||||
@ -177,7 +177,7 @@ assetload::postfunc assetload::font(
|
||||
|
||||
assetload::postfunc assetload::layout(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths&,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& config
|
||||
@ -206,7 +206,7 @@ assetload::postfunc assetload::layout(
|
||||
}
|
||||
assetload::postfunc assetload::sound(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& config
|
||||
@ -220,13 +220,13 @@ assetload::postfunc assetload::sound(
|
||||
for (size_t i = 0; i < extensions.size(); i++) {
|
||||
extension = extensions[i];
|
||||
// looking for 'sound_name' as base sound
|
||||
auto soundFile = paths->find(file + extension);
|
||||
auto soundFile = paths.find(file + extension);
|
||||
if (io::exists(soundFile)) {
|
||||
baseSound = audio::load_sound(soundFile, keepPCM);
|
||||
break;
|
||||
}
|
||||
// looking for 'sound_name_0' as base sound
|
||||
auto variantFile = paths->find(file + "_0" + extension);
|
||||
auto variantFile = paths.find(file + "_0" + extension);
|
||||
if (io::exists(variantFile)) {
|
||||
baseSound = audio::load_sound(variantFile, keepPCM);
|
||||
break;
|
||||
@ -239,7 +239,7 @@ assetload::postfunc assetload::sound(
|
||||
// loading sound variants
|
||||
for (uint i = 1;; i++) {
|
||||
auto variantFile =
|
||||
paths->find(file + "_" + std::to_string(i) + extension);
|
||||
paths.find(file + "_" + std::to_string(i) + extension);
|
||||
if (!io::exists(variantFile)) {
|
||||
break;
|
||||
}
|
||||
@ -265,12 +265,12 @@ static void request_textures(AssetsLoader* loader, const model::Model& model) {
|
||||
|
||||
assetload::postfunc assetload::model(
|
||||
AssetsLoader* loader,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
auto path = paths->find(file + ".vec3");
|
||||
auto path = paths.find(file + ".vec3");
|
||||
if (io::exists(path)) {
|
||||
auto bytes = io::read_bytes_buffer(path);
|
||||
auto modelVEC3 = std::make_shared<vec3::File>(vec3::load(path.string(), bytes));
|
||||
@ -290,7 +290,7 @@ assetload::postfunc assetload::model(
|
||||
}
|
||||
};
|
||||
}
|
||||
path = paths->find(file + ".obj");
|
||||
path = paths.find(file + ".obj");
|
||||
auto text = io::read_string(path);
|
||||
try {
|
||||
auto model = obj::parse(path.string(), text).release();
|
||||
@ -384,7 +384,7 @@ inline bool contains(
|
||||
|
||||
static bool load_animation(
|
||||
Assets* assets,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& atlasName,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
@ -392,20 +392,20 @@ static bool load_animation(
|
||||
) {
|
||||
std::string animsDir = directory + "/animation";
|
||||
|
||||
for (const auto& folder : paths->listdir(animsDir)) {
|
||||
for (const auto& folder : paths.listdir(animsDir)) {
|
||||
if (!io::is_directory(folder)) continue;
|
||||
if (folder.name() != name) continue;
|
||||
//FIXME: if (fs::is_empty(folder)) continue;
|
||||
|
||||
AtlasBuilder builder;
|
||||
append_atlas(builder, paths->find(directory + "/" + name + ".png"));
|
||||
append_atlas(builder, paths.find(directory + "/" + name + ".png"));
|
||||
|
||||
std::vector<std::pair<std::string, int>> frameList;
|
||||
std::string animFile = folder.string() + "/animation.json";
|
||||
if (io::exists(animFile)) {
|
||||
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())) {
|
||||
continue;
|
||||
|
||||
@ -15,49 +15,49 @@ struct AssetCfg;
|
||||
namespace assetload {
|
||||
postfunc texture(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc shader(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc atlas(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& directory,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc font(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc layout(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc sound(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
);
|
||||
postfunc model(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const ResPaths& paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>& settings
|
||||
|
||||
140
src/content/ContentControl.cpp
Normal file
140
src/content/ContentControl.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "ContentControl.hpp"
|
||||
|
||||
#include "io/io.hpp"
|
||||
#include "io/engine_paths.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "Content.hpp"
|
||||
#include "ContentPack.hpp"
|
||||
#include "ContentBuilder.hpp"
|
||||
#include "ContentLoader.hpp"
|
||||
#include "PacksManager.hpp"
|
||||
#include "objects/rigging.hpp"
|
||||
#include "logic/scripting/scripting.hpp"
|
||||
#include "window/input.hpp"
|
||||
#include "core_defs.hpp"
|
||||
|
||||
static void load_configs(Input& input, const io::path& root) {
|
||||
auto configFolder = root / "config";
|
||||
auto bindsFile = configFolder / "bindings.toml";
|
||||
if (io::is_regular_file(bindsFile)) {
|
||||
input.getBindings().read(
|
||||
toml::parse(bindsFile.string(), io::read_string(bindsFile)),
|
||||
BindType::BIND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ContentControl::ContentControl(std::function<void()> postContent)
|
||||
: postContent(std::move(postContent)) {
|
||||
basePacks = io::read_list("res:config/builtins.list");
|
||||
}
|
||||
|
||||
ContentControl::~ContentControl() = default;
|
||||
|
||||
Content* ContentControl::get() {
|
||||
return content.get();
|
||||
}
|
||||
|
||||
std::vector<std::string>& ContentControl::getBasePacks() {
|
||||
return basePacks;
|
||||
}
|
||||
|
||||
void ContentControl::resetContent(
|
||||
EnginePaths& paths, Input& input, std::vector<ContentPack>& contentPacks
|
||||
) {
|
||||
scripting::cleanup();
|
||||
std::vector<PathsRoot> resRoots;
|
||||
{
|
||||
auto pack = ContentPack::createCore(paths);
|
||||
resRoots.push_back({"core", pack.folder});
|
||||
load_configs(input, pack.folder);
|
||||
}
|
||||
PacksManager manager;
|
||||
manager.setSources({
|
||||
"user:content",
|
||||
"res:content",
|
||||
});
|
||||
manager.scan();
|
||||
for (const auto& pack : manager.getAll(basePacks)) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
paths.resPaths = ResPaths(resRoots);
|
||||
content.reset();
|
||||
|
||||
contentPacks.clear();
|
||||
contentPacks = manager.getAll(basePacks);
|
||||
|
||||
postContent();
|
||||
}
|
||||
|
||||
void ContentControl::loadContent(
|
||||
EnginePaths& paths,
|
||||
Input& input,
|
||||
std::vector<ContentPack>& packs,
|
||||
const std::vector<std::string>& names
|
||||
) {
|
||||
PacksManager manager;
|
||||
manager.setSources(getDefaultSources());
|
||||
manager.scan();
|
||||
packs = manager.getAll(manager.assemble(names));
|
||||
loadContent(paths, input, packs);
|
||||
}
|
||||
|
||||
void ContentControl::loadContent(
|
||||
EnginePaths& paths,
|
||||
Input& input,
|
||||
std::vector<ContentPack>& contentPacks
|
||||
) {
|
||||
scripting::cleanup();
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (auto& pack : contentPacks) {
|
||||
names.push_back(pack.id);
|
||||
}
|
||||
|
||||
PacksManager manager;
|
||||
manager.setSources(getDefaultSources());
|
||||
manager.scan();
|
||||
names = manager.assemble(names);
|
||||
contentPacks = manager.getAll(names);
|
||||
|
||||
std::vector<PathsRoot> entryPoints;
|
||||
for (auto& pack : contentPacks) {
|
||||
entryPoints.emplace_back(pack.id, pack.folder);
|
||||
}
|
||||
paths.setEntryPoints(std::move(entryPoints));
|
||||
|
||||
ContentBuilder contentBuilder;
|
||||
corecontent::setup(input, contentBuilder);
|
||||
|
||||
auto corePack = ContentPack::createCore(paths);
|
||||
|
||||
auto allPacks = contentPacks;
|
||||
allPacks.insert(allPacks.begin(), corePack);
|
||||
|
||||
// Setup filesystem entry points
|
||||
std::vector<PathsRoot> resRoots;
|
||||
for (auto& pack : allPacks) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
paths.resPaths = ResPaths(resRoots);
|
||||
// Load content
|
||||
for (auto& pack : allPacks) {
|
||||
ContentLoader(&pack, contentBuilder, paths.resPaths).load();
|
||||
load_configs(input, pack.folder);
|
||||
}
|
||||
content = contentBuilder.build();
|
||||
scripting::on_content_load(content.get());
|
||||
|
||||
ContentLoader::loadScripts(*content);
|
||||
|
||||
postContent();
|
||||
}
|
||||
|
||||
std::vector<io::path> ContentControl::getDefaultSources() {
|
||||
return {
|
||||
"world:content",
|
||||
"user:content",
|
||||
"res:content",
|
||||
};
|
||||
}
|
||||
48
src/content/ContentControl.hpp
Normal file
48
src/content/ContentControl.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class Content;
|
||||
struct ContentPack;
|
||||
class EnginePaths;
|
||||
class Input;
|
||||
|
||||
namespace io {
|
||||
class path;
|
||||
}
|
||||
|
||||
class ContentControl {
|
||||
public:
|
||||
ContentControl(std::function<void()> postContent);
|
||||
~ContentControl();
|
||||
|
||||
Content* get();
|
||||
|
||||
std::vector<std::string>& getBasePacks();
|
||||
|
||||
void resetContent(
|
||||
EnginePaths& paths, Input& input, std::vector<ContentPack>& packs
|
||||
);
|
||||
|
||||
void loadContent(
|
||||
EnginePaths& paths,
|
||||
Input& input,
|
||||
std::vector<ContentPack>& packs,
|
||||
const std::vector<std::string>& names
|
||||
);
|
||||
|
||||
void loadContent(
|
||||
EnginePaths& paths,
|
||||
Input& input,
|
||||
std::vector<ContentPack>& packs
|
||||
);
|
||||
|
||||
std::vector<io::path> getDefaultSources();
|
||||
private:
|
||||
std::unique_ptr<Content> content;
|
||||
std::vector<std::string> basePacks;
|
||||
std::function<void()> postContent;
|
||||
};
|
||||
@ -124,7 +124,7 @@ ContentPack ContentPack::read(const std::string& path, const io::path& folder) {
|
||||
}
|
||||
|
||||
void ContentPack::scanFolder(
|
||||
const std::string& path, const io::path& folder, std::vector<ContentPack>& packs
|
||||
const io::path& folder, std::vector<ContentPack>& packs
|
||||
) {
|
||||
if (!io::is_directory(folder)) {
|
||||
return;
|
||||
@ -133,9 +133,7 @@ void ContentPack::scanFolder(
|
||||
if (!io::is_directory(packFolder)) continue;
|
||||
if (!is_pack(packFolder)) continue;
|
||||
try {
|
||||
packs.push_back(
|
||||
read(path + "/" + packFolder.name(), packFolder)
|
||||
);
|
||||
packs.push_back(read(packFolder.string(), packFolder));
|
||||
} catch (const contentpack_error& err) {
|
||||
std::cerr << "package.json error at " << err.getFolder().string();
|
||||
std::cerr << ": " << err.what() << std::endl;
|
||||
|
||||
@ -58,14 +58,10 @@ struct ContentPack {
|
||||
static const std::vector<std::string> RESERVED_NAMES;
|
||||
|
||||
static bool is_pack(const io::path& folder);
|
||||
static ContentPack read(
|
||||
const std::string& path, const io::path& folder
|
||||
);
|
||||
static ContentPack read(const std::string& path, const io::path& folder);
|
||||
|
||||
static void scanFolder(
|
||||
const std::string& path,
|
||||
const io::path& folder,
|
||||
std::vector<ContentPack>& packs
|
||||
const io::path& folder, std::vector<ContentPack>& packs
|
||||
);
|
||||
|
||||
static std::vector<std::string> worldPacksList(
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
PacksManager::PacksManager() = default;
|
||||
|
||||
void PacksManager::setSources(std::vector<std::pair<std::string, io::path>> sources) {
|
||||
void PacksManager::setSources(std::vector<io::path> sources) {
|
||||
this->sources = std::move(sources);
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@ void PacksManager::scan() {
|
||||
packs.clear();
|
||||
|
||||
std::vector<ContentPack> packsList;
|
||||
for (auto& [path, folder] : sources) {
|
||||
ContentPack::scanFolder(path, folder, packsList);
|
||||
for (auto& folder : sources) {
|
||||
ContentPack::scanFolder(folder, packsList);
|
||||
for (auto& pack : packsList) {
|
||||
packs.try_emplace(pack.id, pack);
|
||||
}
|
||||
|
||||
@ -8,12 +8,12 @@
|
||||
|
||||
class PacksManager {
|
||||
std::unordered_map<std::string, ContentPack> packs;
|
||||
std::vector<std::pair<std::string, io::path>> sources;
|
||||
std::vector<io::path> sources;
|
||||
public:
|
||||
PacksManager();
|
||||
|
||||
/// @brief Set content packs sources (search folders)
|
||||
void setSources(std::vector<std::pair<std::string, io::path>> sources);
|
||||
void setSources(std::vector<io::path> sources);
|
||||
|
||||
/// @brief Scan sources and collect all found packs excluding duplication.
|
||||
/// Scanning order depends on sources order
|
||||
|
||||
@ -7,14 +7,14 @@
|
||||
#include "debug/Logger.hpp"
|
||||
#include "assets/AssetsLoader.hpp"
|
||||
#include "audio/audio.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "coders/GLSLExtension.hpp"
|
||||
#include "coders/imageio.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentBuilder.hpp"
|
||||
#include "content/ContentLoader.hpp"
|
||||
#include "content/ContentControl.hpp"
|
||||
#include "core_defs.hpp"
|
||||
#include "io/io.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
@ -146,7 +146,14 @@ void Engine::initialize(CoreParameters coreParameters) {
|
||||
keepAlive(settings.ui.language.observe([this](auto lang) {
|
||||
setLanguage(lang);
|
||||
}, true));
|
||||
basePacks = io::read_list("res:config/builtins.list");
|
||||
|
||||
content = std::make_unique<ContentControl>([this]() {
|
||||
langs::setup("res:", langs::get_current(), paths.resPaths.collectRoots());
|
||||
if (!isHeadless()) {
|
||||
loadAssets();
|
||||
onAssetsLoaded();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Engine::loadSettings() {
|
||||
@ -284,27 +291,19 @@ EngineController* Engine::getController() {
|
||||
return controller.get();
|
||||
}
|
||||
|
||||
PacksManager Engine::createPacksManager(const io::path& worldFolder) {
|
||||
PacksManager manager;
|
||||
manager.setSources({
|
||||
{"world:content", worldFolder.empty() ? worldFolder : worldFolder / "content"},
|
||||
{"user:content", "user:content"},
|
||||
{"res:content", "res:content"}
|
||||
});
|
||||
return manager;
|
||||
}
|
||||
|
||||
void Engine::setLevelConsumer(OnWorldOpen levelConsumer) {
|
||||
this->levelConsumer = std::move(levelConsumer);
|
||||
}
|
||||
|
||||
void Engine::loadAssets() {
|
||||
logger.info() << "loading assets";
|
||||
Shader::preprocessor->setPaths(resPaths.get());
|
||||
Shader::preprocessor->setPaths(&paths.resPaths);
|
||||
|
||||
auto content = this->content->get();
|
||||
|
||||
auto new_assets = std::make_unique<Assets>();
|
||||
AssetsLoader loader(*this, *new_assets, resPaths.get());
|
||||
AssetsLoader::addDefaults(loader, content.get());
|
||||
AssetsLoader loader(*this, *new_assets, paths.resPaths);
|
||||
AssetsLoader::addDefaults(loader, content);
|
||||
|
||||
// no need
|
||||
// correct log messages order is more useful
|
||||
@ -345,118 +344,21 @@ void Engine::loadAssets() {
|
||||
}
|
||||
}
|
||||
|
||||
static void load_configs(Engine& engine, const io::path& root) {
|
||||
auto& input = engine.getInput();
|
||||
auto configFolder = root / "config";
|
||||
auto bindsFile = configFolder / "bindings.toml";
|
||||
if (io::is_regular_file(bindsFile)) {
|
||||
input.getBindings().read(
|
||||
toml::parse(bindsFile.string(), io::read_string(bindsFile)),
|
||||
BindType::BIND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::loadContent() {
|
||||
scripting::cleanup();
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (auto& pack : contentPacks) {
|
||||
names.push_back(pack.id);
|
||||
}
|
||||
|
||||
PacksManager manager = createPacksManager(paths.getCurrentWorldFolder());
|
||||
manager.scan();
|
||||
names = manager.assemble(names);
|
||||
contentPacks = manager.getAll(names);
|
||||
|
||||
std::vector<PathsRoot> entryPoints;
|
||||
for (auto& pack : contentPacks) {
|
||||
entryPoints.emplace_back(pack.id, pack.folder);
|
||||
}
|
||||
paths.setEntryPoints(std::move(entryPoints));
|
||||
|
||||
ContentBuilder contentBuilder;
|
||||
corecontent::setup(*input, contentBuilder);
|
||||
|
||||
auto corePack = ContentPack::createCore(paths);
|
||||
|
||||
// Setup filesystem entry points
|
||||
std::vector<PathsRoot> resRoots {
|
||||
{"core", corePack.folder}
|
||||
};
|
||||
for (auto& pack : contentPacks) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
resPaths = std::make_unique<ResPaths>("res:", resRoots);
|
||||
|
||||
// Load content
|
||||
{
|
||||
ContentLoader(&corePack, contentBuilder, *resPaths).load();
|
||||
load_configs(*this, corePack.folder);
|
||||
}
|
||||
for (auto& pack : contentPacks) {
|
||||
ContentLoader(&pack, contentBuilder, *resPaths).load();
|
||||
load_configs(*this, pack.folder);
|
||||
}
|
||||
content = contentBuilder.build();
|
||||
scripting::on_content_load(content.get());
|
||||
|
||||
ContentLoader::loadScripts(*content);
|
||||
|
||||
langs::setup("res:", langs::get_current(), resPaths->collectRoots());
|
||||
if (!isHeadless()) {
|
||||
loadAssets();
|
||||
onAssetsLoaded();
|
||||
}
|
||||
content->loadContent(paths, *input, contentPacks);
|
||||
}
|
||||
|
||||
void Engine::resetContent() {
|
||||
scripting::cleanup();
|
||||
std::vector<PathsRoot> resRoots;
|
||||
{
|
||||
auto pack = ContentPack::createCore(paths);
|
||||
resRoots.push_back({"core", pack.folder});
|
||||
load_configs(*this, pack.folder);
|
||||
}
|
||||
auto manager = createPacksManager(io::path());
|
||||
manager.scan();
|
||||
for (const auto& pack : manager.getAll(basePacks)) {
|
||||
resRoots.push_back({pack.id, pack.folder});
|
||||
}
|
||||
resPaths = std::make_unique<ResPaths>("res:", resRoots);
|
||||
contentPacks.clear();
|
||||
content.reset();
|
||||
|
||||
langs::setup("res:", langs::get_current(), resPaths->collectRoots());
|
||||
if (!isHeadless()) {
|
||||
loadAssets();
|
||||
onAssetsLoaded();
|
||||
}
|
||||
|
||||
contentPacks = manager.getAll(basePacks);
|
||||
paths.setCurrentWorldFolder("");
|
||||
content->resetContent(paths, *input, contentPacks);
|
||||
}
|
||||
|
||||
void Engine::loadWorldContent(const io::path& folder) {
|
||||
contentPacks.clear();
|
||||
auto packNames = ContentPack::worldPacksList(folder);
|
||||
PacksManager manager;
|
||||
manager.setSources(
|
||||
{{"world:content", folder.empty() ? folder : folder / "content"},
|
||||
{"user:content", "user:content"},
|
||||
{"res:content", "res:content"}}
|
||||
);
|
||||
manager.scan();
|
||||
contentPacks = manager.getAll(manager.assemble(packNames));
|
||||
paths.setCurrentWorldFolder(folder);
|
||||
loadContent();
|
||||
}
|
||||
|
||||
void Engine::loadAllPacks() {
|
||||
PacksManager manager = createPacksManager(paths.getCurrentWorldFolder());
|
||||
manager.scan();
|
||||
auto allnames = manager.getAllNames();
|
||||
contentPacks = manager.getAll(manager.assemble(allnames));
|
||||
content->loadContent(
|
||||
paths, *input, contentPacks, ContentPack::worldPacksList("world:")
|
||||
);
|
||||
}
|
||||
|
||||
void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||
@ -467,12 +369,7 @@ void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||
}
|
||||
|
||||
void Engine::setLanguage(std::string locale) {
|
||||
langs::setup(
|
||||
"res:",
|
||||
std::move(locale),
|
||||
resPaths ? resPaths->collectRoots()
|
||||
: std::vector<io::path> {{"core", "res:"}}
|
||||
);
|
||||
langs::setup("res:", std::move(locale), paths.resPaths.collectRoots());
|
||||
}
|
||||
|
||||
void Engine::onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer) {
|
||||
@ -505,11 +402,11 @@ Assets* Engine::getAssets() {
|
||||
}
|
||||
|
||||
const Content* Engine::getContent() const {
|
||||
return content.get();
|
||||
return content->get();
|
||||
}
|
||||
|
||||
Content* Engine::getWriteableContent() {
|
||||
return content.get();
|
||||
return content->get();
|
||||
}
|
||||
|
||||
std::vector<ContentPack> Engine::getAllContentPacks() {
|
||||
@ -522,16 +419,12 @@ std::vector<ContentPack>& Engine::getContentPacks() {
|
||||
return contentPacks;
|
||||
}
|
||||
|
||||
std::vector<std::string>& Engine::getBasePacks() {
|
||||
return basePacks;
|
||||
}
|
||||
|
||||
EnginePaths& Engine::getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
ResPaths* Engine::getResPaths() {
|
||||
return resPaths.get();
|
||||
ResPaths& Engine::getResPaths() {
|
||||
return paths.resPaths;
|
||||
}
|
||||
|
||||
std::shared_ptr<Screen> Engine::getScreen() {
|
||||
@ -553,3 +446,7 @@ const CoreParameters& Engine::getCoreParameters() const {
|
||||
bool Engine::isHeadless() const {
|
||||
return params.headless;
|
||||
}
|
||||
|
||||
ContentControl& Engine::getContentControl() {
|
||||
return *content;
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ class Level;
|
||||
class Screen;
|
||||
class EnginePaths;
|
||||
class ResPaths;
|
||||
class ContentControl;
|
||||
class EngineController;
|
||||
class SettingsHandler;
|
||||
struct EngineSettings;
|
||||
@ -64,14 +65,12 @@ class Engine : public util::ObjectsKeeper {
|
||||
std::unique_ptr<Assets> assets;
|
||||
std::shared_ptr<Screen> screen;
|
||||
std::vector<ContentPack> contentPacks;
|
||||
std::unique_ptr<Content> content;
|
||||
std::unique_ptr<ResPaths> resPaths;
|
||||
std::unique_ptr<ContentControl> content;
|
||||
std::unique_ptr<EngineController> controller;
|
||||
std::unique_ptr<cmd::CommandsInterpreter> cmd;
|
||||
std::unique_ptr<network::Network> network;
|
||||
std::unique_ptr<Window> window;
|
||||
std::unique_ptr<Input> input;
|
||||
std::vector<std::string> basePacks;
|
||||
std::unique_ptr<gui::GUI> gui;
|
||||
PostRunnables postRunnables;
|
||||
Time time;
|
||||
@ -127,9 +126,6 @@ public:
|
||||
/// @param folder world folder
|
||||
void loadWorldContent(const io::path& folder);
|
||||
|
||||
/// @brief Collect all available content-packs from res/content
|
||||
void loadAllPacks();
|
||||
|
||||
/// @brief Get active assets storage instance
|
||||
Assets* getAssets();
|
||||
|
||||
@ -140,7 +136,7 @@ public:
|
||||
EnginePaths& getPaths();
|
||||
|
||||
/// @brief Get engine resource paths controller
|
||||
ResPaths* getResPaths();
|
||||
ResPaths& getResPaths();
|
||||
|
||||
void onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer);
|
||||
void onWorldClosed();
|
||||
@ -159,8 +155,6 @@ public:
|
||||
|
||||
std::vector<ContentPack> getAllContentPacks();
|
||||
|
||||
std::vector<std::string>& getBasePacks();
|
||||
|
||||
/// @brief Get current screen
|
||||
std::shared_ptr<Screen> getScreen();
|
||||
|
||||
@ -173,8 +167,6 @@ public:
|
||||
|
||||
EngineController* getController();
|
||||
|
||||
PacksManager createPacksManager(const io::path& worldFolder);
|
||||
|
||||
void setLevelConsumer(OnWorldOpen levelConsumer);
|
||||
|
||||
SettingsHandler& getSettingsHandler();
|
||||
@ -185,6 +177,8 @@ public:
|
||||
|
||||
bool isHeadless() const;
|
||||
|
||||
ContentControl& getContentControl();
|
||||
|
||||
gui::GUI& getGUI() {
|
||||
return *gui;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ UiDocument* menus::show(
|
||||
Engine& engine, const std::string& name, std::vector<dv::value> args
|
||||
) {
|
||||
auto menu = engine.getGUI().getMenu();
|
||||
auto file = engine.getResPaths()->find("layouts/" + name + ".xml");
|
||||
auto file = engine.getResPaths().find("layouts/" + name + ".xml");
|
||||
auto fullname = "core:layouts/" + name;
|
||||
|
||||
auto documentPtr = UiDocument::read(
|
||||
|
||||
@ -61,7 +61,7 @@ Decorator::Decorator(
|
||||
player->getPosition()
|
||||
));
|
||||
}
|
||||
playerNamePreset.deserialize(engine.getResPaths()->readCombinedObject(
|
||||
playerNamePreset.deserialize(engine.getResPaths().readCombinedObject(
|
||||
"presets/text3d/player_name.toml"
|
||||
));
|
||||
}
|
||||
|
||||
@ -247,8 +247,8 @@ std::tuple<std::string, std::string> EnginePaths::parsePath(std::string_view pat
|
||||
return {prefix, filename};
|
||||
}
|
||||
|
||||
ResPaths::ResPaths(io::path mainRoot, std::vector<PathsRoot> roots)
|
||||
: mainRoot(std::move(mainRoot)), roots(std::move(roots)) {
|
||||
ResPaths::ResPaths(std::vector<PathsRoot> roots)
|
||||
: roots(std::move(roots)) {
|
||||
}
|
||||
|
||||
io::path ResPaths::find(const std::string& filename) const {
|
||||
@ -259,7 +259,7 @@ io::path ResPaths::find(const std::string& filename) const {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return mainRoot / filename;
|
||||
return io::path("res:") / filename;
|
||||
}
|
||||
|
||||
std::string ResPaths::findRaw(const std::string& filename) const {
|
||||
@ -356,7 +356,3 @@ std::vector<io::path> ResPaths::collectRoots() {
|
||||
}
|
||||
return collected;
|
||||
}
|
||||
|
||||
const io::path& ResPaths::getMainRoot() const {
|
||||
return mainRoot;
|
||||
}
|
||||
|
||||
@ -19,8 +19,33 @@ struct PathsRoot {
|
||||
}
|
||||
};
|
||||
|
||||
class ResPaths {
|
||||
public:
|
||||
ResPaths() = default;
|
||||
|
||||
ResPaths(std::vector<PathsRoot> roots);
|
||||
|
||||
io::path find(const std::string& filename) const;
|
||||
std::string findRaw(const std::string& filename) const;
|
||||
std::vector<io::path> listdir(const std::string& folder) const;
|
||||
std::vector<std::string> listdirRaw(const std::string& folder) const;
|
||||
|
||||
/// @brief Read all found list versions from all packs and combine into a
|
||||
/// single list. Invalid versions will be skipped with logging a warning
|
||||
/// @param file *.json file path relative to entry point
|
||||
dv::value readCombinedList(const std::string& file) const;
|
||||
|
||||
dv::value readCombinedObject(const std::string& file, bool deep=false) const;
|
||||
|
||||
std::vector<io::path> collectRoots();
|
||||
private:
|
||||
std::vector<PathsRoot> roots;
|
||||
};
|
||||
|
||||
class EnginePaths {
|
||||
public:
|
||||
ResPaths resPaths;
|
||||
|
||||
void prepare();
|
||||
|
||||
void setUserFilesFolder(std::filesystem::path folder);
|
||||
@ -65,28 +90,3 @@ private:
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
class ResPaths {
|
||||
public:
|
||||
ResPaths(io::path mainRoot, std::vector<PathsRoot> roots);
|
||||
|
||||
io::path find(const std::string& filename) const;
|
||||
std::string findRaw(const std::string& filename) const;
|
||||
std::vector<io::path> listdir(const std::string& folder) const;
|
||||
std::vector<std::string> listdirRaw(const std::string& folder) const;
|
||||
|
||||
/// @brief Read all found list versions from all packs and combine into a
|
||||
/// single list. Invalid versions will be skipped with logging a warning
|
||||
/// @param file *.json file path relative to entry point
|
||||
dv::value readCombinedList(const std::string& file) const;
|
||||
|
||||
dv::value readCombinedObject(const std::string& file, bool deep=false) const;
|
||||
|
||||
std::vector<io::path> collectRoots();
|
||||
|
||||
const io::path& getMainRoot() const;
|
||||
|
||||
private:
|
||||
io::path mainRoot;
|
||||
std::vector<PathsRoot> roots;
|
||||
};
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "debug/Logger.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "content/ContentReport.hpp"
|
||||
#include "content/ContentControl.hpp"
|
||||
#include "world/files/WorldConverter.hpp"
|
||||
#include "world/files/WorldFiles.hpp"
|
||||
#include "frontend/locale.hpp"
|
||||
@ -318,7 +319,8 @@ void EngineController::reconfigPacks(
|
||||
runnable removeFunc = [this, controller, packsToAdd, packsToRemove]() {
|
||||
if (controller == nullptr) {
|
||||
try {
|
||||
auto manager = engine.createPacksManager("");
|
||||
PacksManager manager;
|
||||
manager.setSources(engine.getContentControl().getDefaultSources());
|
||||
manager.scan();
|
||||
auto names = PacksManager::getNames(engine.getContentPacks());
|
||||
for (const auto& id : packsToAdd) {
|
||||
@ -339,7 +341,9 @@ void EngineController::reconfigPacks(
|
||||
auto world = controller->getLevel()->getWorld();
|
||||
auto& wfile = *world->wfile;
|
||||
controller->saveWorld();
|
||||
auto manager = engine.createPacksManager(wfile.getFolder());
|
||||
|
||||
PacksManager manager;
|
||||
manager.setSources(engine.getContentControl().getDefaultSources());
|
||||
manager.scan();
|
||||
|
||||
auto names = PacksManager::getNames(world->getPacks());
|
||||
|
||||
@ -71,8 +71,8 @@ inline audio::speakerid_t play_stream(
|
||||
if (std::strchr(filename, ':')) {
|
||||
file = std::string(filename);
|
||||
} else {
|
||||
auto paths = scripting::engine->getResPaths();
|
||||
file = paths->find(filename);
|
||||
const auto& paths = scripting::engine->getResPaths();
|
||||
file = paths.find(filename);
|
||||
}
|
||||
return audio::play_stream(
|
||||
file,
|
||||
|
||||
@ -17,7 +17,7 @@ using namespace scripting;
|
||||
static int l_find(lua::State* L) {
|
||||
auto path = lua::require_string(L, 1);
|
||||
try {
|
||||
return lua::pushstring(L, engine->getResPaths()->findRaw(path));
|
||||
return lua::pushstring(L, engine->getResPaths().findRaw(path));
|
||||
} catch (const std::runtime_error& err) {
|
||||
return 0;
|
||||
}
|
||||
@ -159,7 +159,7 @@ static int l_write_bytes(lua::State* L) {
|
||||
}
|
||||
|
||||
static int l_list_all_res(lua::State* L, const std::string& path) {
|
||||
auto files = engine->getResPaths()->listdirRaw(path);
|
||||
auto files = engine->getResPaths().listdirRaw(path);
|
||||
lua::createtable(L, files.size(), 0);
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
lua::pushstring(L, files[i]);
|
||||
@ -222,7 +222,7 @@ static int l_read_combined_list(lua::State* L) {
|
||||
if (path.find(':') != std::string::npos) {
|
||||
throw std::runtime_error("entry point must not be specified");
|
||||
}
|
||||
return lua::pushvalue(L, engine->getResPaths()->readCombinedList(path));
|
||||
return lua::pushvalue(L, engine->getResPaths().readCombinedList(path));
|
||||
}
|
||||
|
||||
static int l_read_combined_object(lua::State* L) {
|
||||
@ -230,7 +230,7 @@ static int l_read_combined_object(lua::State* L) {
|
||||
if (path.find(':') != std::string::npos) {
|
||||
throw std::runtime_error("entry point must not be specified");
|
||||
}
|
||||
return lua::pushvalue(L, engine->getResPaths()->readCombinedObject(path));
|
||||
return lua::pushvalue(L, engine->getResPaths().readCombinedObject(path));
|
||||
}
|
||||
|
||||
static int l_is_writeable(lua::State* L) {
|
||||
|
||||
@ -68,7 +68,7 @@ static int l_get_generators(lua::State* L) {
|
||||
/// @return The ID of the default world generator
|
||||
static int l_get_default_generator(lua::State* L) {
|
||||
// content is not initialized yet
|
||||
auto combined = engine->getResPaths()->readCombinedObject(
|
||||
auto combined = engine->getResPaths().readCombinedObject(
|
||||
EnginePaths::CONFIG_DEFAULTS.string()
|
||||
);
|
||||
return lua::pushstring(L, combined["generator"].asString());
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#include "assets/AssetsLoader.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentControl.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "graphics/ui/gui_util.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
@ -47,7 +48,8 @@ static int l_pack_get_available(lua::State* L) {
|
||||
if (level) {
|
||||
worldFolder = level->getWorld()->wfile->getFolder();
|
||||
}
|
||||
auto manager = engine->createPacksManager(worldFolder);
|
||||
PacksManager manager;
|
||||
manager.setSources(engine->getContentControl().getDefaultSources());
|
||||
manager.scan();
|
||||
|
||||
const auto& installed = engine->getContentPacks();
|
||||
@ -153,7 +155,8 @@ static int pack_get_infos(lua::State* L) {
|
||||
if (level) {
|
||||
worldFolder = level->getWorld()->wfile->getFolder();
|
||||
}
|
||||
auto manager = engine->createPacksManager(worldFolder);
|
||||
PacksManager manager;
|
||||
manager.setSources(engine->getContentControl().getDefaultSources());
|
||||
manager.scan();
|
||||
auto vec =
|
||||
manager.getAll(std::vector<std::string>(ids.begin(), ids.end()));
|
||||
@ -195,7 +198,8 @@ static int l_pack_get_info(lua::State* L) {
|
||||
if (level) {
|
||||
worldFolder = level->getWorld()->wfile->getFolder();
|
||||
}
|
||||
auto manager = engine->createPacksManager(worldFolder);
|
||||
PacksManager manager;
|
||||
manager.setSources(engine->getContentControl().getDefaultSources());
|
||||
manager.scan();
|
||||
auto vec = manager.getAll({packid});
|
||||
if (!vec.empty()) {
|
||||
@ -208,7 +212,7 @@ static int l_pack_get_info(lua::State* L) {
|
||||
}
|
||||
|
||||
static int l_pack_get_base_packs(lua::State* L) {
|
||||
auto& packs = engine->getBasePacks();
|
||||
auto& packs = engine->getContentControl().getBasePacks();
|
||||
lua::createtable(L, packs.size(), 0);
|
||||
for (size_t i = 0; i < packs.size(); i++) {
|
||||
lua::pushstring(L, packs[i]);
|
||||
@ -232,7 +236,8 @@ static int l_pack_assemble(lua::State* L) {
|
||||
if (level) {
|
||||
worldFolder = level->getWorld()->wfile->getFolder();
|
||||
}
|
||||
auto manager = engine->createPacksManager(worldFolder);
|
||||
PacksManager manager;
|
||||
manager.setSources(engine->getContentControl().getDefaultSources());
|
||||
manager.scan();
|
||||
try {
|
||||
ids = manager.assemble(ids);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user