In the previous part of the series, we rebuilt the game client in C++. Now we crack on with the real reason we bothered to do that - client-side prediction. Currently the "game" only really works with close to no latency (i.e. client and server running on the same machine or network). Now is the time to introduce some artificial lag, dealing with that lag is really where netcode gets interesting.Read More
In the previous part of this series we had an outline of an online game with a fixed tick rate, and support for multiple clients to connect and move around. In this part we bin the horrible client made in Unity, and implement one in C++. You can browse the repository at this stage of development here.
The reason I want to rebuild the client in C++ is that for upcoming work on client-side prediction, we'll need the server and client to have a certain amount of shared code. It's possible to re-implement this shared code in C# for the client, but it would be easier to maintain if we just had one codebase written in C++. Plus I just prefer doing stuff in C++, so there.Read More
In the previous part of this series we ended up with a basic outline of an online game with some very simple game logic, with a fixed tick rate, and support for a single connected client. In this part, we'll be adding support for multiple clients. You can see the repository as it was at this stage of development here.
The first thing we'll need is to actually keep track of the clients who send the server packets. At the moment we store their IP address and port we get from recvfrom, but now we'll need some kind of list of IP addresses and ports of the clients so they can be sent state packets en masse. For this I created an IP_Endpoint struct:Read More
The previous part of this series was at best the "Hello, world!" stage of an online game. Now it's time to actually start actually laying the groundwork.
The Input Loop
Back in the day when multiplayer games were only played on a LAN, the clients would collect their user input, and send it to the server. The server would wait until it had the input from all clients, and then tick the game simulation, and send back the new game state. This is viable on a LAN because latency is so low, but it's not workable today, input lag of even a hundred milliseconds would feel sluggish, let alone two or three.
For now, I'll be doing LAN-style netcode - don't worry, it shouldn't remain like this for long, but it'll help simplify things at this early stage.Read More
I write netcode because I love it. The problems that have to be solved in online games are particularly interesting to me - how to hide lag, how to replicate game state, how to compress data to save bandwidth, etc. I've spent most of my career working on multiplayer games of one sort or another - I built a couple of MMO clients at an indie startup, I was part of the online services team of Total War: Arena, and most recently I was on the network team for Halo Wars 2 DLC. My work has always been confined to just the client, or just services, or just some particular area. It's a necessity of modern game development that you can't do everything (or even some of everything), unless you're at a really small studio. I'd like to though, so I'm going to try to do it in some small way, and write about it here.Read More
TL;DR - I wrote a multiple-producer multiple-consumer queue without any mutexes, it's pretty fast, GitHub.
About a year ago, a colleague was explaining why Erlang is so scalable, and it essentially comes down to a lack of shared memory. When you have two or more threads which share a section of memory, then whenever a thread is writing to that memory, no other threads can perform a read or write at the same time. This can result in code spending too much time waiting for the shared memory to be available for reading/writing, and therefore poor performance.
Communication between threads in Erlang is instead achieved using a message queue. Each process has it's own queue, and other processes can add messages to it. This sounded to me like a great model for concurrency - each thread only writes its own data, and any inter-thread communication is strictly done through a message queue. I wondered if I could create a similar system in C++. My colleague told me someone already did, and it's called Erlang, but at present I'm enjoying C/C++ a little too much to use anything else.
I figured that mainly what this needed was a high performance concurrent message queue. In theory it would be the only point of thread synchronisation, and therefore any concurrency-related bottlenecks would happen there. I knew shared memory was slow because it involved waiting for a mutex to lock, so what about lock-free concurrent data structures I'd heard vaguely about?
For a data structure to be lock-free, it needs to allow multiple operations to happen at once (e.g. one thread adding an item to a queue, while another removes an item). If one of those threads was to be suspended part-way through, it must not stop the other(s) from finishing what they're doing.Read More
Mono is, in my view, a potentially great option for game scripting. Perhaps the most obvious example of this in action is the Unity game engine, and there are a number of benefits to Mono over, say, rolling your own scripting language:
- Nice IDE's like Visual Studio and Xamarin, with code completion and all that good stuff
- The Mono Soft-Mode Debugger makes it easy to step through code in an IDE
- It's (relatively) fast, i.e fast for a scripting language
- C# is type-safe, but easy to learn, a lot of people know it, and there's plenty of learning resources on the web
- .NET interface can be used by modders
So I started to play around with embedding Mono, and providing a way for C# code to call code in a C++ application, a bit like this:Read More
Have you seen JB Evain's talk at Unite? If you haven't, then you probably can't, as it has been inexplicably taken down. The subject matter is mostly about using a library called Mono.Cecil to actually alter a .NET assembly, allowing for both injecting and removing code. This gives us the ability to create C# post-processors which operate on the compiled assembly, not the code files. I've been writing some pretty repetitive code of late, and so I figured I'd try using this approach to simplify things. There is a problem with this though - there isn't an "on assembly built" event in Unity that we can hook in to.
- Compile our code to a managed DLL, and set up Visual Studio to run the assembly post processor on it before placing it in the output directory.
- Hack it up.
One of the things I really hate is a shitty workflow, and (at least at the moment) I find using managed DLLs in Unity to be conducive to exactly that. For example, if I double click on a message in the console, it won't open the file in my IDE like it does when I'm letting Unity compile everything for me. In addition, I'd like to have the option to distribute what I'm working on as an Asset Store editor extension, and imposing upon users that they must compile their code to a managed DLL and import it into their project is pretty much out of the question if you ask me. So, I opted for option #2.Read More
After I haven't posted anything for what seems like forever, this will be just a short one. I've been interested in Bitcoin and cryptocurrencies for a couple of years now, and I've played around with the blockchain.info API recently, and decided to make a visualiser in the same vein as BitListen and so on. New transactions create an explosion of fireworks, the bigger the amount transferred - the bigger the explosion.
If you're making a multiplayer game in Unity and your networking model includes a fully authoritative server, you might have found movement to be a bit of a stumbling block. Client-side prediction is how lag tends to be hidden, Glenn Fiedler has an awesome series of articles, this one explains client-side prediction nicely.
To summarise - clients send their input (e.g. key presses) to the server which computes their updated position in the game world, and sends it back to them. To hide the lag, the client runs the movement code locally, and records its input and position each frame. When an update is received from the server, it looks through all the recorded positions and compares it with the data received from the server. If the two are out of sync by too large a margin, it retrospectively corrects the client by moving them to the correct position, and then runs through all the stored inputs, replaying the users actions up to the present time. This "rewind and replay" system is fine under certain circumstances, but a big problem in Unity is physics.
For about two years I've been developing a Unity multiplayer FPS on and off. Naturally, players can run about, jump up and down, collide with objects, and so on. I have no way of triggering the Rigidbody component on the player to simulate a frame, so I can't rewind and replay can I? Well I can, if I roll my own basic Rigidbody class:
It's been quite a while since I've programmed in AS3, but something I found quite useful for communication between SWFs was the LocalConnection class. The SWFs don't need to be on the same page, or even the same browser. I suspect that the BBC iPlayer desktop application (built with AIR) uses this under the hood to trigger a download to start when you click the download button on the iPlayer website.
LocalConnection itself is fairly crude, it can listen for data coming from any other LocalConnection which knows its connection name, and it can send data to any other LocalConnection by name. There's no mechanism built in for knowing where received data had come from, that has to be implemented yourself. A quick code example:Read More
A problem for a fair few Mono and .NET developers is "what if the user doesn't have Mono or .NET installed?" You can bootstrap the .NET installer into an .msi installer, but if you really need to just zip up a few files and send them to someone, and have your application just work, then you might need mkbundle.
Mkbundle is a great tool included in the Mono framework, which allows you to embed the Mono runtime with your application, into a single executable. On OSX you can just use MonoMac (especially if you want to distribute something on the Mac App Store), but on Windows we'll need to crank up the good ol' command line!
Right, the first thing to say, is that on Windows, mkbundle is sort of broken (at least in Mono 2.10.5 which I'm using), the code is pretty straightforward, so I might have a go at patching it up if I get some time in the next few months, I've never contributed to an open-source project before, first time for everything. Anyway, here's the list of workarounds I had to use to get an application to bundle and run:Read More
I recently had an unusual amount of difficulty just loading an embedded resource in a MonoDevelop C# project. I couldn't find a great deal of useful information through googling, and in the end found out how to do it by looking through the GTK# source code of all things. So for anyone else wondering, here's how I achieved it:
Select the file in the solution viewRead More