This was supposed to be posted march 29th, but I kind of got distracted halfway through and never finished writing it, so I've merged today's post with the leftover of that post!
Personal
I GOT AN OFFER LETTER.
I haven't accepted yet for some small reasons I'm getting sorted out, but holy shit. This is actually happening. I still need to do salary negotiation (hopefully it's not too late for that -- fun fact, even what they offered me is more than 2x what I'm making now) and they're flying me out to visit before I have to decide, which is great.
I'm taking a cursory look at apartments so that I can hopefully arrange visits while I'm there. Holy shit, I can't wait to have more than a single room to my name and maybe more than a single counter of space.
Tech things
Had to look at the previous post to figure out where I left off.
So as I previously mentioned, the improvement mod already has a lot of the binary file mapped out. There is one problem though: they skip the first 8 bytes of the file. For their intents and purposes, it's irrelevant.
But, turns out the first 2 bytes are super important for both replay.dat and replay_list.dat files: they're checksums. I was struggling with that a bit, but had the feeling that this was, again, a solved problem since if they can decompress and substitute BBCF data files, they've gotta have figured out how to spoof checksums.
Thankfully I stopped being a shy nerd and just went ahead and explained where I was stuck in the modding discord, and sure enough a prominent developer nearly immediately gave me a solution:
public static ushort CreateChecksum(byte[] data)
{
uint x = 0x0;
for (uint i = 0; i < data.Length; i += 0x2)
{
var y = (uint)((data[i + 1] << 8) | data[i]);
x += y;
y = x;
x &= 0xFFFF;
y >>>= 0x10;
x += y;
}
return (ushort)~x;
}
To use this function I just zero out the first two bytes and then it'll replace the first two bytes with the checksum. I really want to ask him how he figured this out, but I'll do it later because seems like he's dealing with some stuff right now.
To-do
I can now read in a replay_list.dat file and pull header information for all of the involved replays, but I need to write code to rewrite a particular header entry.
I also need to write code that given a directory of replays, reads in the headers from all of those replays to pull out some info to show to the user (so they know what replays they're loading in) and prepare to substitute into the replay_list.dat file.
I also need to write code that backs up the replays before copying in the old ones, and a button to revert changes. Same deal for backing up replay_list.dat before overwriting it, and reverting it.
I also want to explore the headers in replay_list.dat a little bit more -- in particular, it has to have stage/music information in the header and I want to find where that data is stored. My plan to find the relevant bytes is really straightforward. Stupid, even.
I'm going to twiddle bytes by adding +1 to each of the unknown padding bytes one-by-one and seeing which ones cause the stage/music to change. :^) Then I can try to figure out whether they're just integer IDs or some more complicated representation.
Something important I gotta keep in mind is that if I want to do this exploration, I might want to strip out the file reading code into a library. That way I can actually write a console app that mucks around with the file info without having to make a UI or doing jank things in the UI app (on launch it makes change x to file y). This might be a good idea to do anyways because my friend suggested I make this program with WPF, not forms, if I want to make a really nice UI. (e.g. show character portraits, like in the replay theater.)
Actually, my friend just pointed out that hex editors exist. So I might be able to just use one of those to manually toggle that information, though I might still want something to update the replay_list.dat file.
C
I'm so rusty with C#. It's been forever since I've had to code in it. Thankfully my friend is very patient and enjoys explaining things.
Part of the funny bit of all of this is I'm terrible with vocabulary usage, so he keeps having to correct my use of words to make sure I describe things correctly. For example, he's made the following to stress the difference between an Attribute and a Member, and the difference between a Property and a Field.
// Declared as "ExampleAttribute" - is an attribute that can be attached to a class.
[Example]
public class SomeClass
{
public string Name { get; set; } // Property; also a member of SomeClass
private string Title { get; set; }
public int Number;
private int _id; // Field; also a member of SomeClass
private readonly int _anotherNumber;
public void DoTheThing() // Method, also a member of Some Class
{
// ...
}
}
It's also been strange getting used to coding in a strongly-typed language again. For example, it's more appropriate to use the shortcut var rather than re-typing the type here:
using (var ms = new MemoryStream(bytearray)) {...}
In python you'd HAVE to declare the variable ms as a MemoryStream, as otherwise autocomplete and the limited type hinting would have no idea what it is.
Other
Lol I still haven't fixed my pagination. Oops.