• # The Poor Man's Netcode

Networking and Multiplayer

The more you know about a given topic, the more you realize that no one knows anything.

For some reason (why God, why?) my topic of choice is game development. Everyone in that field agrees: don't add networked multiplayer to an existing game, you drunken clown.

Well, I did it anyway because I hate myself. Somehow it turned out great. None of us know anything.

## Problem #1: assets

My first question was: how do I tell a client to use such-and-such mesh to render an object? Serialize the whole mesh? Nah, they already have it on disk. Send its filename? Nah, that's inefficient and insecure. Okay, just a string identifier then?

Fortunately, before I had time to implement any of my own terrible ideas, I watched a talk from Mike Acton where he mentions the danger of "lazy decision-making". One of his points was: strings let you lazily ignore decisions until runtime, when it's too late to fix.

If I rename a texture, I don't want to get a bug report from a player with a screenshot like this:

I had never thought about how powerful and complex strings are. Half the field of computer science deals with strings and what they can do. They usually require a heap allocation, or something even more complex like ropes and interning. I usually don't bother to limit their length, so a single string expands the possibility space to infinity, destroying whatever limited ability I had to predict runtime behavior.

And here I am using these complex beasts to identify objects. Heck, I've even used strings to access object properties. What madness!

Long story short, I cultivated a firm conviction to avoid strings where possible. I wrote a pre-processor that outputs header files like this at build time:

namespace Asset
{
namespace Mesh
{
const int count = 3;
const AssetID player = 0;
const AssetID enemy = 1;
const AssetID projectile = 2;
}
}

So I can reference meshes like this:

renderer->mesh = Asset::Mesh::player;

If I rename a mesh, the compiler makes it my problem instead of some poor player's problem. That's good!

The bad news is, I still have to interact with the file system, which requires the use of strings. The good news is the pre-processor can save the day.

const char* Asset::Mesh::filenames[] =
{
"assets/player.msh",
"assets/enemy.msh",
"assets/projectile.msh",
0,
};

With all this in place, I can easily send assets across the network. They're just numbers! I can even verify them.

if (mesh < 0 || mesh >= Asset::Mesh::count)
net_error(); // just what are you trying to pull, buddy?

## Problem #2: object references

My next question was: how do I tell a client to please move/delete/frobnicate "that one object from before, you know the one". Once again, I was lucky enough to hear from smart people before I could shoot myself in the foot.

From the start, I knew I needed a bunch of lists of different kinds of objects, like this:

Array<Turret> Turret::list;
Array<Projectile> Projectile::list;
Array<Avatar> Avatar::list;

Let's say I want to reference the first object in the Avatar list, even without networking, just on our local machine. My first idea is to just use a pointer:

Avatar* avatar;

avatar = &Avatar::list[0];

This introduces a ton of non-obvious problems. First, I'm compiling for a 64 bit architecture, which means that pointer takes up 8 whole bytes of memory, even though most of it is probably zeroes. And memory is the number one performance bottleneck in games.

Second, if I add enough objects to the array, it will get reallocated to a different place in memory, and the pointer will point to garbage.

Okay, fine. I'll use an ID instead.

template<typename Type> struct Ref
{
short id;
inline Type* ref()
{
return &Type::list[id];
}

};

Ref<Avatar> avatar = &Avatar::list[0];

avatar.ref()->frobnicate();

Second problem: if I remove that Avatar from the list, some other Avatar will get moved into its place without me knowing. The program will continue, blissfully and silently screwing things up, until some player sends a bug report that the game is "acting weird". I much prefer the program to explode instantly so I at least get a crash dump with a line number.

Okay, fine. Instead of actually removing the avatar, I'll put a revision number on it:

struct Avatar
{
short revision;
};

template<typename Type> struct Ref
{
short id;
short revision;
inline Type* ref()
{
Type* t = &Type::list[id];
return t->revision == revision ? t : nullptr;
}
};

Instead of actually deleting the avatar, I'll mark it dead and increment the revision number. Now anything trying to access it will give a null pointer exception. And serializing a reference across the network is just a matter of sending two easily verifiable numbers.

## Problem #3: delta compression

Which by the way is here: gafferongames.com

As I set out to implement my own version of Glenn's netcode, I read this article, which details one of the biggest challenges of multiplayer games. Namely, if you just blast the entire world state across the network 60 times a second, you could gobble up 17 mbps of bandwidth. Per client.

Delta compression is one of the best ways to cut down bandwidth usage. If a client already knows where an object is, and it hasn't moved, then I don't need to send its position again.

This can be tricky to get right.

The first part is the trickiest: does the client really know where the object is? Just because I sent the position doesn't mean the client actually received it. The client might send an acknowledgement back that says "hey I received packet #218, but that was 0.5 seconds ago and I haven't gotten anything since."

So to send a new packet to that client, I have to remember what the world looked like when I sent out packet #218, and delta compress the new packet against that. Another client might have received everything up to packet #224, so I can delta compress the new packet differently for them. Point is, we need to store a whole bunch of separate copies of the entire world.

Someone on Reddit asked "isn't that a huge memory hog"?

No, it is not.

Actually I store 255 world copies in memory. All in a single giant array. Not only that, but each copy has enough room for the maximum number of objects (2048) even if only 2 objects are active.

If you store an object's state as a position and orientation, that's 7 floats. 3 for XYZ coordinates and 4 for a quaternion. Each float takes 4 bytes. My game supports up to 2048 objects. 7 floats * 4 bytes * 2048 objects * 255 copies = ...

14 MB. That's like, half of one texture these days.

I can see myself writing this system five years ago in C#. I would start off immediately worried about memory usage, just like that Redditor, without stopping to think about the actual data involved. I would write some unnecessary, crazy fancy, bug-ridden compression system.

Taking a second to stop and think about actual data like this is called Data-Oriented Design. When I talk to people about DOD, many immediately say, "Woah, that's really low-level. I guess you want to wring out every last bit of performance. I don't have time for that. Anyway, my code runs fine." Let's break down the assumptions in this statement.

Assumption 1: "That's really low-level".

Look, I multiplied four numbers together. It's not rocket science.

Assumption 2: "You sacrifice readability and simplicity for performance."

Let's picture two different solutions to this netcode problem. For clarity, let's pretend we only need 3 world copies, each containing up to 2 objects.

Here's the solution I just described. Everything is statically allocated in the .bss segment. It never moves around. Everything is the same size. No pointers at all.

Here's the idiomatic C# solution. Everything is scattered randomly throughout the heap. Things can get reallocated or moved right in the middle of a frame. The array is jagged. 64-bit pointers all over the place.

Which is simpler?

The second diagram is actually far from exhaustive. C#-land is a lot more complex in reality. Check the comments and you'll probably find someone correcting me about how C# actually works.

But that's my point. With my solution, I can easily construct a "good enough" mental model to understand what's actually happening on the machine. I've barely scratched the surface with the C# solution. I have no idea how it will behave at runtime.

Assumption 3: "Performance is the only reason you would code like this."

To me, performance is a nice side benefit of data-oriented design. The main benefit is clarity of thought. Five years ago, when I sat down to solve a problem, my first thought was not about the problem itself, but how to shoehorn it into classes and interfaces.

I witnessed this analysis paralysis first-hand at a game jam recently. My friend got stuck designing a grid for a 2048-like game. He couldn't figure out if each number was an object, or if each grid cell was an object, or both. I said, "the grid is an array of numbers. Each operation is a function that mutates the grid." Suddenly everything became crystal clear to him.

Assumption 4: "My code runs fine".

Again, performance is not the main concern, but it's important. The whole world switched from Firefox to Chrome because of it.

Try this experiment: open up calc.exe. Now copy a 100 MB file from one folder to another.

I don't know what calc.exe is doing during that 300ms eternity, but you can draw your own conclusions from my two minutes of research: calc.exe actually launches a process called Calculator.exe, and one of the command line arguments is called "-ServerName".

Does calc.exe "run fine"? Did throwing a server in simplify things at all, or is it just slower and more complex?

I don't want to get side-tracked. The point is, I want to think about the actual problem and the data involved, not about classes and interfaces. Most of the arguments against this mindset amount to "it's different than what I know".

## Problem #4: lag

I now hand-wave us through to the part of the story where the netcode is somewhat operational.

Right off the bat I ran into problems dealing with network lag. Games need to respond to players immediately, even if it takes 150ms to get a packet from the server. Projectiles were particularly useless under laggy network conditions. They were impossible to aim.

I decided to re-use those 14 MB of world copies. When the server receives a command to fire a projectile, it steps the world back 150ms to the way the world appeared to the player when they hit the fire button. Then it simulates the projectile and steps the world forward until it's up to date with the present. That's where it creates the projectile.

I ended up having the client create a fake projectile immediately, then as soon as it hears back from the server that the projectile was created, it deletes the fake and replaces it with the real thing. If all goes well, they should be in the same place due to the server's timey-wimey magic.

Here it is in action. The fake projectile appears immediately but goes right through the wall. The server receives the message and fast-forwards the projectile straight to the part where it hits the wall. 150ms later the client gets the packet and sees the impact particle effect.

The problem with netcode is, each mechanic requires a different approach to lag compensation. For example, my game has an "active armor" ability. If players react quick enough, they can reflect damage back at enemies.

This breaks down in high lag scenarios. By the time the player sees the projectile hitting their character, the server has already registered the hit 100ms ago. The packet just hasn't made it to the client yet. This means you have to anticipate incoming damage and react long before it hits. Notice in the gif above how early I had to hit the button.

To correct this, the server implements something I call "damage buffering". Instead of applying damage instantly, the server puts the damage into a buffer for 100ms, or whatever the round-trip time is to the client. At the end of that time, it either applies the damage, or if the player reacted, reflects it back.

Here it is in action. You can see the 200ms delay between the projectile hitting me and the damage actually being applied.

Here's another example. In my game, players can launch themselves at enemies. Enemies die instantly to perfect shots, but they deflect glancing blows and send you flying like this:

Which direction should the player bounce? The client has to simulate the bounce before the server knows about it. The server and client need to agree which direction to bounce or they'll get out of sync, and they have no time to communicate beforehand.

At first I tried quantizing the collision vector so that there were only six possible directions. This made it more likely that the client and server would choose the same direction, but it didn't guarantee anything.

Finally I implemented another buffer system. Both client and server, when they detect a hit, enter a "buffer" state where the player sits and waits for the remote host to confirm the hit. To minimize jankiness, the server always defers to the client as to which direction to bounce. If the client never acknowledges the hit, the server acts like nothing happened and continues the player on their original course, fast-forwarding them to make up for the time they sat still waiting for confirmation.

## Problem #5: jitter

My server sends out packets 60 times per second. What about players whose computers run faster than that? They'll see jittery animation.

Interpolation is the industry-standard solution. Instead of immediately applying position data received from the server, you buffer it a little bit, then you blend smoothly between whatever data that you have.

In my previous attempt at networked multiplayer, I tried to have each object keep track of its position data and smooth itself out. I ended up getting confused and it never worked well.

This time, since I could already easily store the entire world state in a struct, I was able to write just two functions to make it work. One function takes two world states and blends them together. Another function takes a world state and applies it to the game.

How big should the buffer delay be? I originally used a constant until I watched a video from the Overwatch devs where they mention adaptive interpolation delay. The buffer delay should smooth out not only the framerate from the server, but also any variance in packet delivery time.

This was an easy win. Clients start out with a short interpolation delay, and any time they're missing a packet to interpolate toward, they increase their "lag score". Once it crosses a certain threshold, they tell the server to switch them to a higher interpolation delay.

Of course, automated systems like this often act against the user's wishes, so it's important to add switches and knobs to the algorithm!

## Problem #6: joining servers mid-match

Wait, I already have a way to serialize the entire game state. What's the hold up?

Turns out, it takes more than one packet to serialize a fresh game state from scratch. And each packet may take multiple attempts to make it to the client. It may take a few hundred milliseconds to get the full state, and as we've seen already, that's an eternity. If the game is already in progress, that's enough time to send 20 packets' worth of new messages, which the client is not ready to process because it hasn't loaded yet.

The solution is—you guessed it—another buffer.

I changed the messaging system to support two separate streams of messages in the same packet. The first stream contains the map data, which is processed as soon as it comes in.

The second stream is just the usual fire-hose of game messages that come in while the client is loading. The client buffers these messages until it's done loading, then processes them all until it's caught up.

## Problem #7: cross-cutting concerns

This next part may be the most controversial.

Remember that bit of gamedev wisdom from the beginning? "don't add networked multiplayer to an existing game"?

Well, most of the netcode in this game is literally tacked on. It lives in its own 5000-line source file. It reaches into the game, pokes stuff into memory, and the game renders it.

Just listen a second before stoning me. Is it better to group all network code in one place, or spread it out inside each game object?

I think both approaches have advantages and disadvantages. In fact, I use both approaches in different parts of the game, for various reasons human and technical.

But some design paradigms (*cough* OOP) leave no room for you to make this decision. Of course you put the netcode inside the object! Its data is private, so you'll have to write an interface to access it anyway. Might as well put all the smarts in there too.

## Conclusion

I'm not saying you should write netcode like I do; only that this approach has worked for me so far. Read the code and judge for yourself.

There is an objectively optimal approach for each use case, although people may disagree on which one it is. You should be free to choose based on actual constraints rather than arbitrary ones set forth by some paradigm.

Report Article

## User Feedback

There are no comments to display.

## Create an account

Register a new account

• 0
• 2
• 2
• 7
• 0

• 12
• 9
• 9
• 9
• 14
• ### Similar Content

• I am currently an undergrad several months from graduation. My major is in Game Programming and Development. During the course of my studies, we've had a few modeling classes and I really took to it and feel that is the direction I really want to go, specifically I would love to become a character artist. I keep hearing about your portfolio being super important, but I've really never been able to find out what kind of work is best to put into my portfolio. There's no "put 2 of these and 1 of those in," kind of tips. I get that I'll want to put some characters I've modeled in there, but I guess what I really want to know is, if I want my portfolio to be noticed and taken seriously for a character artist position, what is the best way to present it? Since most of my courses have dealt more with programming, I need to build everything for my modeling portfolio on the side, outside of class on my own time. I know there are no specific numbers like: put 3 realistic humans, 2 robots, a creature, and a stylistic character in your portfolio. But as a general rule is there some kind basic guideline or tips for what to make to get your portfolio off to a good start?

• Hi!
Is there by any chance you can give me an idea/concept that's different but related to the game Tower of London? (Is it called Tower of London?)
Can you show me some reference images, games or videos related to the same?
I've attached a reference image.
Thanks!

• Hi everybody,
So, me and my colleagues are now joining Unity Game Jam. It's gonna be two weeks and we are trying to make a Third Person Shooter with RPG and RTT mechanics video game. We've started yesterday with the main concept and this is what we have:

Game Storyline
Nobody could imagine the falling of the whole world until the deaths woke up. That nonliving ones became something we cannot consider as human being. They change into a new creature, stronger, more frightening, and almost unbeatable. Society broke in pieces and the few ones alive had to survive at any cost.
As the Major of a ranger platoon you have found an abandoned Military Outpost crowded of helpless people closer to one of the coldest parts in the world. You must keep them in safe until the reinforcements arrive.
There’s only one way to kill the damn zombies: the BlockchainZ Ammo.
Search for the BlockchainZ Ammo and destroy the hordes of zombies, but beware of the raiders: they will take your BlockchainZ Ammo whatever it takes.
Right now the Raiders have all the BlockchainZ ammo, you must fight them and spoil it, but be on guard, they will counterattack.
Remember, the survival of the people depends on you. Don’t let them down!

Gameflow.
Once you start playing Project BlockchainZ, you must defend the bunker against the hordes of zombies and raiders on a fixed map where you'll fight with your troops and traps.
The bunker is basically the main area where you'll not only have to keep the people within alive, but also yourself during the reinforcements arrive.
The zombies are extremely resistant, so you will need a type of ammo called BlockchainZ, which contains a very strong poison that acts directly against the brain traveling through the body.
The BlockchainZ Ammo is hidden in Raiders's Facility Bases and you must spoil it from them. The more  B-Z Ammo you spoil, the more Raiders will attack you, increasing the game difficulty level.

Features.
Third Person Shooter. Tactical map to manage your troops across the battle. Deploy defensive elements to direct the action where you want. Post apocalypse - scify style. RPG character development.
Right now, we've just opened our Project page in the forum. We only have two weeks to develope this idea. Our team is formed by two programmers, one game designer/ scriptwriter and one artist. So, we will update this thread to show you our improvements. Hope you like it. Any suggestions are always welcome. Thanks for all the support!

Whilst a lot of people find programming to be a stimulating activity, for others, traditional programming can be very intimidating; needing to remember what seems like arcane symbology, and seemingly endless streams of specific keywords into an editor can be very off-putting.  As many of us know, this actually gets easier with practice and soon becomes a less daunting task, but fortunately for those who struggle, there are other options available.
Many modern game engines offer different types of visual interface with which you can set up an environment and characters, and input the logic required to turn those pieces into a functioning game.  In this article, I aim to give a brief overview of some of the currently available options for creating games without traditional programming.  This list will not be exhaustive, but instead, aim to cover a few of the more popular and capable options, and I will leave it as an exercise for the reader to further research those options and choose what may be most suitable for their own goals.
Features and prices listed are current at the time of writing in October 2018.  Many of the options presented offer free trials, which I would encourage you to try out before spending your hard earned money -- in the case that no trial is available I would suggest checking out some written and video tutorials of the software to see if it looks like something you could understand and work with, as well as some games made with the software to see if it may be able to create the types of games you have in mind.
The first option I'm going to introduce is a simpler one suitable for introducing programming to younger would-be developers and is more limited in its capabilities, so if you're interested in more complex options please don't be put off and keep scrolling to the following items.  Below the list of options you'll find a few thoughts on visual systems.

Scratch
Scratch is a freely available programming environment created by the Lifelong Kindergarten Group at MIT Media Lab, and allows you to create games, interactive stories, and animations.  There is also an active online community of people sharing their creations and giving positive feedback.  Programming in Scratch is done by snapping building blocks together to input your logic, and although it's usable by people of all ages and abilities it's specially designed for younger learners ages 8 to 16.  Scratch works right in the web browser via the Flash plugin, so there are also no large downloads.  If you prefer working offline, there is also a downloadable version available.

Honestly, you're not going to create a smash hit video game with Scratch, but it's the perfect introduction for a child with an interest and may be a valuable starting point for people who find other systems intimidating.  Working with the visual system in scratch will encourage logical, structured thinking that can be applied to more complex systems or even to traditional programming at a later stage, and although it's fairly basic children will be excited to see and play with their own creations.  You can view (and play with!) some projects created with Scratch in the Explore section of their community.  Note that while you can share and play your creations with the Scratch community, but won't be able to deploy to other platforms such as mobile, consoles, etc.

Game Maker
Game Maker is a popular option amongst hobbyist and indie developers and is able to create games for a wide variety of platforms including mobile and many of the consoles. The engine has only rudimentary 3d capabilities and is not intended for making 3d games, but is very capable when it comes to 2d.  A number of very successful games including Hyper Light Drifter, Hotline Miami, Risk of Rain, Nuclear Throne and more have been created with Game Maker.  Check out the Game Maker Showcase for examples of what the engine is capable of.
Developers can use a simplified programming language called GML (Game Maker Language), or with a visual "drag and drop" system, and almost anything that can be done with GML can also be done with drag and drop -- albeit sometimes it might be a bit more clunky.  As a popular engine, you'll find plenty of tutorials (including lengthy series of officially provided video tutorials), sample projects, and people willing to help with learning and creating your projects.
You can get started with an unlimited free trial, and publish to additional platforms with a yearly subscription starting from US$39/year for Windows, up to US$1500/year for all available platforms.

Construct
Construct is a browser-based game engine that allows you to create games with a visual editor - in fact, in this case, programming is not even an option.  Games are created by applying and configuring "behaviours", and by using a visual "event sheet" that runs commands in order, and you are able to create most types of 2d game.  Because the editor runs in a browser you can create your game from any platform with a suitable browser, including mobile -- although you'll find it awkward to work with on a smaller screen.  A downloadable version is also available, and many functions of the editor are able to work offline.

Note that Construct is strictly a HTML5 engine, so exports for other platforms are provided via wrappers -- essentially packing your game up with a cut-down web browser to create an executable for the platform in question.  Their is an active community using the software, and plenty of tutorials and examples available to help you get started.  A free trial is available with some limitations, with full features available via subscription starting at US$99/year for a personal license or US$149/year for a business license (which you'll probably want if you're planning to monetize).

Stencyl
Stencyl is another visual editor aimed at creating 2d games, and able to publish to a range of platforms.  Stencyl's editor uses logic blocks similar to those available in Scratch, but also allows more advanced users to write some code if they wish to do so.  You can view some games created with Stencyl is the showcase.  Stencyl seems to have a slightly less active community than some other options, but there is some help available, and plenty of tutorials.  Some of the tutorials seem to be for previous versions of the software.

Unity + PlayMaker
Unity is an incredibly popular and very capable engine that can be used to create great games.  By itself, Unity doesn't provide visual scripting capabilities (programming is done with the C# programming language), but a third party add-on called PlayMaker comes to the rescue by adding a visual system and allowing developers to create games without writing code.  PlayMaker will currently set you back US\$45.50 (or cheaper with a Unity Plus or Pro subscription).
PlayMaker games are created with a flow-based system that involves toggling settings on nodes, which you connect in different orders to achieve the desired behaviour.  You will find PlayMaker more limiting than programming Unity with C#, but the experience you gain with the visual system may encourage you to try to C# and give you some fundamental logical thinking skills to build upon.

Unreal BluePrints
Unreal is another popular engine used by professional developers.  In this case, a visual system is built into the engine in the form of Blueprints, intended to allow non-coding designers to work with the engine and create interactive content.  You can get started using Unreal with no upfront cost, and pay just 5% of your game's earnings once you surpass a certain threshold.  Like many of the other options, there is an active community using Unreal, and plenty of tutorial content available, although most users do the majority of their Unreal development via C++ programming, with Blueprints used by non-coding team members.

Are There Limitations?
Honestly, yes.  Just as those using an engine might find themselves more limited than those developing their game "from scratch", you will often find that visual systems are more limited than traditional development.  Some things may be difficult or more time-consuming to implement in a visual editor, or if the creator hasn't exposed some data or a function you need your idea may be impossible.
However, many find these options to be more approachable, and some very impressive and successful games have been created using them.  Just be sure to do your due diligence about any limitations you might face before spending money hoping to create your dream game.

Other Options
The above are just a few of the popular options that can allow you to create games without traditional programming, but there are other options available if you're willing to do some further research.  Some others you might wish to look in to include GameSalad, RPG Maker, Unity + uScript Professional, Buildbox (,I found this editor to be especially limiting), and more.

Why Do I Keep Calling It "Traditional Programming"?
You may have noticed I keep saying "traditional programming" rather than just "programming".  Some people don't consider visual systems like those provided by the engines above to be programming, but I would disagree.  Wikipedia describes programming as:
and goes on to say:

I would argue that you are still doing the same task with a visual system, just via a different input method where you join blocks (or whatever the system in question provides) rather than typing special keywords.  Although some people find this type of visual programming less intimidating and easier to understand, you'll find that you're developing the same skills of logical thinking, planning out solutions, and finding (hopefully elegant) solutions.  After some time with visual systems, you may find the concepts used in traditional programming more familiar and approachable.

Conclusion
There are numerous options available to create games without traditional programming, and with the right selection you can likely find something capable of the type of games you wish to create.  Remember to research your options carefully, and don't be bothered by those who try to tell you it isn't "real game development".  I hope the above list helps to get you started with finding a suitable option for your project.

• I have a project with a bunch of different .java files. Is there a way for me to organize them in eclipse while still allowing them to access each other?
If I split the project in different folders, Eclipse can't find the different files when they're called in a different file.
×