Files
OpenRA3/third_party/libra3assets/src/assets.cppm
T
EnderTheCoder 23f8be394c feat(assets): read retail assets through the vendored libra3assets library
Vendor libra3assets (C++26 modules: BIG4, RefPack, BinaryAsset, CSF, CkMp map)
under third_party/ and add the ra3_assets target. ra3.fs, ra3.map and ra3.terrain
become thin adapters over it:

- ra3.fs delegates RefPack and the BIG4 index/payload reads (index-only, payloads
  read on demand).
- ra3.map decodes ObjectsList and CSF via map_document/csf_table; starts come from
  player_starts(), replacing the off-by-one whole-buffer scan.
- ra3.terrain takes the CkMp container and HeightMapData from map_document, with
  BlendTileData (not modelled by the library) parsed from the chunk payload.

Adds an opt-in real-asset check (OPENRA3_TEST_ASSETS) plus the library's own unit
suite as ra3assets_unit.
2026-09-29 23:58:13 +08:00

66 lines
2.5 KiB
C++

/**
* libra3assets - read (and write) Red Alert 3's built-in resource files.
*
* The primary module interface re-exports every partition:
*
* - `:error` - the `asset_error` exception family
* - `:bytes` - bounds-checked little-/big-endian readers and writers
* - `:refpack` - EA's RefPack codec (decompress and compress)
* - `:big` - `BIG4` archives (`Data\*.big`), read and write
* - `:binary` - compiled `BinaryAsset` streams (`*.bin` + `.manifest`)
* - `:csf` - SAGE `.csf` string tables
* - `:map` - SAGE `.map` containers (`CkMp`), read and write
*
* Nothing here reads game data on its own: callers point the library at their
* own installation (`RA3_GAME_DIR` / `C:\Red Alert 3`).
*/
export module ra3.assets;
export import :error;
export import :bytes;
export import :refpack;
export import :big;
export import :binary;
export import :csf;
export import :map;
import std;
export namespace ra3::assets {
/**
* Locate a Red Alert 3 installation.
*
* Resolution order: the explicit argument, then `$RA3_GAME_DIR`, then the
* default `C:\Red Alert 3`. A directory qualifies only if it has a `Data`
* subdirectory.
*/
[[nodiscard]] inline auto find_game_dir(const std::optional<std::filesystem::path> &explicit_dir = std::nullopt) -> std::optional<std::filesystem::path> {
const auto qualifies = [](const std::filesystem::path &candidate) {
std::error_code ec;
return !candidate.empty() && std::filesystem::is_directory(candidate / "Data", ec);
};
if (explicit_dir && qualifies(*explicit_dir)) return explicit_dir;
if (const auto *env = std::getenv("RA3_GAME_DIR"); env != nullptr && *env != '\0') {
const std::filesystem::path candidate{env};
if (qualifies(candidate)) return candidate;
}
const std::filesystem::path default_dir{"C:/Red Alert 3"};
if (qualifies(default_dir)) return default_dir;
return std::nullopt;
}
/** Every `Data\*.big` archive in an installation, sorted by name. */
[[nodiscard]] inline auto list_archives(const std::filesystem::path &game_dir) -> std::vector<std::filesystem::path> {
std::vector<std::filesystem::path> archives;
std::error_code ec;
for (const auto &entry: std::filesystem::directory_iterator(game_dir / "Data", ec)) {
if (entry.is_regular_file() && entry.path().extension() == ".big") archives.push_back(entry.path());
}
std::ranges::sort(archives);
return archives;
}
} // namespace ra3::assets