[nostalgia] Add UUID to file path mapping

This commit is contained in:
Gary Talent 2023-02-12 22:13:32 -06:00
parent ba7ee92ad2
commit 5e43eff631
8 changed files with 105 additions and 42 deletions

View File

@ -15,14 +15,14 @@
namespace nostalgia::core {
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>();
ctx->setWindowerData(id);
using namespace std::chrono;
id->startTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
glfwInit();
oxReturnError(initGfx(ctx.get()));
return ctx;
return std::move(ctx);
}
ox::Error run(Context *ctx) noexcept {

View File

@ -17,9 +17,7 @@ ox::Result<ox::UUID> readUuidHeader(const char *buff, std::size_t buffLen) noexc
if (ox_memcmp(buff, "N1;", 3) != 0) {
return OxError(2, "No Nostalgia header data");
}
ox::UUID out;
oxReturnError(out.fromString(ox::StringView(buff + 3, 36)));
return out;
return ox::UUID::fromString(ox::StringView(buff + 3, 36));
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept {

View File

@ -28,6 +28,7 @@ class AssetContainer {
ox::Signal<ox::Error()> updated;
private:
ox::UUID uuid;
T m_obj;
mutable int m_references = 0;
@ -190,14 +191,14 @@ class AssetManager {
ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache;
public:
ox::Result<AssetRef<T>> getAsset(const ox::String &path) const noexcept {
auto out = m_cache.at(path);
ox::Result<AssetRef<T>> getAsset(const ox::String &assetId) const noexcept {
auto out = m_cache.at(assetId);
oxReturnError(out);
return AssetRef<T>(out.value->get());
}
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
auto &p = m_cache[path];
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, const T &obj) noexcept {
auto &p = m_cache[assetId];
if (!p) {
p = ox::make_unique<AssetContainer<T>>(obj);
} else {
@ -207,8 +208,8 @@ class AssetManager {
return AssetRef<T>(p.get());
}
ox::Result<AssetRef<T>> setAsset(const ox::String &path, T &&obj) noexcept {
auto &p = m_cache[path];
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, T &&obj) noexcept {
auto &p = m_cache[assetId];
if (!p) {
p = ox::make_unique<AssetContainer<T>>(obj);
} else {
@ -221,7 +222,7 @@ class AssetManager {
void gc() noexcept final {
for (const auto &ack : m_cache.keys()) {
auto &ac = m_cache[ack];
if (ac->references()) {
if (!ac->references()) {
m_cache.erase(ack);
}
}
@ -243,15 +244,15 @@ class AssetManager {
public:
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>();
return m->getAsset(path);
return m->getAsset(assetId);
}
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>();
return m->setAsset(path, obj);
return m->setAsset(assetId, obj);
}
void gc() noexcept {

View File

@ -21,6 +21,9 @@ class Context {
ox::StringView appName = "Nostalgia Foundation App";
#ifndef OX_BARE_METAL
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<PackTransform> packTransforms;
#else

View File

@ -7,15 +7,17 @@
#include <ox/std/memory.hpp>
#include "context.hpp"
#include "media.hpp"
#include "module.hpp"
namespace nostalgia::foundation {
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>();
ctx->rom = std::move(fs);
ctx->appName = appName;
oxReturnError(buildUuidMap(ctx.get()));
auto mods = modules();
if (mods) {
for (auto &mod : *mods) {

View File

@ -40,6 +40,32 @@ ox::Result<void*> findPreloadSection() noexcept {
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
@ -50,6 +76,10 @@ ox::Result<void*> findPreloadSection() noexcept {
namespace nostalgia::foundation {
ox::Error buildUuidMap(Context*) noexcept {
return {};
}
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
// put the header in the wrong order to prevent mistaking this code for the
// media section

View File

@ -10,9 +10,9 @@
#include <ox/fs/fs.hpp>
#include <ox/model/metadata.hpp>
#include <nostalgia/foundation/context.hpp>
#include "asset.hpp"
#include "context.hpp"
#include "typeconv.hpp"
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, 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
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);
if (err) {
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
@ -48,27 +49,55 @@ ox::Result<foundation::AssetRef<T>> readObj(
}
return std::move(obj);
};
if (forceLoad) {
oxRequire(buff, ctx->rom->read(path));
oxRequire(obj, readConvert(buff));
oxRequire(cached, ctx->assetManager.setAsset(path, obj));
return std::move(cached);
ox::StringView path;
if (ctx->useUuids) {
path = ctx->uuidToPath[assetId];
} 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) {
oxRequire(buff, ctx->rom->read(path));
oxRequire(obj, readConvert(buff));
oxReturnError(ctx->assetManager.setAsset(path, obj).moveTo(&cached));
oxRequire(buff, ctx->rom->read(assetId));
oxRequire(obj, readConvert(ctx, buff));
oxReturnError(ctx->assetManager.setAsset(assetId, obj).moveTo(&cached));
}
return std::move(cached);
return cached;
}
}
#else
template<typename T>
ox::Result<foundation::AssetRef<T>> readObjNoCache(
foundation::Context *ctx,
ox::CRStringView assetId) noexcept {
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));
} else {
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
}
@ -78,8 +107,8 @@ ox::Result<foundation::AssetRef<T>> readObj(
const ox::FileAddress &file,
[[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
oxRequire(path, file.getPath());
return readObj<T>(ctx, ox::StringView(path), forceLoad);
oxRequire(assetId, file.getPath());
return readObj<T>(ctx, ox::StringView(assetId), forceLoad);
#else
if constexpr(ox::preloadable<T>::value) {
oxRequire(addr, getPreloadAddr(ctx, file));
@ -100,9 +129,9 @@ ox::Error writeObj(
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;

View File

@ -69,7 +69,7 @@ static ox::Error run(const ox::ClArgs &args) noexcept {
ox::Buffer dstBuff(32 * ox::units::MB);
oxReturnError(ox::FileSystem32::format(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());
oxReturnError(generateTypes(&ts));
oxReturnError(pack(ctx.get(), &ts, &dst));