[nostalgia] Add UUID to file path mapping
This commit is contained in:
parent
ba7ee92ad2
commit
5e43eff631
@ -15,14 +15,14 @@
|
|||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<ox::UPtr<Context>> init(ox::UPtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
|
ox::Result<ox::UPtr<Context>> init(ox::UPtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
|
||||||
auto ctx = foundation::init<Context>(std::move(fs), appName);
|
oxRequireM(ctx, foundation::init<Context>(std::move(fs), appName));
|
||||||
const auto id = ox::make<GlfwImplData>();
|
const auto id = ox::make<GlfwImplData>();
|
||||||
ctx->setWindowerData(id);
|
ctx->setWindowerData(id);
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
id->startTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
id->startTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||||
glfwInit();
|
glfwInit();
|
||||||
oxReturnError(initGfx(ctx.get()));
|
oxReturnError(initGfx(ctx.get()));
|
||||||
return ctx;
|
return std::move(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error run(Context *ctx) noexcept {
|
ox::Error run(Context *ctx) noexcept {
|
||||||
|
@ -17,9 +17,7 @@ ox::Result<ox::UUID> readUuidHeader(const char *buff, std::size_t buffLen) noexc
|
|||||||
if (ox_memcmp(buff, "N1;", 3) != 0) {
|
if (ox_memcmp(buff, "N1;", 3) != 0) {
|
||||||
return OxError(2, "No Nostalgia header data");
|
return OxError(2, "No Nostalgia header data");
|
||||||
}
|
}
|
||||||
ox::UUID out;
|
return ox::UUID::fromString(ox::StringView(buff + 3, 36));
|
||||||
oxReturnError(out.fromString(ox::StringView(buff + 3, 36)));
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::ModelObject> readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept {
|
ox::Result<ox::ModelObject> readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept {
|
||||||
|
@ -28,6 +28,7 @@ class AssetContainer {
|
|||||||
ox::Signal<ox::Error()> updated;
|
ox::Signal<ox::Error()> updated;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ox::UUID uuid;
|
||||||
T m_obj;
|
T m_obj;
|
||||||
mutable int m_references = 0;
|
mutable int m_references = 0;
|
||||||
|
|
||||||
@ -190,14 +191,14 @@ class AssetManager {
|
|||||||
ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache;
|
ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ox::Result<AssetRef<T>> getAsset(const ox::String &path) const noexcept {
|
ox::Result<AssetRef<T>> getAsset(const ox::String &assetId) const noexcept {
|
||||||
auto out = m_cache.at(path);
|
auto out = m_cache.at(assetId);
|
||||||
oxReturnError(out);
|
oxReturnError(out);
|
||||||
return AssetRef<T>(out.value->get());
|
return AssetRef<T>(out.value->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
|
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, const T &obj) noexcept {
|
||||||
auto &p = m_cache[path];
|
auto &p = m_cache[assetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = ox::make_unique<AssetContainer<T>>(obj);
|
p = ox::make_unique<AssetContainer<T>>(obj);
|
||||||
} else {
|
} else {
|
||||||
@ -207,8 +208,8 @@ class AssetManager {
|
|||||||
return AssetRef<T>(p.get());
|
return AssetRef<T>(p.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<AssetRef<T>> setAsset(const ox::String &path, T &&obj) noexcept {
|
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, T &&obj) noexcept {
|
||||||
auto &p = m_cache[path];
|
auto &p = m_cache[assetId];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = ox::make_unique<AssetContainer<T>>(obj);
|
p = ox::make_unique<AssetContainer<T>>(obj);
|
||||||
} else {
|
} else {
|
||||||
@ -221,7 +222,7 @@ class AssetManager {
|
|||||||
void gc() noexcept final {
|
void gc() noexcept final {
|
||||||
for (const auto &ack : m_cache.keys()) {
|
for (const auto &ack : m_cache.keys()) {
|
||||||
auto &ac = m_cache[ack];
|
auto &ac = m_cache[ack];
|
||||||
if (ac->references()) {
|
if (!ac->references()) {
|
||||||
m_cache.erase(ack);
|
m_cache.erase(ack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,15 +244,15 @@ class AssetManager {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<AssetRef<T>> getAsset(const ox::String &path) noexcept {
|
ox::Result<AssetRef<T>> getAsset(const ox::String &assetId) noexcept {
|
||||||
auto m = getTypeManager<T>();
|
auto m = getTypeManager<T>();
|
||||||
return m->getAsset(path);
|
return m->getAsset(assetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
|
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, const T &obj) noexcept {
|
||||||
auto m = getTypeManager<T>();
|
auto m = getTypeManager<T>();
|
||||||
return m->setAsset(path, obj);
|
return m->setAsset(assetId, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc() noexcept {
|
void gc() noexcept {
|
||||||
|
@ -21,6 +21,9 @@ class Context {
|
|||||||
ox::StringView appName = "Nostalgia Foundation App";
|
ox::StringView appName = "Nostalgia Foundation App";
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
AssetManager assetManager;
|
AssetManager assetManager;
|
||||||
|
bool useUuids = false;
|
||||||
|
ox::HashMap<ox::String, ox::UUID> pathToUuid;
|
||||||
|
ox::HashMap<ox::UUIDStr, ox::String> uuidToPath;
|
||||||
ox::Vector<const class BaseConverter*> converters;
|
ox::Vector<const class BaseConverter*> converters;
|
||||||
ox::Vector<PackTransform> packTransforms;
|
ox::Vector<PackTransform> packTransforms;
|
||||||
#else
|
#else
|
||||||
|
@ -7,15 +7,17 @@
|
|||||||
#include <ox/std/memory.hpp>
|
#include <ox/std/memory.hpp>
|
||||||
|
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
|
#include "media.hpp"
|
||||||
#include "module.hpp"
|
#include "module.hpp"
|
||||||
|
|
||||||
namespace nostalgia::foundation {
|
namespace nostalgia::foundation {
|
||||||
|
|
||||||
template<typename Ctx = foundation::Context>
|
template<typename Ctx = foundation::Context>
|
||||||
ox::UPtr<Ctx> init(ox::UPtr<ox::FileSystem> &&fs, ox::CRStringView appName) noexcept {
|
ox::Result<ox::UPtr<Ctx>> init(ox::UPtr<ox::FileSystem> &&fs, ox::CRStringView appName) noexcept {
|
||||||
auto ctx = ox::make_unique<Ctx>();
|
auto ctx = ox::make_unique<Ctx>();
|
||||||
ctx->rom = std::move(fs);
|
ctx->rom = std::move(fs);
|
||||||
ctx->appName = appName;
|
ctx->appName = appName;
|
||||||
|
oxReturnError(buildUuidMap(ctx.get()));
|
||||||
auto mods = modules();
|
auto mods = modules();
|
||||||
if (mods) {
|
if (mods) {
|
||||||
for (auto &mod : *mods) {
|
for (auto &mod : *mods) {
|
||||||
|
@ -40,6 +40,32 @@ ox::Result<void*> findPreloadSection() noexcept {
|
|||||||
return OxError(1, "findPreloadSection is unsupported on this platform");
|
return OxError(1, "findPreloadSection is unsupported on this platform");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ox::Error buildUuidMap(Context *ctx, ox::CRStringView path) noexcept {
|
||||||
|
oxRequire(files, ctx->rom->ls(path));
|
||||||
|
for (const auto &f : files) {
|
||||||
|
oxRequire(filePath, ox::join("/", ox::Array<ox::StringView, 2>{path, f}));
|
||||||
|
oxRequire(stat, ctx->rom->stat(filePath));
|
||||||
|
if (stat.fileType == ox::FileType::NormalFile) {
|
||||||
|
oxRequire(data, ctx->rom->read(filePath));
|
||||||
|
oxRequire(hdr, readAssetHeader(data));
|
||||||
|
ctx->pathToUuid[filePath] = hdr.uuid;
|
||||||
|
ctx->uuidToPath[hdr.uuid.toString()] = filePath;
|
||||||
|
} else if (stat.fileType == ox::FileType::Directory) {
|
||||||
|
if (!beginsWith(f, ".")) {
|
||||||
|
oxReturnError(buildUuidMap(ctx, filePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error buildUuidMap(Context *ctx) noexcept {
|
||||||
|
if (!ctx->rom) {
|
||||||
|
return OxError(1, "No ROM FS");
|
||||||
|
}
|
||||||
|
return buildUuidMap(ctx, "");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -50,6 +76,10 @@ ox::Result<void*> findPreloadSection() noexcept {
|
|||||||
|
|
||||||
namespace nostalgia::foundation {
|
namespace nostalgia::foundation {
|
||||||
|
|
||||||
|
ox::Error buildUuidMap(Context*) noexcept {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
|
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
|
||||||
// put the header in the wrong order to prevent mistaking this code for the
|
// put the header in the wrong order to prevent mistaking this code for the
|
||||||
// media section
|
// media section
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
#include <ox/fs/fs.hpp>
|
#include <ox/fs/fs.hpp>
|
||||||
#include <ox/model/metadata.hpp>
|
#include <ox/model/metadata.hpp>
|
||||||
|
|
||||||
#include <nostalgia/foundation/context.hpp>
|
|
||||||
|
|
||||||
#include "asset.hpp"
|
#include "asset.hpp"
|
||||||
|
#include "context.hpp"
|
||||||
#include "typeconv.hpp"
|
#include "typeconv.hpp"
|
||||||
|
|
||||||
namespace nostalgia::foundation {
|
namespace nostalgia::foundation {
|
||||||
@ -32,13 +32,14 @@ oxModelEnd()
|
|||||||
ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, const ox::FileAddress &file) noexcept;
|
ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, const ox::FileAddress &file) noexcept;
|
||||||
ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, ox::CRStringView file) noexcept;
|
ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, ox::CRStringView file) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ox::Result<foundation::AssetRef<T>> readObj(
|
|
||||||
[[maybe_unused]] foundation::Context *ctx,
|
|
||||||
[[maybe_unused]] ox::CRStringView path,
|
|
||||||
[[maybe_unused]] bool forceLoad = false) noexcept {
|
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
const auto readConvert = [ctx](const ox::Buffer &buff) -> ox::Result<T> {
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<foundation::AssetRef<T>> readObjFile(
|
||||||
|
foundation::Context *ctx,
|
||||||
|
ox::CRStringView assetId,
|
||||||
|
bool forceLoad) noexcept {
|
||||||
|
constexpr auto readConvert = [](Context *ctx, const ox::Buffer &buff) -> ox::Result<T> {
|
||||||
auto [obj, err] = readAsset<T>(buff);
|
auto [obj, err] = readAsset<T>(buff);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
|
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
|
||||||
@ -48,27 +49,55 @@ ox::Result<foundation::AssetRef<T>> readObj(
|
|||||||
}
|
}
|
||||||
return std::move(obj);
|
return std::move(obj);
|
||||||
};
|
};
|
||||||
if (forceLoad) {
|
ox::StringView path;
|
||||||
oxRequire(buff, ctx->rom->read(path));
|
if (ctx->useUuids) {
|
||||||
oxRequire(obj, readConvert(buff));
|
path = ctx->uuidToPath[assetId];
|
||||||
oxRequire(cached, ctx->assetManager.setAsset(path, obj));
|
|
||||||
return std::move(cached);
|
|
||||||
} else {
|
} else {
|
||||||
auto [cached, err] = ctx->assetManager.getAsset<T>(path);
|
path = assetId;
|
||||||
|
}
|
||||||
|
if (forceLoad) {
|
||||||
|
oxRequire(buff, ctx->rom->read(assetId));
|
||||||
|
oxRequire(obj, readConvert(ctx, buff));
|
||||||
|
oxRequire(cached, ctx->assetManager.setAsset(assetId, obj));
|
||||||
|
return cached;
|
||||||
|
} else {
|
||||||
|
auto [cached, err] = ctx->assetManager.getAsset<T>(assetId);
|
||||||
if (err) {
|
if (err) {
|
||||||
oxRequire(buff, ctx->rom->read(path));
|
oxRequire(buff, ctx->rom->read(assetId));
|
||||||
oxRequire(obj, readConvert(buff));
|
oxRequire(obj, readConvert(ctx, buff));
|
||||||
oxReturnError(ctx->assetManager.setAsset(path, obj).moveTo(&cached));
|
oxReturnError(ctx->assetManager.setAsset(assetId, obj).moveTo(&cached));
|
||||||
}
|
}
|
||||||
return std::move(cached);
|
return cached;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<foundation::AssetRef<T>> readObjNoCache(
|
||||||
|
foundation::Context *ctx,
|
||||||
|
ox::CRStringView assetId) noexcept {
|
||||||
if constexpr(ox::preloadable<T>::value) {
|
if constexpr(ox::preloadable<T>::value) {
|
||||||
oxRequire(addr, getPreloadAddr(ctx, path));
|
oxRequire(addr, getPreloadAddr(ctx, assetId));
|
||||||
return foundation::AssetRef<T>(reinterpret_cast<const T*>(addr));
|
return foundation::AssetRef<T>(reinterpret_cast<const T*>(addr));
|
||||||
} else {
|
} else {
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ox::Error buildUuidMap(Context *ctx) noexcept;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<foundation::AssetRef<T>> readObj(
|
||||||
|
[[maybe_unused]] foundation::Context *ctx,
|
||||||
|
[[maybe_unused]] ox::CRStringView assetId,
|
||||||
|
[[maybe_unused]] bool forceLoad = false) noexcept {
|
||||||
|
#ifndef OX_BARE_METAL
|
||||||
|
return readObjFile<T>(ctx, assetId, forceLoad);
|
||||||
|
#else
|
||||||
|
return readObjNoCache<T>(ctx, assetId);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +107,8 @@ ox::Result<foundation::AssetRef<T>> readObj(
|
|||||||
const ox::FileAddress &file,
|
const ox::FileAddress &file,
|
||||||
[[maybe_unused]] bool forceLoad = false) noexcept {
|
[[maybe_unused]] bool forceLoad = false) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
oxRequire(path, file.getPath());
|
oxRequire(assetId, file.getPath());
|
||||||
return readObj<T>(ctx, ox::StringView(path), forceLoad);
|
return readObj<T>(ctx, ox::StringView(assetId), forceLoad);
|
||||||
#else
|
#else
|
||||||
if constexpr(ox::preloadable<T>::value) {
|
if constexpr(ox::preloadable<T>::value) {
|
||||||
oxRequire(addr, getPreloadAddr(ctx, file));
|
oxRequire(addr, getPreloadAddr(ctx, file));
|
||||||
@ -100,9 +129,9 @@ ox::Error writeObj(
|
|||||||
return ctx->rom->write(file, objBuff.data(), objBuff.size());
|
return ctx->rom->write(file, objBuff.data(), objBuff.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept;
|
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView assetId) noexcept;
|
||||||
|
|
||||||
ox::Result<char*> loadRom(ox::CRStringView path = "") noexcept;
|
ox::Result<char*> loadRom(ox::CRStringView assetId = "") noexcept;
|
||||||
|
|
||||||
void unloadRom(char*) noexcept;
|
void unloadRom(char*) noexcept;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ static ox::Error run(const ox::ClArgs &args) noexcept {
|
|||||||
ox::Buffer dstBuff(32 * ox::units::MB);
|
ox::Buffer dstBuff(32 * ox::units::MB);
|
||||||
oxReturnError(ox::FileSystem32::format(dstBuff.data(), dstBuff.size()));
|
oxReturnError(ox::FileSystem32::format(dstBuff.data(), dstBuff.size()));
|
||||||
ox::FileSystem32 dst(ox::FileStore32(dstBuff.data(), dstBuff.size()));
|
ox::FileSystem32 dst(ox::FileStore32(dstBuff.data(), dstBuff.size()));
|
||||||
const auto ctx = foundation::init(ox::make_unique<ox::PassThroughFS>(argSrc), "nost-pack");
|
oxRequire(ctx, foundation::init(ox::make_unique<ox::PassThroughFS>(argSrc), "nost-pack"));
|
||||||
core::TypeStore ts(ctx->rom.get());
|
core::TypeStore ts(ctx->rom.get());
|
||||||
oxReturnError(generateTypes(&ts));
|
oxReturnError(generateTypes(&ts));
|
||||||
oxReturnError(pack(ctx.get(), &ts, &dst));
|
oxReturnError(pack(ctx.get(), &ts, &dst));
|
||||||
|
Loading…
Reference in New Issue
Block a user