Skip to content

yo-ru/rhmParse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rhmParse

A small C++17 library that parses and encodes Rhythia map files.

  • Single header + one .cpp (plus vendored miniz for ZIP/DEFLATE). Drop into any project as a submodule.
  • No external dependencies beyond the C++17 standard library and the vendored miniz amalgamation.
  • Round-trip-safe. Bytes that parse will re-encode with identical metadata; audio and cover payloads are preserved verbatim.

File layout

include/rhmParse/rhmParse.h     # public API
src/rhmParse.cpp                # implementation
src/miniz.h, src/miniz.c        # vendored ZIP/DEFLATE (public domain)
examples/dump.cpp               # print a map's contents
examples/roundtrip.cpp          # parse + re-encode and verify
examples/convert.cpp            # convert between .rhm and .sspm
CMakeLists.txt                  # optional, for add_subdirectory() users

Integration

As a git submodule (recommended)

git submodule add https://github.com/yo-ru/rhmParse third_party/rhmParse

Then add third_party/rhmParse/src/rhmParse.cpp and third_party/rhmParse/src/miniz.c to your build's source list and put third_party/rhmParse/include/ and third_party/rhmParse/src/ on the include path.

Via CMake

add_subdirectory(third_party/rhmParse)
target_link_libraries(my_app PRIVATE rhmParse::rhmParse)

Plain build

g++ -std=c++17 -I include -I src src/rhmParse.cpp src/miniz.c my_code.cpp -o my_app

Usage

#include <rhmParse/rhmParse.h>
#include <fstream>
#include <iterator>

std::ifstream f("map.rhm", std::ios::binary);
std::vector<uint8_t> bytes((std::istreambuf_iterator<char>(f)),
                            std::istreambuf_iterator<char>());

rhm::Rhm rhm;
if (!rhm::Parse(bytes, rhm)) {
    fprintf(stderr, "invalid map\n");
    return 1;
}

printf("Title:  %s\n", rhm.map.title.c_str());
printf("Notes:  %zu\n", rhm.map.notes.size());
printf("Audio:  %zu bytes\n", rhm.audio.size());

// Re-encode (for editing or repackaging):
auto encoded = rhm::Encode(rhm);

See examples/dump.cpp for a complete CLI utility.

API

Symbol Purpose
rhm::Rhm Top-level record: map, audio, cover.
rhm::Map Decoded map JSON: metadata + the note list. Nullable JSON fields use std::optional.
rhm::Note One playable note (time, x, y).
rhm::Parse(bytes, out) Decode bytes into an Rhm. Returns false on truncation/malformed zip/invalid JSON.
rhm::Encode(rhm) Encode an Rhm to std::vector<uint8_t>. Writes map always; writes audio and cover only when they're populated.
rhm::FromSspm(bytes, out) Decode an SSPM v2 file into an Rhm. Non-ssp_note markers, requires_mod and the sha1 hash are dropped.
rhm::ToSspm(rhm) Encode an Rhm as SSPM v2 bytes. The difficulty_name custom field, audio, and cover are preserved; RHM-only metadata (onlineId, onlineStatus, audioFileName, imagePath path strings) is dropped.

All API surface is documented inline in rhmParse.h.

Wire format

A .rhm is a ZIP archive containing:

Entry Required Contents
map yes UTF-8 JSON: metadata + the note list
audio no raw audio bytes (typically MP3); omitted when the map ships without audio
cover no raw image bytes (typically PNG); omitted when the map has no cover

The map JSON, in the canonical field order the game emits:

{
  "OnlineId":             null,     // or int - ranked / uploaded map id
  "OnlineStatus":         null,     // or string
  "LegacyId":             "string", // stable SSPM-style id
  "SongName":             "string",
  "Mappers":              ["string", ...],
  "Title":                "string",
  "Duration":             0,        // ms
  "Difficulty":           0,        // preset slot
  "CustomDifficultyName": "string",
  "StarRating":           0.0,
  "Notes": [
    { "Time": 0, "X": 0, "Y": 0 },
    ...
  ],
  "AudioFileName":        "string",
  "ImagePath":            null      // or string - null means no cover
}

Note coordinates lie on the standard Sound-Space-style 3x3 grid (typically 0..2); some maps use fractional offsets, so Note.x and Note.y are floats.

License

MIT. Use freely; attribution appreciated but not required.

The vendored miniz (src/miniz.{h,c}) is in the public domain.

Credits

The .rhm container and map JSON layout were reverse-engineered from maps exported by the official client. This library is an independent reimplementation; no game code is reused.

About

C++17 parser and encoder for Rhythia map files.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors