A Post-Mortem on Byte Size
Byte size is a checkpoint saving and loading system that was created in a little over two weeks. As a group, we were given this project to save out and load components, although we were individually responsible for what data of our components were to be saved and loaded. In this post, I’m going to break down the development process and look at the key events, how those events impacted the project and what I’m going to do differently for next time.
Planning/designing the project
During the planning of the project and how we were going to go about implementing this project we didn't really discuss all the available options and the pros an cons of them. We just chose a method and discussed how we'd implement that and decided on that. For instance, for the file extension of which we had free rain to decide any, we chose XML, and XML is quite great for this purpose of neatly saving data it's not the fastest and in the end, I believe that's what we needed.
During this process, I believe that we didn't explain what we planned on implementing in enough detail and what was said, was then not implemented into the TDD so, for me, this discussion might as well not have happened. I believe the bulk of the blame for that was on me. When I clear as day saw holes in the plans I didn't speak up and that left me and possibly other team members, not in the loop of what we're planning on creating as a team.
I also know I should have contributed to the discussion more, now that's because of the fact that I was in uncharted territory and had no clue how we'd go about this project, which is, from my point of view, a fair excuse. Although as I said I should have said and made the team aware that I was confused and where so we could further explain the project in more detail.
Going forward I need to not be afraid to announce to my team that I'm confused, and when I see that was said in the discussion wasn't implemented into the technical design document, communicate to resolve that issue. By doing this it would have made the process of the project smoother by planing it out more and covering all bases.
Developing a TDD
As I mentioned before the Technical Design Document, at the start of the project, wasn't even really a TDD, we, well most of us, had just defined what data we were going to save out and that was it so when I came to implement the base saving and loading functionality, I had no idea of what to do.
The TDD didn't really look like a TDD until the project was coming to an end, which was after I implemented the base of the saving and load and I now knew what we were going to do because we already did it.
Making the TDD after the chunk of the project was completed defeats the purpose of a TDD. A TDD is something to be followed, not to ignored and filled in later after the fact.
I'm not sure why we didn't fill it up with literally what we discussed amongst each other. But we definitely should have pushed to get those discussed plans down in the document.
In the future, we should as a team makes sure what was planned is written into the TDD with little to no assumptions left to be made when implementing based on it. If we did do this it would have made the next step in the process a lot of a smoother and faster experience.
Our next task after the "completion" of the TDD, was to make our own individual little test script(s) and implement a hacky prototype of the saving and loading, and you bet I did that and made it especially hacky.
The saving and loading, at the time, was working by a thread and I couldn't get it saving out to XML working, let alone loading from it, so I scrapped the XML part and for now and just got the relevant data saving out and loading within the scene.
Since I chose to save out Rigidbody2D and Particle System, I originally saved out data I thought was necessary, my approach to picking what data would save was looking at the potential variables I could save out and thought which variables could possibly change at runtime during the game. For instance, obviously, velocity would change so I definitely need to save that, though with mass I've never changed that at runtime but I could imagine that it could be possible so I saved that out too.
In hindsight, I know that at this time, I wasn't saving out the child objects only the parents. Of which, the thing is with particle systems you add sub emitters as children or whatever so they wouldn't save out at that time.
Another thing I noticed at the time was that the particles weren't completely returning to the state that they were at the time of the save, which was something I wanted to achieve.
The take away from this is yet again I'm going to mention having a TDD at this time would have made it a lot easier, and less hacky.
Final class setup
After making the hacky prototype and getting everything working it was time to make it way better and more easier for others to add in their data, and so I made my existing test class do just that. To do this I added a DataContainer class that holds a string for the identifier of the object and then a dictionary that stores all the relevant data for the given object that's being passed through to be saved. This dictionary was made to storing basically a list of System.Objects which is what all variables are derived from so you could store any data type in there, you'll just have to cast it a specific variable type when you're loading it out.
At this point I still hadn’t set up the XML, but I got the base of it working really well, and this set up would be great to have other people drag over their component data, they only thing that was pointed out to me that needed to be changed was the use of strings as the keys of the dictionary, having them as string can very easily lead to miss spelling the key and getting an error thrown, and miss spelling strings is one of those error that you least expect to be the cause, so as recommend an Enum set up would be beneficial.
After I got this set up working and doing the thing, the other members of my team agreed that this system would be the best method, so My next step was to transfer my existing code over to the main non-test scripts and get it working with that which was relatively simple, after that I got the enum going instead of the strings and it was up and running, ready for the others to transfer over their data, after that we just need the xml going with it and a good example scene to test that save and loading fo all the components.
Theirs no real negative aspect to learn from in this aspect of the project, so I think just in the future I need to make sure to make hacky prototypes and then come in and not be afraid to ask for help to make whats already their better, cause without doing that it would definitely still be hacky.
Building an example scene
After making a saving and loading system, you need a good scene to show that off. We all made our own scene that demonstrates only our components and so with all of our individual stuff coming together, we needed a scene that demonstrates all of our components saving and loading data.
My first thought was to just drag in an old project that has stuff like objects moving and particle effects and persistent sounds and then be done with this task, an easy one checked off the list. So I did just that I used my project from about 6 months ago and avoided looking at my old uncommented code at all cost, cause I know how I was. I did that and pushed it to the master repository and finished the task. Then later that day I copped an ear full from a teammate about it being a 500mb push they had to pull on a train with a spotty connection (In hindsight, I seemed to have a role of contributing too much memory to the project which I find funny due to the name of the project). I had no idea it was that big of a project which was an oversight on my part.
After that conundrum, I thought my team member had a fair point and so I made a new example/test scene and scrapped the old one from the project. This new scene I wanted to make it a museum that had displays of examples of different components saving and loading, and the name of what the display is demonstrating and who was responsible for that component. This scene turned out and really nice and was a tenth of the size which was better and the team agreed too.
In future, I need to definitely be more careful about what I'm pushing. In the past, I've only stopped myself from pushing if it had an error with it, but going forward, I need to be careful of what I'm pushing in general, especially the size.
Changing class setup for XML
After spending a rather long time setting up the final structure of the classes that worked wonderfully, it was about time to get the XML in the project, and XML hated it. It would complain about not having a default constructor because we were passing through a game object as a parameter to save its data. It was also complaining about having a static class, and so much more.
After spending maybe 3 hours stubbornly trying to get it to work. I came to the realization that I've done more than my fair share of the project so I'd thought I would pass this beauty off to a team member, and share some of the workload. I already know this member has past experience in saving and loading and he told me he likes this kind of stuff (what a monster), and I did and as he was doing it he saw my struggle.
Although due to this we had to refactor a very large amount of the classes to get it to work with XML.
Once the XML was finally working with us, we had saving working but not loading at this stage. When we all saw the sheer amount of data that was being saved out, lets just say it wasn't bye size, at all, I knew straight away that it was me and the way I was saving out every individual particles data including such things as, its position, velocity, color, and so so much more. It was something like five times the amount of data due to my particle saving, and the XML file was 600-700 THOUSAND lines long.
This amount of data saving lead to their being 2-5 second freeze when saving and loading (differs on the amount of data and if there's a particle system in the scene of course).
Although the particles returning to exactly the way that it was when saving was really cool it was perhaps a bit overkill. I think if we used a different file extension, perhaps a binary one, it would be a lot faster and wouldn't have that huge lag spike, or just have a loading screen appear during the loading/saving.
I think the blame as to why we had to restructure the code for this implementation was because of how it was first laid out - with little knowledge of how XML works, and with little planning, yet again having barely anything on the TDD screwed us over again.
The take away from this one I think Is to not be stubborn over getting something to work if it isn't working I should either ask for help or delegate the task to some I think more capable of completing it. Also researching more into how XML works, in the beginning, would have prevented the issues with implementing it - building a system with XML in mind, instead of try to jam it in later with what's already there.
For the project wrap up, I got the chance to get to know how to make a package in unity, and it was way more simple than I thought. Before I could do that I first had to clean up the files and clean up the code where possible.
The cleaning of the files was relatively simple, I just had to remove script we weren't using or were empty, order the example stuff and the core functionality of the checkpoint system into different files.
In conclusion, after 2ish weeks, four others and I made a really cool system that will be easy to implement into a future project and through doing that I learnt a lot that I can put into practice in the next project.
More on that later.