From 1b7b6e306e8fc35ebded2174b2c3a70261abe207 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 12 Feb 2023 00:02:41 -0600 Subject: [PATCH] [nostalgia] Add support for asset UUID headers --- src/nostalgia/appmodules/appmodules.cpp | 6 ++-- src/nostalgia/core/gfx.hpp | 4 +-- src/nostalgia/core/module.cpp | 5 +-- src/nostalgia/foundation/CMakeLists.txt | 4 ++- src/nostalgia/foundation/asset.cpp | 47 +++++++++++++++++++++++++ src/nostalgia/foundation/asset.hpp | 42 ++++++++++++++++++++++ src/nostalgia/foundation/media.hpp | 24 +++++++++---- src/nostalgia/foundation/module.hpp | 1 + src/nostalgia/foundation/typeconv.cpp | 5 +-- src/nostalgia/foundation/typeconv.hpp | 8 +++-- src/nostalgia/player/main.cpp | 4 +++ src/nostalgia/studio/lib/configio.hpp | 16 +++++---- src/nostalgia/studio/lib/project.hpp | 5 +-- src/nostalgia/tools/pack/pack.cpp | 4 +-- 14 files changed, 144 insertions(+), 31 deletions(-) create mode 100644 src/nostalgia/foundation/asset.cpp create mode 100644 src/nostalgia/foundation/asset.hpp diff --git a/src/nostalgia/appmodules/appmodules.cpp b/src/nostalgia/appmodules/appmodules.cpp index f63385c5..a7ac347d 100644 --- a/src/nostalgia/appmodules/appmodules.cpp +++ b/src/nostalgia/appmodules/appmodules.cpp @@ -11,9 +11,9 @@ namespace nostalgia { +static bool modulesLoaded = false; void loadModules() noexcept { - static bool done = false; - if (done) { + if (modulesLoaded) { return; } const ox::Array mods = { @@ -23,7 +23,7 @@ void loadModules() noexcept { for (const auto m : mods) { foundation::registerModule(m); } - done = true; + modulesLoaded = true; } } diff --git a/src/nostalgia/core/gfx.hpp b/src/nostalgia/core/gfx.hpp index cb9c2eda..57423a4d 100644 --- a/src/nostalgia/core/gfx.hpp +++ b/src/nostalgia/core/gfx.hpp @@ -87,8 +87,8 @@ void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbb) noexcept; /** * @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section]) */ -ox::Error loadBgTileSheet(Context *ctx, unsigned cbb, const ox::FileAddress &tilesheet, - const ox::FileAddress &palette = nullptr) noexcept; +ox::Error loadBgTileSheet(Context *ctx, unsigned cbb, const ox::FileAddress &tilesheetAddr, + const ox::FileAddress &paletteAddr = nullptr) noexcept; ox::Error loadSpriteTileSheet(Context *ctx, const ox::FileAddress &tilesheetAddr, diff --git a/src/nostalgia/core/module.cpp b/src/nostalgia/core/module.cpp index 3ed67326..f330b11b 100644 --- a/src/nostalgia/core/module.cpp +++ b/src/nostalgia/core/module.cpp @@ -4,6 +4,7 @@ #include +#include #include #include "gfx.hpp" @@ -39,8 +40,8 @@ ox::Vector CoreModule::packTransforms() const noexcep return { // convert tilesheets to CompactTileSheets [](foundation::Context *ctx, ox::Buffer *buff) -> ox::Error { - oxRequire(hdr, ox::readClawHeader(*buff)); - const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion, hdr.typeParams); + oxRequire(hdr, foundation::readAssetHeader(*buff)); + const auto typeId = ox::buildTypeId(hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams); if (typeId == ox::buildTypeId() || typeId == ox::buildTypeId() || typeId == ox::buildTypeId()) { diff --git a/src/nostalgia/foundation/CMakeLists.txt b/src/nostalgia/foundation/CMakeLists.txt index 25785c01..ac741983 100644 --- a/src/nostalgia/foundation/CMakeLists.txt +++ b/src/nostalgia/foundation/CMakeLists.txt @@ -1,7 +1,7 @@ add_library( NostalgiaFoundation - foundation.hpp + asset.cpp media.cpp module.cpp typeconv.cpp @@ -20,6 +20,8 @@ install( FILES assetmanager.hpp context.hpp + foundation.hpp + asset.hpp media.hpp module.hpp typeconv.hpp diff --git a/src/nostalgia/foundation/asset.cpp b/src/nostalgia/foundation/asset.cpp new file mode 100644 index 00000000..bbc4d1d9 --- /dev/null +++ b/src/nostalgia/foundation/asset.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "asset.hpp" + +namespace nostalgia::foundation { + +ox::Result readUuidHeader(const ox::Buffer &buff) noexcept { + return readUuidHeader(buff.data(), buff.size()); +} + +ox::Result readUuidHeader(const char *buff, std::size_t buffLen) noexcept { + if (buffLen < 40) { + return OxError(1, "Insufficient data contain complete Nostalgia header"); + } + 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; +} + +ox::Result readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept { + std::size_t offset = 0; + if (!readUuidHeader(buff).error) { + offset = 40; // the size of N1 headers + } + return ox::readClaw(ts, buff.data() + offset, buff.size() - offset); +} + +ox::Result readAssetHeader(const char *buff, std::size_t buffLen) noexcept { + AssetHdr out; + const auto err = readUuidHeader(buff, buffLen).moveTo(&out.uuid); + const auto offset = err ? 0 : 40; + buff = buff + offset; + buffLen = buffLen - offset; + oxReturnError(ox::readClawHeader(buff, buffLen).moveTo(&out.clawHdr)); + return out; +} + +ox::Result readAssetHeader(const ox::Buffer &buff) noexcept { + return readAssetHeader(buff.data(), buff.size()); +} + +} diff --git a/src/nostalgia/foundation/asset.hpp b/src/nostalgia/foundation/asset.hpp new file mode 100644 index 00000000..8013d328 --- /dev/null +++ b/src/nostalgia/foundation/asset.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace nostalgia::foundation { + +[[nodiscard]] +ox::Result readUuidHeader(const ox::Buffer &buff) noexcept; + +ox::Result readUuidHeader(const char *buff, std::size_t buffLen) noexcept; + +template +ox::Result readAsset(const ox::Buffer &buff) noexcept { + std::size_t offset = 0; + const auto err = readUuidHeader(buff).error; + if (!err) { + offset = 40; // the size of N1 headers + } + return ox::readClaw(buff.data() + offset, buff.size() - offset); +} + +ox::Result readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept; + +struct AssetHdr { + ox::UUID uuid; + ox::ClawHeader clawHdr; +}; + +ox::Result readAssetHeader(const char *buff, std::size_t buffLen) noexcept; + +ox::Result readAssetHeader(const ox::Buffer &buff) noexcept; + +} diff --git a/src/nostalgia/foundation/media.hpp b/src/nostalgia/foundation/media.hpp index 0a723796..b6f6d5ff 100644 --- a/src/nostalgia/foundation/media.hpp +++ b/src/nostalgia/foundation/media.hpp @@ -12,10 +12,13 @@ #include +#include "asset.hpp" #include "typeconv.hpp" namespace nostalgia::foundation { +// Pointer to preloaded data that can be stored in FS in place of the actual +// data. struct PreloadPtr { static constexpr auto TypeName = "net.drinkingtea.ox.PreloadPtr"; static constexpr auto TypeVersion = 1; @@ -30,11 +33,13 @@ ox::Result getPreloadAddr(foundation::Context *ctx, const ox::FileA ox::Result getPreloadAddr(foundation::Context *ctx, ox::CRStringView file) noexcept; template -ox::Result> readObj([[maybe_unused]] foundation::Context *ctx, [[maybe_unused]] ox::CRStringView path, - [[maybe_unused]] bool forceLoad = false) noexcept { +ox::Result> 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 { - auto [obj, err] = ox::readClaw(buff); + auto [obj, err] = readAsset(buff); if (err) { if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) { return err; @@ -68,8 +73,10 @@ ox::Result> readObj([[maybe_unused]] foundation::Context } template -ox::Result> readObj(foundation::Context *ctx, const ox::FileAddress &file, - [[maybe_unused]] bool forceLoad = false) noexcept { +ox::Result> readObj( + foundation::Context *ctx, + const ox::FileAddress &file, + [[maybe_unused]] bool forceLoad = false) noexcept { #ifndef OX_BARE_METAL oxRequire(path, file.getPath()); return readObj(ctx, ox::StringView(path), forceLoad); @@ -84,8 +91,11 @@ ox::Result> readObj(foundation::Context *ctx, const ox:: } template -ox::Error writeObj(foundation::Context *ctx, const ox::FileAddress &file, const T &obj, - ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept { +ox::Error writeObj( + foundation::Context *ctx, + const ox::FileAddress &file, + const T &obj, + ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept { oxRequire(objBuff, ox::writeClaw(&obj, fmt)); return ctx->rom->write(file, objBuff.data(), objBuff.size()); } diff --git a/src/nostalgia/foundation/module.hpp b/src/nostalgia/foundation/module.hpp index 9dd83896..04acff1b 100644 --- a/src/nostalgia/foundation/module.hpp +++ b/src/nostalgia/foundation/module.hpp @@ -26,6 +26,7 @@ class Module { Module &operator=(const Module&) noexcept = delete; Module &operator=(Module&&) noexcept = delete; constexpr virtual ~Module() noexcept = default; + [[nodiscard]] virtual ox::Vector types() const noexcept; [[nodiscard]] diff --git a/src/nostalgia/foundation/typeconv.cpp b/src/nostalgia/foundation/typeconv.cpp index a32ba101..f3abdb65 100644 --- a/src/nostalgia/foundation/typeconv.cpp +++ b/src/nostalgia/foundation/typeconv.cpp @@ -4,6 +4,7 @@ #include +#include "media.hpp" #include "typeconv.hpp" namespace nostalgia::foundation { @@ -52,8 +53,8 @@ ox::Result> convert( const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { - oxRequire(hdr, ox::readClawHeader(srcBuffer)); - return convert(ctx, srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion); + oxRequire(hdr, readAssetHeader(srcBuffer)); + return convert(ctx, srcBuffer, hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, dstTypeName, dstTypeVersion); } #endif diff --git a/src/nostalgia/foundation/typeconv.hpp b/src/nostalgia/foundation/typeconv.hpp index ab5fb67b..045b4a40 100644 --- a/src/nostalgia/foundation/typeconv.hpp +++ b/src/nostalgia/foundation/typeconv.hpp @@ -11,6 +11,7 @@ #include #include "context.hpp" +#include "media.hpp" namespace nostalgia::foundation { @@ -135,7 +136,7 @@ class Converter: public BaseConverter { } ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) const noexcept final { - oxRequireM(src, ox::readClaw(srcBuff)); + oxRequireM(src, readAsset(srcBuff)); auto dst = makeWrap(); oxReturnError(convert(ctx, &src, wrapCast(dst.get()))); return ox::Result>(std::move(dst)); @@ -176,8 +177,9 @@ ox::Result convertBuffToBuff(foundation::Context *ctx, const ox::Buf template auto transformRule(foundation::Context *ctx, ox::Buffer *buff) -> ox::Error { - oxRequire(hdr, ox::readClawHeader(*buff)); - const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion, hdr.typeParams); + oxRequire(hdr, readAssetHeader(*buff)); + const auto typeId = ox::buildTypeId( + hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams); if (typeId == ox::buildTypeId()) { oxReturnError(foundation::convertBuffToBuff(ctx, *buff, fmt).moveTo(buff)); } diff --git a/src/nostalgia/player/main.cpp b/src/nostalgia/player/main.cpp index 8ab23f0f..4f42c3ca 100644 --- a/src/nostalgia/player/main.cpp +++ b/src/nostalgia/player/main.cpp @@ -13,7 +13,11 @@ static ox::Error run(int argc, const char **argv) noexcept { ox::trace::init(); +#ifdef OX_USE_STDLIB + // GBA doesn't need the modules and calling this doubles the size of the + // binary. nostalgia::loadModules(); +#endif if (argc < 2) { oxErr("Please provide path to project directory or OxFS file.\n"); return OxError(1); diff --git a/src/nostalgia/studio/lib/configio.hpp b/src/nostalgia/studio/lib/configio.hpp index e28ab408..0391d6b0 100644 --- a/src/nostalgia/studio/lib/configio.hpp +++ b/src/nostalgia/studio/lib/configio.hpp @@ -22,7 +22,7 @@ ox::String configPath(const core::Context *ctx) noexcept; template ox::Result readConfig(core::Context *ctx, ox::CRStringView name) noexcept { - oxAssert(ox_strcmp(name, ""), "Config type has no TypeName"); + oxAssert(name != "", "Config type has no TypeName"); const auto path = ox::sfmt("/{}.json", name); ox::PassThroughFS fs(configPath(ctx)); const auto [buff, err] = fs.read(path); @@ -41,7 +41,7 @@ ox::Result readConfig(core::Context *ctx) noexcept { template ox::Error writeConfig(core::Context *ctx, ox::CRStringView name, T *data) noexcept { - oxAssert(ox_strcmp(name, ""), "Config type has no TypeName"); + oxAssert(name != "", "Config type has no TypeName"); const auto path = ox::sfmt("/{}.json", name); ox::PassThroughFS fs(configPath(ctx)); if (const auto err = fs.mkdir("/", true)) { @@ -66,8 +66,9 @@ ox::Error writeConfig(core::Context *ctx, T *data) noexcept { template void openConfig(core::Context *ctx, const auto &name, Func f) noexcept { oxAssert(name != "", "Config type has no TypeName"); - const auto c = readConfig(ctx, name); - f(&c.value); + const auto [c, err] = readConfig(ctx, name); + oxLogError(err); + f(&c); } template @@ -79,9 +80,10 @@ void openConfig(core::Context *ctx, Func f) noexcept { template void editConfig(core::Context *ctx, const auto &name, Func f) noexcept { oxAssert(ox_strcmp(name, ""), "Config type has no TypeName"); - auto c = readConfig(ctx, name); - f(&c.value); - oxLogError(writeConfig(ctx, name, &c.value)); + auto [c, err] = readConfig(ctx, name); + oxLogError(err); + f(&c); + oxLogError(writeConfig(ctx, name, &c)); } template diff --git a/src/nostalgia/studio/lib/project.hpp b/src/nostalgia/studio/lib/project.hpp index 26d2d969..f6cd42dc 100644 --- a/src/nostalgia/studio/lib/project.hpp +++ b/src/nostalgia/studio/lib/project.hpp @@ -13,6 +13,7 @@ #include #include +#include #include "nostalgiastudio_export.h" @@ -129,9 +130,9 @@ template ox::Result Project::loadObj(const ox::String &path) const noexcept { oxRequire(buff, loadBuff(path)); if constexpr (ox::is_same_v) { - return ox::readClaw(&m_typeStore, buff); + return foundation::readAsset(&m_typeStore, buff); } else { - return ox::readClaw(buff); + return foundation::readAsset(buff); } } diff --git a/src/nostalgia/tools/pack/pack.cpp b/src/nostalgia/tools/pack/pack.cpp index 83e06713..6d2fd9ef 100644 --- a/src/nostalgia/tools/pack/pack.cpp +++ b/src/nostalgia/tools/pack/pack.cpp @@ -79,7 +79,7 @@ static ox::Error doTransformations(foundation::Context *ctx, ox::TypeStore *ts, oxReturnError(tr(ctx, &buff)); } // transform FileAddresses - oxRequireM(obj, ox::readClaw(ts, buff)); + oxRequireM(obj, foundation::readAsset(ts, buff)); oxReturnError(transformFileAddressesObj(dest, &obj)); oxReturnError(ox::writeClaw(&obj).moveTo(&buff)); // write file to dest @@ -165,7 +165,7 @@ static ox::Error preloadObj( GbaPreloader *pl, ox::CRStringView path) noexcept { // load file oxRequireM(buff, romFs->read(path)); - oxRequireM(obj, ox::readClaw(ts, buff)); + oxRequireM(obj, foundation::readAsset(ts, buff)); if (obj.type()->preloadable) { oxOutf("preloading {}\n", path); // preload