[nostalgia] Add support for asset UUID headers

This commit is contained in:
Gary Talent 2023-02-12 00:02:41 -06:00
parent 2b821b73ff
commit 1b7b6e306e
14 changed files with 144 additions and 31 deletions

View File

@ -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<foundation::Module*, 2> mods = {
@ -23,7 +23,7 @@ void loadModules() noexcept {
for (const auto m : mods) {
foundation::registerModule(m);
}
done = true;
modulesLoaded = true;
}
}

View File

@ -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,

View File

@ -4,6 +4,7 @@
#include <ox/model/model.hpp>
#include <nostalgia/foundation/asset.hpp>
#include <nostalgia/foundation/module.hpp>
#include "gfx.hpp"
@ -39,8 +40,8 @@ ox::Vector<foundation::PackTransform> 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<TileSheetV1>() ||
typeId == ox::buildTypeId<TileSheetV2>() ||
typeId == ox::buildTypeId<TileSheet>()) {

View File

@ -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

View File

@ -0,0 +1,47 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "asset.hpp"
namespace nostalgia::foundation {
ox::Result<ox::UUID> readUuidHeader(const ox::Buffer &buff) noexcept {
return readUuidHeader(buff.data(), buff.size());
}
ox::Result<ox::UUID> 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<ox::ModelObject> 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<AssetHdr> 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<AssetHdr> readAssetHeader(const ox::Buffer &buff) noexcept {
return readAssetHeader(buff.data(), buff.size());
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/defines.hpp>
#include <ox/claw/claw.hpp>
#include <ox/fs/fs.hpp>
#include <nostalgia/foundation/context.hpp>
namespace nostalgia::foundation {
[[nodiscard]]
ox::Result<ox::UUID> readUuidHeader(const ox::Buffer &buff) noexcept;
ox::Result<ox::UUID> readUuidHeader(const char *buff, std::size_t buffLen) noexcept;
template<typename T>
ox::Result<T> 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<T>(buff.data() + offset, buff.size() - offset);
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore *ts, const ox::Buffer &buff) noexcept;
struct AssetHdr {
ox::UUID uuid;
ox::ClawHeader clawHdr;
};
ox::Result<AssetHdr> readAssetHeader(const char *buff, std::size_t buffLen) noexcept;
ox::Result<AssetHdr> readAssetHeader(const ox::Buffer &buff) noexcept;
}

View File

@ -12,10 +12,13 @@
#include <nostalgia/foundation/context.hpp>
#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<std::size_t> getPreloadAddr(foundation::Context *ctx, const ox::FileA
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 {
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> {
auto [obj, err] = ox::readClaw<T>(buff);
auto [obj, err] = readAsset<T>(buff);
if (err) {
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
return err;
@ -68,8 +73,10 @@ ox::Result<foundation::AssetRef<T>> readObj([[maybe_unused]] foundation::Context
}
template<typename T>
ox::Result<foundation::AssetRef<T>> readObj(foundation::Context *ctx, const ox::FileAddress &file,
[[maybe_unused]] bool forceLoad = false) noexcept {
ox::Result<foundation::AssetRef<T>> readObj(
foundation::Context *ctx,
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);
@ -84,8 +91,11 @@ ox::Result<foundation::AssetRef<T>> readObj(foundation::Context *ctx, const ox::
}
template<typename T>
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());
}

View File

@ -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<TypeDescGenerator> types() const noexcept;
[[nodiscard]]

View File

@ -4,6 +4,7 @@
#include <ox/claw/read.hpp>
#include "media.hpp"
#include "typeconv.hpp"
namespace nostalgia::foundation {
@ -52,8 +53,8 @@ ox::Result<ox::UniquePtr<Wrap>> 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

View File

@ -11,6 +11,7 @@
#include <ox/claw/write.hpp>
#include "context.hpp"
#include "media.hpp"
namespace nostalgia::foundation {
@ -135,7 +136,7 @@ class Converter: public BaseConverter {
}
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) const noexcept final {
oxRequireM(src, ox::readClaw<SrcType>(srcBuff));
oxRequireM(src, readAsset<SrcType>(srcBuff));
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, &src, wrapCast<DstType>(dst.get())));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
@ -176,8 +177,9 @@ ox::Result<ox::Buffer> convertBuffToBuff(foundation::Context *ctx, const ox::Buf
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
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<From>()) {
oxReturnError(foundation::convertBuffToBuff<To>(ctx, *buff, fmt).moveTo(buff));
}

View File

@ -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);

View File

@ -22,7 +22,7 @@ ox::String configPath(const core::Context *ctx) noexcept;
template<typename T>
ox::Result<T> 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<T> readConfig(core::Context *ctx) noexcept {
template<typename T>
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<typename T, typename Func>
void openConfig(core::Context *ctx, const auto &name, Func f) noexcept {
oxAssert(name != "", "Config type has no TypeName");
const auto c = readConfig<T>(ctx, name);
f(&c.value);
const auto [c, err] = readConfig<T>(ctx, name);
oxLogError(err);
f(&c);
}
template<typename T, typename Func>
@ -79,9 +80,10 @@ void openConfig(core::Context *ctx, Func f) noexcept {
template<typename T, typename Func>
void editConfig(core::Context *ctx, const auto &name, Func f) noexcept {
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
auto c = readConfig<T>(ctx, name);
f(&c.value);
oxLogError(writeConfig(ctx, name, &c.value));
auto [c, err] = readConfig<T>(ctx, name);
oxLogError(err);
f(&c);
oxLogError(writeConfig(ctx, name, &c));
}
template<typename T, typename Func>

View File

@ -13,6 +13,7 @@
#include <ox/std/hashmap.hpp>
#include <nostalgia/core/typestore.hpp>
#include <nostalgia/foundation/media.hpp>
#include "nostalgiastudio_export.h"
@ -129,9 +130,9 @@ template<typename T>
ox::Result<T> Project::loadObj(const ox::String &path) const noexcept {
oxRequire(buff, loadBuff(path));
if constexpr (ox::is_same_v<T, ox::ModelObject>) {
return ox::readClaw(&m_typeStore, buff);
return foundation::readAsset(&m_typeStore, buff);
} else {
return ox::readClaw<T>(buff);
return foundation::readAsset<T>(buff);
}
}

View File

@ -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