Why I shouldn't have made the game state static in Tempus
When I started working on Tempus I made the game state a static class like I usually do. The game state had a lot of stuff in it, like the console, match data, and connection info. This is typically fine if you have just a single player game.
However, my problems began when I tried to make Tempus multiplayer as I had planned from the start. The actual networking code wasn't much of a problem; there are loads of tutorials online about how to set up the server and a client so that they can talk to each other and I had already done so multiple times. However, I don't have much experience past that. There are relatively few tutorials on how to actually handle the design of your code so that sending data back and forth and integrating this data into the update loop isn't a pain. I often have problems implementing this code, but that's a different issue amplified by my poor choice of making the game state static.
The problem was that the player was supposed to be able to start and host a game, which meant the player could potentially run the server and the game client at the same time. Since the game state data was static, this meant that the server and the client shared the same game data. This was terrible because it made debugging difficult. It was like trying to separate two differently colored piles of sand in a box with no divider. I was difficult and increasingly frustrating as I attempted to continue and improve rather than refactor the code.
This ambiguous mix of what was server code and what was client code became a pain. In particular, I had a console in the game where I could execute commands such as "set cvar foo bar". In order to distinguish whether or not the server was executing the command instead of the client I basically had to litter a bunch of if statements in every single command where it mattered. Consoles are usually a good idea because they allow me to quickly test things in games, but in this case I couldn't be sure if the command was doing what I expected. Did "match set host Magikarp" set the host of the match to be Magikarp on the client, on the server, or both?
I could have separate commands for each case but they would all essentially do the same thing, increasing the potential for errors. On top of that, I would have to name all of them differently. I would have to use something like Hungarian notation, perhaps prepending "client-", "host-", and "both-" to each separate command. This is a terrible idea because there is no way to actually enforce at compile time that the command “host-match” actually only changes match data for the host. Also, on another note, that looks like it should mean I want to create a new match if I were the client. In addition, since the console was part of the static game data, I could not make that server command unavailable to a client.
A lot of problems started to pop up. I should have known better; I know about server-client game architecture and should have been doing that from the start. I eventually did end up refactoring the code, but the time I lost proved to difficult to catch up on as I ran out of time to complete the game for One Game a Month. I ended up having the cut the networking feature completely, something I had worked on for a little over a month, in order to finish in time. Even then, I was not able to complete the game to a point that I could be satisfied with.
Don't make game state data static.