New network subsystem Unity 5 uNet. Authoritarian architecture project.

Example of the network architecture with an authoritarian server in Unity

Considering the facts that

  • the old network principles of Unity has become out of date.
  • I didn’t understand anyway how that magic worked for me.
  • A new method has appeared and started catching my eyes at every launch of Unity. Because of that I decided to grasp the network exchange better and make things clear.

I started moving in one direction – authoritarian server. It means that all game events, from turning to causing lots of damage, are solved and executed by the server solely. A player can only ask the server to execute their intensions. This approach allows to eliminate plenty of cheaters and hackers, which do magic with the client code and meddle with it. Of course there’s lots of other cheating methods but we won’t pay attention to them.

The Task:

Make a project, which will implement the authoritarian architecture.


In this project I don’t organize connection sessions – there’s plenty of Unity “for dummies” methods out there.

In this project I won’t tell you which keys to press. A reader, who doesn’t know how to follow given actions in Unity, isn’t really a good enough for this article.

In this project I am not going to care about the process physics, aerodynamic calculations etc. I’ll only show you the order of the network users’ interaction.

Needed result:

The output should consist of a detailed and transparent executive example, which will show how a client interacts with the server.

For this purpose I had to work on my own terminology. Without the terminology I couldn’t pull the task off.

                                  The Terminology:

Server – the place where the code, which serves other people, is executed. Usually user can’t physically touch the server’s console (input controller).

Host – the place where the server code is executed, but one of the players is playing there simultaneously. No one usually takes a closer look at this mode. That’s why understanding of this mode consists of the bunch of believes on how a server and a client work.

Client – the place, where the code, which is related to a particular player, is executed. Roughly speaking it’s your computer.

Unit – a game unit that represents a player in the game space – the character.

Unity architecture is made the way that it is easier to try and write one script to control one unit than try and write 3 different scripts: the first – to control yourself, the second – for the server to represent your gaming personality, the third – for the other player on my computer.

“I”, “my” – the code that takes my intensions directly through the console, joystick etc.

“Spirit” – the code that is executed on the server and only this code can implement the game solutions.

“My spirit” – the code on the server, which transmits my intensions into the actions on the game area.

“Somebody else’s spirit” – the code, which implements someone else’s intensions on the game area respectively.

“Avatar” – the code that reflects actions of any player on my (or somebody else’s) screen.

“My avatar” – the code that reflects the actions of “My Spirit”. “I” myself is “My Avatar”.

We will write one single script that satisfies all the roles. Why one same script? Just because we drive on similar or comparable tanks. You wouldn’t make me write one code for T-34, another code for Panzer 4, and another for Sherman Mk.IVAY, would you?!

Sorry for making up such a weird terminology but after lazily skimming through the topics of multiplayer development during a year I realized that this kind of terminology didn’t exist. But attempts to explain using existing terminology aren’t usually understood easily by people.


So. As I said earlier I decided to write one script for “Myself”, “My spirit” and “My avatar”. And also for “That guy”, what is ubiquitously recommended by Unity documentation.

So… are you ready?

Here we go.

  • Open Unity. Create the ground, for example a Plane. Scale the ground as 1000 x 1 x 1000.
  • Create a material. Set the color to RGB = (64:80:40). Let’s set it as a material for the ground. Just not to get blinded by the default white color. Believe it or not but I named the material “Ground”.
  • Add a cube to the scene. Add a Rigidbody component, mass of which define as 30 tons. Just fine for an average tank. Rename the “Cube” to “Tank”. Set scale of the Tank to (3:2:6). Lift it up above the Ground setting the Y-coordinate to 1.1. At the same time I recommend to leave X and Z coordinates as null.
  • Add another Cube to the scene. Define the scale as (1.5:1:2). Name it “Turret”. Set the coordinates to (0:2.4:1).
  • Add a cube to the scene. Set the scale to (0.2:0.2:4) and coordinates to (0:2.5:4). Let’s call it “Barrel”.
  • Add an empty GameObject to the scene named “Gun”. Its coordinates would be (0:2.4:2) and let’s leave its scale as it is.
  • Let’s drag the Gun object onto the Turret object so the Gun becomes a child of the Turret. Let’s make the Turret a child of the Tank. 
  • I set the Tank parts color to Khaki (64:96:32). Just because. As a result we should get something that reminds a tank. If you ask why should we nest the Gun in the Barrel I’ll answer – If you rotate the Barrel around the X-axis, the axis won’t be at its place. But if you rotate the Gun around the X-axis the picture will look pretty good. In reality you will work with the normal graphical models that have their rotation points set correctly in the very graphical editor. So this kind of problems shouldn’t appear.

Let’s move along.

We’re going to take our bearings on this article, but just take the bearings. We will have differences.

  • Let’s create a GameObject on the scene and call it “NetworkCommander”. Let’s add 2 components to it: NetworkManager and NetworkmmanagerHUD. We should make sure that NetworkManagerHUD component has the ShowRuntimeUI checked. NetworkManager implements a general management of the network sessions. To make the life for the players/developers easier NetworkManagerHUD draws a simple menu on the screen, which has the basic actions with the network – serve a game, host a game, join a game.
  • Add a NetworkIdentity component to the Tank object, but don’t check the LocalPlayerAuthority. We don’t need it for the authoritarian architecture and it doesn’t make sense anyway.
  • Make a Tank Prefab – that is copy the GameObject to a Project folder. Name it “TankPrefab”.
  • In the NetworkCommander object in the SpawInfo part set the TankPrefab into the PlayerPrefab field.
  • Create a C# script AmourDrive.cs. We don’t need the function Start() yet. We need only Update().
  • Include the UnityEngine.Networking namespace. It will allow us to use the network functions of uNet..
  • Change the ArmourDrive class from MonoBehaviour on NetworkBehaviour. This class expands  usual logic adding the network functions to it.
  • In the ArmourDrive class create the fields:
float veloMyMax = 10, veloMyCurr = 0; //the variables I use. Maximal accessible speed and desired speed, m/s.
float veloSvrMax = 1 d0, veloSvrCurr = 0; //the variables that use my spirit. Maximally accessible speed and needed speed, m/s.
float periodSvrRpc = 0.02f; //how often does the server send the image updates to the clients, in seconds.
float timeSvrRpcLast = 0; //when was the last time the server sent the image update. 
  •  An instant script will be executed in 3 places at the time: in order to read my intensions on my computer (“I”), on the server for receiving the intensions and converting them into actions (“My spirit”), and on the computer of the guy, for whom the actions are going to be rendered (“my avatar”). We can differ these three things by using two variables.

The isServer variable means that this copy of the script is executing on the server and in this case it is “my spirit”.

The variable isClient means that this copy of the script is executing on a client and in this case it is someone else’s “avatar”.

The isLocalPlayer variable means that it is “my avatar”.

  • Let’s form the intensions inside of the Update() function;
if (this.isLocalPlayer)
            //The code is executed just on my computer.
            //Form a new requirement for the speed.
            float veloMyNew = 0;
            veloMyNew += Input.GetKey(KeyCode.W) ? veloMyMax : 0;
            veloMyNew += Input.GetKey(KeyCode.S) ? -veloMyMax : 0;
            if (veloMyCurr != veloMyNew)
                //If a requirement for the speed has changed, let’s send a new requirement to the server. 

                CmdDrive(veloMyCurr = veloMyNew);
  • In order to send my intensions on a server the programmer has to: a) start a name of the function with letters “Cmd”; b) when you write a function, mark it as executive one on a server on a client’s demand. Here’s the text:
[Command(channel = 0)]
    void CmdDrive(float veloSvrNew)
        if (this.isServer)
            //My spirit receives and checks the command.
            //Check my requirement for its validity.
            veloSvrNew = Mathf.Clamp(veloSvrNew, -veloSvrMax, veloSvrMax);
            //Set the current value of the speed I require for the spirit.	
            veloSvrCurr = veloSvrNew;
            //The spirit is going to execute it later.
  • Now the server should authoritatively move my tank. It can be done in the Update() function. But Unity authors recommend making physical calculations inside of the FixedUpdate function. We don’t have cool physics but let’s follow the advice.
void FixedUpdate()
        if (this.isServer)
            //The code is only executed at “Spirit”.
            //Process my commands.
            this.transform.Translate(0, 0, veloSvrCurr * Time.deltaTime, Space.Self);
            if (timeSvrRpcLast + periodSvrRpc < Time.time)
                //Send the coordinates to all my avatars if it’s about time.            {
                timeSvrRpcLast = Time.time;

Cmd kind of functions have Rpc kind of functions as a callback. The Rpc functions are called by the server and are executed on the clients’ computers. Here’re some more syntactic requirements: the function should have a [ClientRpc] mark and its name should start with “Rpc”. The server sent us new coordinates that it got from our speed requirements and we should move our unit to a new place.

[ClientRpc(channel = 0)]
    void RpcUpdateUnitPosition(Vector3 posNew)
        if (this.isClient)
            //My avatars copy my spirit’s state.
            this.transform.position = posNew;

Here we could put a smooth approach to the point in order to avoid any tank jerks on the screen, but we won’t be distracted.

  • Considering the fact that the tank can accidentally turn during its linear movement (run over a hillock or something)
  • [ClientRpc(channel = 0)]
        void RpcUpdateUnitOrientation(Quaternion oriNew)
        {n the
            if (this.isClient)
                //My avatars copy my spirit’s state        {
                this.transform.rotation = oriNew;


  • This script should be added to the tank’s prefab.
  • Now we’re almost ready to start the game. But there’s a problem – usually it’s easier to configure, develop and basically work with the GameObject on the scene. But when a network game starts the object shouldn’t be on the scene. Usually the teachers from Youtube erase the object from the scene before they start the game. But it’s easier for me to activate it instead of deleting it. So deactivate Tank object or just delete it.
  • Start and press the LAN(Host) button in the dialog which is given by a NetworkManagerHud.

    Here we go. The tank got drowned in the ground to the level of its turret. That’s because NetworkManager sets a player on a zero-level height, so the bottom of the tank is going to be under the ground. We can deal with the players’ respawn later but for now let’s indulge ourselves in a little duct tape. At the moment we are not dealing with the respawn but with the network. Let’s write:
  • Now we’re ready to launch the game. Let’s use the Host mode in order to create and join the game quickly and not worry about the additional copies.
void Awake()
//The duct tape: lift up the player 110 cm higher, so it won’t fall      //through the landscape. 
//TODO – examine the players’ respawn coordinates.
this.transform.position = new Vector3(0, 1.1f, 0);
  • Let’s launch the game once more and choose the Host mode. Everything is fine. The tank moves forwards and backwards when pressing the keys.
  • Now let’s build a Standalone so we will be able to launch a few copies of the game. Press Build Settings -> Player options. Don’t forget to check the “Run in Background” check. This will allow you to launch a few instances of the game without most of them working in a sleeping mode. Besides let’s turn off the “Default is full screen” option for now, and for the descriptive reasons set a poor resolution of 400x300. Since we don’t need better resolution yet, let’s switch the Display Resolution Dialog to Disabled. After that let’s press Build one more time and create an executive file.
  • We can launch a few executive files at a time.
  • We can turn them on in any combination: either a host and two clients or a server and two clients. Here’s an example of a server and two clients:

                                   The Result

We can make sure that both tanks go well, sync smoothness for this kind of a project is more than acceptable.

But you might say “Stop! We have implemented just the forwards/backwards movement! Where’s the rotation of both tank and turret?

And here’s my answer:
Rotation of the tank, turret and barrel can be implemented absolutely identically to the forwards/backwards movement.

Why did I implement the network exchange the way I did and why do I put this “fake” out?

Just because the tutorials for the new system uNet are pretty slender yet and there’s a really scanty amount of them. And the methods, which they tell about, can’t turn the tank parts, just the whole tank.

But in this article we examined (I hope so) clear logic of how a network works, which is valid for the tank’s parts movement and for the smoke, and the damage, and the very shots.

That’s the way it is.


User replies

No replies yet