Quick implementation of Network for existing Game

There are 2 common choices of architecture for game network implementation:

  1. client-server
  2. peer-to-peer

What I did was some kind of hybrid of those two. I used Remote Procedure Calls (RPCs). In this post I will describe this technique giving some basic examples showing the role of server and actually giving it some tools to do it’s role as a server.

First, hybrid?

Client is the Server for logic management. But it is not a technical server. Client is written in C#, Server in Erlang. What Erlang Server does is just receive packets and sends them to other clients who has not sent those. In future it will be doing a vast variety of things. That states for client-server architecture.

Every client could by a Server who decides the game state (which is a synchronisation between clients). Because of RPC, client calls procedures on other clients but through logic server which is client…  and that states for part of peer-to-peer.

Show me your Hybrid

Let’s consider such function in a former form:

Now, let me modify it a little. Let’s state that every unit’s ID is a unique value in entire game and is known to all players (clients). So Player 1 don’t have a unit with any same ID as Player 2, 3 and so on.

Let’s continue:

What did I change? I made possible to call the function from outside. Server decides which unit  dies and can tell about it to all of players. Actually, server calls this function and tells other players to call the same function. But in the other hand, players can’t decide to call this function on their own.

So, my implementation looks like this, let’s say it’s in UnitManager:

In your NetworkManager write such function:

Of course this call could be done through Reflection Mechanism but it’s easier to debug like this, actually. So I recommend to implement RPC receiver functions for every message/RPC call type.

What is important – look at two calls of GetRPCState(bool isMessageFromNetwork). Thanks to this our first function knows whether to send Remote Procedure Call and whether to call internal behaviour right now or wait for RPC to be sent from server (to call this internal behaviour then). Calling internal behaviour has to have proper Unit  object which could be a little hard to send over the network and make some incosistences due to references, so that’s why the first argument is unitId.

Note about isConnected argument: if I test the game without connecting anywhere I want to always call my internal behaviours, no matter whether I am a client or server. Also being offline means no sending RPCs.

Don’t duplicate call

That’ll be the last example describing all of this technique. Let’s consider that we have a bomb in game which destroys many units. Because of unideal position synchronisation on clients, there’s a possiblity (actually, it happens pretty often) that some clients will see 4 killed units and some 5 killed units. It cannot be! To prevent that we have Server of course. Server decides: kill this and this, and this unit. And this one, too. Let’s see:

Server calls bombUnits(unitsIdsToKill) function and he sees bombing animation but no one more does it. destroyUnit(unitId) sends RPCs to other players but only about destroying units and not bombing them… Let’s modify it to send bombing RPC!

You see, it’s cool. But there’s a problem.. Let’s see… there’s being send an RPC bombing units… and wait, there’s more! We’re not sending RPCs for destroying units.

Let’ see how this would work:

Almost. Now every unit dies twice because every client gets info about bombing units and destroying them. Client should destroy unit based on bombing info. And that’s where all RPCState.DontDuplicateCall() function comes in handy:

I hope it’s simple enough to figure out understanding of this util.

Client can send RPC too

When client wants to make some move/command and tell about it other players, he can simply send RPC. Just implement such function the same way as destroyUnit() but instead of sending RPC to other clients… send it to the server, check and modifty it in there and send from server to other players to call same or another function implementing the move/command.

Summary

All this implementation appeared at the moment when I have started implementing a network functionality into ready game prototype so I didn’t want to change all the code around at the time. The other cause was that a colleague sitting near to me was still changing code for unit behaviours and such.

The basic question about such technique is simple – is it production-ready? It depends on architecture. Also, although it seems to work best in turn-based logic, I did it in two different realtime game prototypes (one is much more realtime than the other).  For best result it’s sure not enough to just send commands over the network. There has to exist some kind of game objects position synchronisation based on time and some predictions. Also in this form it’s still not ready for anti-cheating mechanisms.

So, to sum up, it’s a good and fast technique for lagless network prototyping. It’s also fairly easy to implement into the existing game.

Implementation was made in C# and Unity3D but I have done it in pure Java (using Reflection), too.

Resources

Here are some of my inspirations: