Skip to main content

Helpers

src/helpers/ — CD-ROM/archive file loading, the asset load queue and loader that consumes it, and world-space unit literals.

ArchiveHelper​

src/helpers/archive.hh

The engine's default file loader — reads files out of a psyqo::paths::ArchiveManager-backed archive (the format produced by pcsx-redux's authoring tool, see Loading Assets). Every asset manager (TextureManager, MeshManager, ColbinManager, AnimationManager, SoundManager, ModSoundManager) loads its raw file data through this.

constexpr uint8_t MAX_ARCHIVE_FILE_NAME_LEN = 255;

// hashes a name the same way psyqo-paths hashes its own archive index, so pool entries can store
// and compare names as a uint64_t instead of a full string. Runtime-string overload:
uint64_t HashName(eastl::string_view name);
// compile-time overload for string literals, folds to a constant:
template <unsigned S> constexpr uint64_t HashName(const char (&name)[S]);

class ArchiveHelper final {
public:
void init(eastl::function<void()> cb);
psyqo::Coroutine<psyqo::Buffer<uint8_t>> LoadFile(const eastl::string_view& fileName);
};

Non-static member of MadnightEngine (g_madnightEngine.m_archiveHelper). MAX_ARCHIVE_FILE_NAME_LEN is the shared name-length constant used throughout the engine for fixed-capacity asset name strings (mesh names, texture names, VAG names, and so on). HashName (also declared here) is the hashing helper used throughout the engine to turn a name into the uint64_t several managers now store/compare instead of a full string (see Updating the Engine → v0.0.1) — precompute a hash with it if you're going to look the same name up repeatedly.

Internals​

  • init() is asynchronous (callback-based, sets up the archive's decompressor and initializes against the CD-ROM device) — calling LoadFile before that callback has fired just logs a warning and returns an empty buffer, it doesn't queue or wait.
  • LoadFile loads a file from the archive by name.

CDRomHelper​

src/helpers/cdrom.hh

A lower-level loader that reads directly off an ISO9660 filesystem instead of a packed archive.

:::caution Deprecated As of v0.0.1, CDRomHelper is marked [[deprecated]] in favour of ArchiveHelper, and its instance (m_cdromHelper) is now a private member of MadnightEngine — game code can no longer reach it directly. It's documented here for reference/upstream reading, not for new use. :::

class CDRomHelper final {
public:
void init(eastl::function<void()> cb);
psyqo::Coroutine<psyqo::Buffer<uint8_t>> LoadFile(const eastl::string_view& fileName);
#ifndef PCDRV
psyqo::CDRomDevice& CDRomDevice();
#endif
};

CDRomHelper::LoadFile has no callers; ArchiveHelper::LoadFile runs all asset loads instead, in both PCDRV and non-PCDRV builds, borrowing CDRomHelper::CDRomDevice() as its underlying device in the latter case.

LoadQueue​

src/helpers/load_queue.hh

The runtime entry type produced by parsing a SCENEBIN manifest — a list of these is what you hand to FileLoader::LoadFiles (directly, or via MadnightEngine::HardLoadingScreen/SoftLoadingScreen) to bulk-load everything a scene needs.

enum LoadFileType { OBJECT, TEXTURE, MOD_FILE, ANIMATION, COLBIN, VAG, SCENE = 255 };

struct LoadQueue {
eastl::fixed_string<char, MAX_ARCHIVE_FILE_NAME_LEN> name;
LoadFileType type;
union {
struct { uint16_t x, y, clutX, clutY; }; // used when type == TEXTURE
};
};

See SCENEBIN → Types for the full type table and the on-disk manifest format this is parsed from.

FileLoader​

src/file_loader.hh

Consumes a LoadQueue list and loads every entry through the matching manager (MeshManager, TextureManager, ModSoundManager, AnimationManager, ColbinManager, SoundManager) in order, one file at a time. This is the actual loading engine — MadnightEngine::HardLoadingScreen/SoftLoadingScreen (below) are the higher-level entry points most game code should call instead of using FileLoader directly, but it's useful to understand since it owns the queue, progress counters, and load order.

enum LOAD_STATE : uint8_t { UNKNOWN, LOADING, COMPLETE };

class FileLoader final {
public:
// clearPools dumps all existing game objects, textures, meshes, colbins, and sfx first —
// it does not check whether anything is still in use before doing so.
psyqo::Coroutine<> LoadFiles(eastl::vector<LoadQueue> &&files, bool clearPools = true);
uint16_t TotalFiles(void); // increases as SCENE entries are encountered
uint16_t LoadedFiles(void);
LOAD_STATE LoadState(void);
};

Non-static member of MadnightEngine (g_madnightEngine.m_fileLoader). It owns a SceneLoader internally (src/scenes/scene_loader.hh) to resolve SCENE-type queue entries — SceneLoader isn't exposed on MadnightEngine directly, only reached through FileLoader.

Usage​

Most game code goes through MadnightEngine rather than calling FileLoader directly — it wraps FileLoader::LoadFiles with scene push/pop around the built-in (or your own) loading screen:

// a SCENE-type entry gets expanded into more entries internally, via FileLoader's own
// SceneLoader -- SceneLoader itself isn't reachable from game code directly as of v0.0.1
eastl::vector<LoadQueue> files = {{.name = "level01.scenebin", .type = LoadFileType::SCENE}};

// pops the current scene, shows the loading screen, loads everything, then switches to postLoadScene
co_await g_madnightEngine.HardLoadingScreen(eastl::move(files), &gameplayScene);

Two lighter variants exist alongside HardLoadingScreen:

// keeps the current scene on the stack instead of unloading it, and doesn't dump existing
// pools -- useful for streaming in extra assets without a full scene transition. Uses the
// engine's own built-in loading scene.
co_await g_madnightEngine.SoftLoadingScreen(eastl::move(files));

// either HardLoadingScreen or SoftLoadingScreen can take your own loading scene instead
// of the engine's default one
co_await g_madnightEngine.HardLoadingScreen(eastl::move(files), myLoadingScene, &gameplayScene);

The one-argument SoftLoadingScreen(files) forwards to the two-argument overload with the engine's built-in default loading scene; pass your own psyqo::Scene as a second argument if you want a custom one instead.

Calling FileLoader::LoadFiles directly only makes sense if you're building your own loading-screen flow rather than using MadnightEngine's.

Internals​

  • LoadFiles empties and releases the queue's capacity (m_queue.set_capacity(0)) once loading finishes — it doesn't just sit there holding memory between loads.
  • A SCENE-type entry can append more entries onto the queue mid-load (via SceneLoader::LoadScene), which is why TotalFiles() can grow while loading is in progress — don't treat it as a fixed count up front.
  • clearPools (default true) dumps game objects, meshes, textures, colbins, and sound all at once before loading starts — pass false (as SoftLoadingScreen does) if you want to add to what's already loaded instead of replacing it.

World-space literals​

src/helpers/world_space.hh

User-defined literals for converting Blender-exported units directly into engine world-space fixed-point values, matching the 128-units-per-metre scale described in Core → World units.

using namespace psyqo::fixed_point_literals;

// 1m, 0.5 Blender units = 0.5_ws
// 2m, 1 Blender unit = 1.0_ws
// if Blender says X is 50m, you want 25.0_ws; if 1m, you want 0.5_ws
consteval psyqo::FixedPoint<> operator"" _ws(long double blenderUnits);
consteval psyqo::FixedPoint<10> operator"" _ws10(long double blenderUnits);

_ws10 is the same conversion targeting a FixedPoint<10> (10 fractional bits) rather than the engine's default fixed-point precision — used wherever a call site specifically needs that precision (e.g. angle-adjacent lerps).