Straftat Was A 1v1 Game

Originally it was hard coded in many places to only support a server and a single client, and the code base is the closest thing to a house of cards I have ever worked with. But first I’m going to talk about how I first got involved with the project.

Getting Involved

The introduction

I found Straftat through somebody who posted a link to the game in the SLZ discord server while it was still just a demo. I played it a LOT I put 40 hours into it in just 4 days, most of that was frontloaded in the first two days, iirc I played it for about 20 hours in one day. It was really good. Something I have thought about since then is why I liked the game so much, and I think it came down to faster games with lower stakes. This is something that overlooked when making modern multiplayer games, with the industry trend of battle royales and extraction shooters I was not playing the demo to grind out gear or a battle pass, it was just genuinely the most fun.

After this I got into modding the game and was working on two main mods, a map loader and a core library mod. The map loader mod was to allow custom maps to be loaded into the game, hopefully downloaded at runtime from the ThunderStore API, didn’t get that far as I was more focused on the core library mod. The core library mod was to make it easier to make other mods, by providing a QOL and namely a lobby filtering system. The game at the time did not use ANY filters on the steamworks lobbies, so you couldn’t just host modded games without normal players joining them. So my mod would replace the steam lobby list and filter it out by the mods you had installed. It would also support mod makers marking there mods as compatible with the base game.

This system took inspiration from the Content Warning mod attribute, with a few notable improvements. The Content Warning attribute was a class attribute instead of an assembly attribute, meaning it took longer to find. I fixed that, this was negligible but still an improvement. Second it didnt have any way of handling compatible assemblies without the attribute, I solved this with dependency scanning. Meaning if you had an assembly without the attribute, but it was depended on by an assembly with the attribute labeled as compatible, it would also be considered compatible. This was important as some mods depend on common libraries like DiscordRPC.

During this time the developers where facing seemingly random lag spikes, I was contacted by one of the devs, Sirius Lemaitre, if I knew what the problem was. Unfortunately at the time I did not. I thought it could relate to graphics problems or something on Unities end, but without a profiler I couldn’t be sure. So I offered to help them out, wrote a “resume” and asked for source access. They agreed and I got access to the source code.

The first thing I needed to do was fix the git setup, as it was a mess. I spent a bit fixing the git ignores and cleaning up branches, after that it was ready for actual collaboration. (this proved to be a extremely good idea later on as it allowed for map creators to work on the project easily, something very important once talented showed up in the community interested in making maps.) Once that was done I started looking into the lag spikes, and I came up completely empty handed, until one of my Steam Friends with a level of 0 was online. That immediately caused the lag spikes to start to get worse. After some digging it turned out that the steamworks wrapper the game used (heathen steamworks) would create a coroutine to try to get the players level. On it’s own that wouldn’t be a problem, but the coroutine assumed a level of 0 was a failure, and instead of just ending the coroutine or reusing the same coroutine to try to get the info again, IT WOULD FORKBOMB ITSELF. Creating more and more coroutines trying to get the level, until the game was completely unresponsive. The fix was simple, just stop assuming 0 was a failure, and also fix the forkbombing. After that those lag spikes where gone, and the game was not randomly unplayable anymore.

After this I would occasionally fix issues that annoyed me or my friends. Until a few months later when I was asked to help with the four player update.

Working on the Four Player Update

I was contacted to help with the four player update as I had already done a lot of work on the codebase and was the only person other than Sirius himself with knowledge of the codebase having already worked on it for months. Most of the game was hard coded to only support a single client and a single server, so I had to go through and change all of these places to support multiple clients. This was made harder by the fact that the codebase is a mess, server/client scope was so difficult to track, and there was no consistent or good structure to the codebase. This was sirius’s first multiplayer game after all, and the use of Fishnet, a kinda alright networking library, didn’t help that. Especially since it was on Fishnet 3 and not the newer Fishnet versions, this makes it even more of an issue cuz the fishnet team doesn’t even provide the documentation for that version anymore and the discord recommends the use of the wayback machine to view it (utterly insane and unacceptable imo).

I tried to avoid making large sweeping changes to the code base and keep the scope of my changes as small as possible. I did this as I was not going to be around forever, and I wanted to make sure that the changes I made would be as easy to maintain as possible for Sirius. This meant documenting the systems I had written and making sure they kept the same functionality as before, just with more players.

The big systems that needed to be reworked where the lobby system, the score handling system, the player spawning system, and then making a new team system.

I had to rework was how the game handles steam lobbies as it was a very non-standard implementation that was extremely buggy. While technically functional it would often fail in numerous ways, and with more clients it would become a near constant failure point. I ended up rewriting the entire lobby system to be more standard and while doing that also implemented the mod filtering system I had made for my mod directly into the game.

Then it was score handling, that also needed a complete rewrite to support multiple clients. First it was just a simple system to allow for multiple clients to have their own score, but then later that got reworked to handle teams. This was the most enjoyable part of the entire update, as I got to design the system from the ground up and knew the scope of the changes I was making, avoiding the house of cards situation I was in before. The team system did need to touch a lot of the other code base to account for various things like friendly fire. Due to wierd fishnet source generation issues, inheritance breaks down and does not work properly with networking; that meant I had to go through each type of weapon and modify them all to account for friendly fire. If I had to come back to the project the weapon system would be the first thing I would rework, as it’s a mess and very difficult to work with and introduces a lot of bugs, but not so spaghetti-ed that it would be a herculean task to fix. The reason it’s such a mess is since it does not properly use polymorphism as fishnet’s source gen breaks abstract and virtual RPC’s in some really insidious ways.

But there’s two things that are far too spaghetti-ed to fix, the player controller and the UI, both of these are just a nightmare to work with and would need a complete rewrite and remake to be fixed. A rewrite of the player controller will never happen just because it’s such a massive task and would likely change its functionality in ways the players would hate. Making the changes to these systems to support four players was the hardest part as they are so intertwined with everything that a single change would require like 30 minutes of checking and testing to make sure nothing else broke, so I avoided it as much as possible, the key thing I needed to change was the way players spawn in and wait for the round to start. This system still has issues, but is better than before the update as it no longer gives the host a massive advantage by spawning and letting them move first. Rn there are issues with it keeping track of what players to spawn and if somebody connects or disconnects at the wrong time it can freeze everybody. Due to how Straftat handles Fishnet’s disconnect and connect logic this is very difficult to fix, and I’ve yet to nail down a fix that works in all situations ):

Of course, I was not the only person working on the update, Sirius also did a lot of the coding specifically related to the parts of the project I didn’t trust myself to not break. Not to mention the incredible work done by the map creators and Leonard.

Beta Test and Launch

So during the beta test I was mostly just fixing bugs that came up, and trying to make sure the game was as stable as possible (at least more stable than before). We ran the beta test through steams playtesting system rather than a beta branch because it was what Sirius was most familiar with. I think this was a mistake as it made it more difficult to let people into the beta, but overall it worked out fine.

The launch was incredible, we broke 1800 concurrent players on launch day, then peaked at 2200 concurrent players a few days later.

Working on Straftat was just an incredible experience, I got to apply the knowledge I had learned from maintaining and working on software to a game played by a quite a lot of people. Probably the most fulfilling project I’ve ever worked on, and I hope to work on projects that I actually ship in the future.