0.0.0 • Published 5 years ago

yarnballs v0.0.0

Weekly downloads
8
License
Apache-2.0
Repository
github
Last release
5 years ago

yarnballs

Parser and writer for the "A Hat in Time" Nintendo Switch savefile archive.

Installation and Usage

CLI

$ npm install -g yarnballs
$ yarnballs -h

For playing with AHiT saves, the most useful commands are:

## create a new savefile from template
$ yarnballs -C "A Hat in Time GameState"

## update first save slot using a PC game save
$ yarnballs -u "A Hat in Time GameState" /w/DataChanges/HatinTimeGame/SaveData/slot1 save.hat

NodeJS

Install the module with NPM, then require:

const YARNBALLS = require("yarnballs");

Browser

Add a reference to the crc-32 library before referencing the script. The UNPKG cdn hosts scripts:

<script src="https://unpkg.com/crc-32/crc32.js"></script>
<script src="https://unpkg.com/yarnballs/yarnballs.js"></script>

See index.html, live at https://switchjs.com/yarnballs.html

API

YARNBALLS.parse(data) parses a Uint8Array, returning an array of entries

YARNBALLS.write(entries) generates a Uint8Array from the entries.

File Structure

People have explored the format. An example file generated by @leo60228 included a few questionable sizes. Since we were unable to reproduce the issues, they are not documented here, but the code includes logic to handle those cases.

Frame Structure

The file starts with the magic number 0x13 0x22 0xb2 0xe5 0xa8 0x04 0x10 0xdc

After that, a series of entry objects appear in the data. There is no padding between the objects.

The last 4 bytes of the file is a CRC-32 cksum of the magic and entries.

OffsetLengthDesc
08Magic Number 0x13 0x22 0xb2 0xe5 0xa8 0x04 0x10 0xdc
8size - 12Series of entry objects (defined below)
-44CRC-32 checksum of Magic + Entries

Entry Structure

There are two entry types, "files" and "folders", with magic numbers:

Entry TypeMagic Number
File0xb1 0xca 0x20 0x97 0xb4 0x81 0x00 0x00
Folder0x01 0xa4 0x20 0xb2 0xfd 0x41 0x00 0x00

Creation / Access / Modify times are stored in the Windows FILETIME format.

Paths are specified in the UNIX backslash style. Folder names do not include the trailing slash.

OffsetLengthDesc
08Entry Magic Number (see table above)
88Creation Time
168Access Time
248Modify Time
322Length of the Path in bytes (not including null)
34N+1Null-terminated Path (ASCII characters)

Files include additional data after the path:

OffsetLengthDesc
08Upper bound on data size (see "Game Details")
84Magic 0xe9 0xb7 0x12 0x3a
1212+(n)Data (n is less than or equal to the upper bound)

Game Details

The actual game presumes the folder /w/DataChanges/HatinTimeGame exists. Subfolders like /w/DataChanges/HatinTimeGame/Config are explicitly specified.

In test files that we generated, the individual entry data sizes were correct. However, there are test files where this is not the case. No information regarding version numbers are available, so in accordance with Postel's law we just do a linear scan for the next entry.

Credits

0.0.0

5 years ago