# funny chart format File extension: .bvcf (binary VSRG chart format) allright so, basically: multi-byte fields use little endian - Name: Something that anyone with two braincells can understand the meaning of - Size: Either measured in bytes explicitly, or with ?; i use nb format even if it's only bytes because why tf not and you cant stop me - Type: Standard stuff - Notes ptr: See the Notes section, the relevant field has a good description. ### Main format: | Name | Size | Type | Notes ptr | |------------|:-----|:-----------|:----------| |Magic bytes |8b | Literal string "vsrg :3\0"| n/a |Version |1b |uint8 |1 |Lanes |1b |uint8 |2 |Note count |4b |uint32 |3 |Seek table ptr |8b | uint64| 9 |Seek table dist| 2b | uint16| 11 |Notes here |? |Array\|4 |Seek table | ? | Array\ | 10 ### Note object: | Name | Size | Type | Notes ptr | |------|------|-------|-----------| |Type |1b |uint8 | 5 |Lane |1b |uint8 | 6 |Time |4b |uint32 | 7 ### Long note subclass: If Note.Type is 1: | Name | Size | Type | Notes ptr | |---------|------|----------|-----------| |End Time |4b |uint32 |8 ### Seek table entry: (this is fixed size so you can just do multiplication with this struct's size to get the offsets relative to Seek table ptr) | Name | Size | Type | Notes ptr | |-|-|-|-| |Note pointer | 8b | uint64 | 12 ### Notes: 1. 256 possible versions should be more than enough lol, and at that point we could just have the final version have subversions and we can just stack that to infinity xD 2. how many lanes this chart has, **make sure to match the type with `6`** 3. i was thinking of having a byte that is the length of the next number, basically letting us represent any number to `2^(256*8)`, which is more massive than energy's. uint32 will have to do lol 4. and by array i mean just fucking dump every single struct after each other lmao 5. 0 if normal note, 1 if long note, anything else is custom idgaf. Pretend this is 0 for the base Note object. 6. this represents what lane the note goes into *(read 2)*, I know we could be doing half bytes or even like 3 bits (i pretty much always do 4k gameplay lol), but it's easier to work with full bytes, plus it dosen't waste that much storage.... (flashbacks to fnf using json) 7. Times are in milliseconds. 8. time at which you should stop holding the note, same format as 7. 9. Byte offset for the seek table so a parser can just jump. By convention that i pulled out of my ass pointers should be uint64. this must point to the first valid seek table entry. 10. by ST i mean seek table duh, *(read 9)*. If this and ST dist is 0 then the seek table does not exist. 11. Distance between notes in the seek table, if this is 4 then every 4th note gets put here, etc.. I'm considering multiplying this by some constant to both kill off psycopathic usage and save on the other byte. Set this to something high like 512 /srs, anything lower than 256 and i will murder you cutely /s; **Subnote:** if bool(ST dist) xor bool(ST ptr) then the data is invalid and the parser should scream at you 12. *(read 9)* Pointer to the start of the note. Yes this is a security annoyance. Yes im going to piss off the parser devs. (yk this is optional for yall to implement right?) this entire table exists because notes aren't fixed size D: (i could probably put in 4 unused bytes so that the entire ST is useless but then that fucks over extensibility because now the note with the fattest struct bloats everything else)