Skip to main content

Rei Blog Post 6



We are back after a long break, while Matthew was able to work on the project over break, much of my time was taken by my job. I then developed the flu, so the time I was able to work was much less then my partner's. Anyway, now that we are done with excuses, lets talk about what I have been working on.

Now that I have recovered a bit more and am capable of working again, I have begun work on a replay parser. We have spoken about replays in the past however, I would like to take the time here to really go in depth about how replays store information.

Rivals of Aether makes out job parsing replays much easier by storing replays in plain text format. With some help from the RoA community we have been able to break down what a lot of the symbols mean. I am going to go in a little more depth about what data we can extract from the file and why we care about it.


Line One

The first line of the file contains basic meta-data about the replay itself. The line is formatted as follows.

'is the replays starred? || Version of replay || Date and time of the replay || formatted date-time '

The data that we are really looking at here is the version of the replay, because replays can only be played on the version they are "recorded" in, we need to separate our replay files into batches by version.

Matthew talks more about how we broke up the files in their post.


Line Two

This line contains information about the rules of the game. The line is formatted as follows:

'stage type || stage id || stock count || time limit || team switch || friendly fire switch || online play? || p1 information || p2 information.'

at this point in time, it is difficult to know what of this we will need. The stage type and stage id will be useful for further breaking up the batches, it is possible that the AI will associate techniques with stages so this information may be useful. The stock count will most likely also come into play. But until we see our AI play, it will be hard to know.

Replay Lines

The first two lines will always contain information in exactly this format, after this we get data that can vary. The next line will contain information about the player, if the line starts with an H we know the player is in fact human, the rest of that line contains information about the player, like what character they are playing and their color pallet. We do care what character they are playing, so we will need to extract that data.

 If the player is a human, then the next line will be all of their input data from the game. The fact that this is all on one line means it will be incredibly easy to pull out from the file, just doing a read line will allow us to have all that players inputs. Where this process gets messy is breaking up the inputs into readable tokens. The post where we got most of this data from has a handy chart to help us match data with input, I will include it below, but I will also link the original post here.

The number to the left of a letter is the frame that an input takes place on.
The first frame that a player can take action on is frame 126.
An uppercase letter means that a button is being pressed, and a lowercase button means that a button is being released.
Tapping a direction only has an uppercase variant and only lasts for one frame.
Aa=attack
Bb=special
Cc=strong
Jj=jump
Ss=dodge
Ll=left
Rr=right
Uu=up
Dd=down
E=tap left
I=tap right
M=tap up
O=tap down
Ff=fstrong to the left
Gg=fstrong to the right
Ww=Dstrong
Xx=Ustrong
Zz=Enable or disable angles for airdodges and specials
y  0=angled right
y 90=angled up
y180=angled left
y270=angled down

These lines will repeat until we fill up all the player slots, or until we run out of players.


because there are no spaces between inputs, but spaces appear as part of inputs, it will be a bit more difficult to parse in these files then we hoped. The main trouble here comes from the y inputs, because the three. numbers after them do in fact count as part of the input. If this was not the case, we could just use the letters as breaks.

We will also need to really focus on syncing this input with the images coming in from SerpentAI, which will be difficult.

The next couple of weeks will be dedicated to working on the parsing and the syncing of data. 

Comments

Popular posts from this blog

Rei - Blog Post 10

So,  I missed blog post 9. This is me acknowledging that for consistency. Anyway, the past couple of weeks have been incredibly productive for ContentsMayBeHot. Matthew has finished collecting all the replay data, we have refactored our project to reduce complexity, we have improved the runtime of our code, and finally we have started seriously training our model. The Changes Matthew implemented multi-threading for the model loading. Which reduced our load time between files from about 3-5 Seconds to 1 Second or less. Which allows us to fully train a model in much less time! While Matthew did this I reduced the code duplication in our project. This way, if we needed to change how we loaded our training data, we didn't have to change it in multiple places. This just allows us to make hot-fixes much more efficiently. We also started working on some unittests for our project using pytest. These tests were written because of a requirement for another class, but we thought it

Matthew - Blog Post 8

replaymanager.py is only 339 lines long but it feels at least three times that when I'm working on it. The module is definitely due for a refactor. For one, the term subdataset should be renamed to version_set and extracted into a class. version_set more accurately and describes what it is, and the class extraction would clean up the namespace in ReplayManager. There is probably some kind of class extraction possible for replays, so that their names, paths, file streams, and Twitter profiles can all be neatly encapsulated, thereby cleaning up the namespace even more. However, I do not want to worry about having two kinds of replays: the one used by ReplayManager and the one used by ReplayParser. Even though ReplayManager does not use ReplayParser, the prospect of making things more muddier deters me. There's probably a right way to refactor this code, but, to put it simply, now is not the time. Speaking of time, I came up with a great way to get work done, even when I am slee

Matthew - Blog Post 7

Since January, we've been working hard to not only finish writing the Replay Parser and Frame Collector but also totally synchronize them. I'm pleased to report our success. This is an amazing milestone for us because it means that we've surmounted one of our most troubling obstacles. I have also made sure to keep our documentation up to date. So, if you like, you can follow along with this blog post by replicating its results. The Frame Collector uses timed input sequences to start each replay associated with the currently running game version. Then, after waiting a set amount of time for playback to begin, it starts grabbing 1/4-scale frames at a rate of 10 frames per second. The Frame Collector takes these down-scaled frames, which are NumPy arrays, and rapidly pickles and dumps them into the file system. Here's a screenshot of the Frame Collector in action: If you look at the image above, you'll see that each pickle (the .np files)