Contents
VSD2JSON
See the source code here: raineycat/vsd2json
About
This is just a small tool I wrote to dump the song information found in vivid/stasis data files, on account of the game using a proprietary binary format.
It uses binary-reader to help parse the format, and serde/serde_json to write it out in a sensible format.
In this post, I’ll refer to these song info files (song_information.bin) as VSDs, since that’s the magic number they use, and also how they’re referred to in the game’s code. These are not to be confused with other files that use the .vsd extension, since as far as I’ve seen nothing else uses this binary format.
The format
VSDs are very similar to chart files in structure, as the header and tagged chunk format are very similar.
---
title: Empty/simplest VSD file, not including the signature
config:
packet:
bitsPerRow: 48
bitWidth: 16
---
packet
+24: "Magic number: \"VSD\" (0x565344)"
+8: "Version: 0x01"
+8: "Null byte"
+8: "End marker: 0xFF"
After the header, the data is made up of tagged sections. Each tag is 1 byte, and the data after it has no fixed length. After all chunks are read, there must be a termination byte (0xFF).
There is also a 384 byte RSA signature after this, however at the time of writing this is never verified, so it can just be zeroed out.
The only top level chunk is a song info chunk, where the tag byte is 0xA0. This contains an arbitrary amount of song field (tag 0xA2) chunks, up to four chart info (0xC0) chunks, and has a 0xA1 terminator tag.
Each song info chunk has the following fields:
- The numerical song ID
- The textual song ID
- The song’s name
- The song’s name plus any formatting characters
- The song’s artist
- The jacket image’s artist
- The BPM value to display
- The chart’s version
- Whether an encore chart is present
- Whether the song is a vivid/stasis original
- Whether the song has been released
And each chart info chunk stores:
- The difficulty to display
- The actual difficulty value
- The note designer’s name
If you want to see the full logic behind reading the song data, you can see the code here. Otherwise, this is as far as I’ll go here to avoid this post getting too long.
Finishing up
As you can guess, having this in a simpler (and saner) format is very useful, (example: the tourney code maker on this site), which is why I made this tool.
The output JSON schema is detailed in the README, but it’s easy to transform it into whatever format you need.
For example, the nushell code I used to generate data for the code maker is:
open song_information.json | get songs | select song_id song_name song_artist charts | update charts { $in | where difficulty_constant > 0 | length } | save tourney_song_data.json
Anyway, bye for now, and stay silly™!