I find networking by far the most difficult part of game programming. The concept presents itself as a multiplication of game clients which are to be in sync in terms of the game state.

Wait, why do I try to sound all so strict and academic and all?

Let’s try again. Multiplayer online games have to be synchronized across all of the game clients. When I’m pressing ‘Shoot’, my character begins to shoot on my client and it should start shooting at your device as soon as possible. Game state updates are happening via travelling IP packets in tcp or udp transport layer and as awesome as these technicalities and choices are we’re gonna skip them for now. Point being, it’s network boi, it’s not reliable at all. Even more so on mobile with wireless connection, with its sudden drops and bandwidth being not as wide as in wired connection. Diving down into implementing networking engine in your game, you should keep this in mind, that even if you strive for the best experience possible, you’ll never get the dream of zero latency updates.

Let’s stop with the patronizing talk right now. I’ve spent roughly between 20-30 hours trying to make UNET work and kinda succeeded. A quick note for those who don’t know what UNET is.

UNET is an Unity library for networking inside the Unity game engine. It is divided into HLAPI (High Level API) and LLAPI (figure out full words yourself). HLAPI are mostly components which are to be added to gameobjects. LLAPI are scripts on which HLAPI runs and you’re invited to mess with them as you like. It is quite old solution and undividedly hated inside the whole Unity community. At the start of Stellar Asylum development there was no other Unity-signed networking solution. And UNET, or more precisely – the HLAPI, was deprecated. You may think, how can a solution be deprecated when there is no successor, no alternative. Well, I don’t know either, maybe ask Unity, they seem to feel OK with that.

me, really pissed at UNET

Getting back to Stellar Asylum I’ve ditched whole UNET in favor of Darkrift2 which is a far superior third-party network solution which comes in two versions: free and pro. Before we get to the Darkrift tho, let’s learn from UNET mistakes.

UNET sucks.

Let’s try to keep flame to the minimum. I’m going with bullet list, not ordered via pain-in-the-ass-potential. Łukasz, let’s keep it short, don’t flame too much, it will be OK, you’re over it now. Here:

Lack of the goddamn documentation – Dear Lord. Networking is such a hard concept. How can you provide an engine-wide solution with little to no documentation? This should have extensive description not only of HLAPI and LLAPI as well! As an author of library you cannot just throw the code at your users. You should make sure that your users have the resources to understand your code.

– Dear Lord. Networking is such a hard concept. How can you provide an engine-wide solution with little to no documentation? This should have extensive description not only of HLAPI and LLAPI as well! As an author of library you cannot just throw the code at your users. You should make sure that your users have the resources to understand your code. Designed for the finite set of game types – In theory the HLAPI is supposed to be used by default and when users need a fine-grained solution they can resort to LLAPI and code things themselves. However the lack of documentation on LLAPI basically leaves you only with HLAPI which is designed to work in a certain types of games like FPS. For example, UNET has component NetworkTransform. What I would expect this component to be is a generic component able to transform any variable through network and update it on other clients. What it is instead is a solution for transporting exactly either Rigidbody or Transform (or Player Controller which is a weird component with made up values, no room for extension and which no one ever uses, what the hell even…). When you want to sync, for example, character health – well, code it yourself!

– In theory the HLAPI is supposed to be used by default and when users need a fine-grained solution they can resort to LLAPI and code things themselves. However the lack of documentation on LLAPI basically leaves you only with HLAPI which is designed to work in a certain types of games like FPS. For example, UNET has component NetworkTransform. What I would expect this component to be is a generic component able to transform any variable through network and update it on other clients. What it is instead is a solution for transporting exactly either Rigidbody or Transform (or Player Controller which is a weird component with made up values, no room for extension and which no one ever uses, what the hell even…). When you want to sync, for example, character health – well, code it yourself! Peer to peer architecture – First of the clients instantiates server for the rest. I feel like Unity devs should know better if it comes to such obvious architectural decision. UNET as a solution does not provide a possibility to have server remotely. You’re bound to have game server running on one of the clients. Why is it bad? Well, one of the client has 0 latency when all the rest have non-zero latency. More so, imagine that client which happens to be also server is playing a game in car and his connection drops when entering tunnel. What you would expect is that only he is disconnected from a game. What happens instead is the following: client with server successfully advances in the game, probably killing all the other players, while they disconnect. There may be cases where such an architecture is OK, but it should never be the default. Also, it’s a much easier solution to implement from Unity side. To be honest and I feel like it’s a cutting-corners attitude from engine providers.

– First of the clients instantiates server for the rest. I feel like Unity devs should know better if it comes to such obvious architectural decision. UNET as a solution does not provide a possibility to have server remotely. You’re bound to have game server running on one of the clients. Why is it bad? Well, one of the client has 0 latency when all the rest have non-zero latency. More so, imagine that client which happens to be also server is playing a game in car and his connection drops when entering tunnel. What you would expect is that only he is disconnected from a game. What happens instead is the following: client with server successfully advances in the game, probably killing all the other players, while disconnect. There may be cases where such an architecture is OK, but it should never be the default. Also, it’s a much easier solution to implement from Unity side. To be honest and I feel like it’s a cutting-corners attitude from engine providers. UNET enforces prefab modification to be used in an online game – For me and Stellar Asylum it’s a huge one. What I would expect is that I can have one prefab of a Prisoner and I am able to use it both in local and online game. Good luck with trying to accomplish that in UNET. Your scripts become polluted with checks like ‘if server do that’, ‘if local player do that’. There is no possibility to separate UNET from prefabs. This way you end up with two different games, one online and one local. Every time you tweak something in animation or script, remember to change it in the other mode as well. Have fun!

– For me and Stellar Asylum it’s a huge one. What I would expect is that I can have one prefab of a Prisoner and I am able to use it both in local and online game. Good luck with trying to accomplish that in UNET. Your scripts become polluted with checks like ‘if server do that’, ‘if local player do that’. There is no possibility to separate UNET from prefabs. This way you end up with two different games, one online and one local. Every time you tweak something in animation or script, remember to change it in the other mode as well. Have fun! UNET pitholes – Honestly UNET was my first clash with engineering networking in games. Now that I’ve experienced it a little it’s easier for me to understand some of UNET nowhere-told caveats but it may still be mind-bending sometimes. I’m talking about stuff like: ‘you can only instantiate objects on the server’ or ‘for playing an animation across all clients there is a special component’. There is no way to learn these from some tutorial or such. You have to run into problem of not-appearing-instances or not-playing-animations, then google it and eventually read from answers in stack overflow or Unity forum.

– Honestly UNET was my first clash with engineering networking in games. Now that I’ve experienced it a little it’s easier for me to understand some of UNET nowhere-told caveats but it may still be mind-bending sometimes. I’m talking about stuff like: ‘you can only instantiate objects on the server’ or ‘for playing an animation across all clients there is a special component’. There is no way to learn these from some tutorial or such. You have to run into problem of not-appearing-instances or not-playing-animations, then google it and eventually read from answers in stack overflow or Unity forum. Deprecation – UNET is a deprecated networking solution. For a long time there was no other Unity network solution than UNET. Really – how can you deprecate entire library without providing any alternative?

And there are much more subtle nuances which I’m not gonna give as much screen time as the major problems above:

You have to do ResetTrigger() on server right after calling SetTrigger() for animation to play correctly across all clients.

NetworkAnimator component works even when set to not active.

Utter lack of engagement from Unity people on upvoted Unity threads on UNET. Unity people are non-existent there. For example this is a thread which helped me more than UNET docs, given no interaction from Unity side: https://forum.unity.com/threads/animator-settrigger-networkanimator-settrigger-bug.370984/. Thread dates 2014 and newest post is Dec 11, 2018!

To fix firewall problems UNET uses Unity relay service, meaning that network packets before reaching other clients have to travel to Unity servers first adding additional latency overall.

Each trigger has checkbox in network animator with no explanation what it does. It feels like it should be checked to be synchronized over network, but in my case it only worked when being unchecked.

Throwing your trigger names at you with no explanation what the checkbox does, great.

Since Unity 2019.1 has a Preview package with new networking solution but frankly I’m not up to date with this cause I’m not interested anymore. I expected a brand new solution, but seeing statement ‘The new Unity Transport Package which will replace the UNet low-level API’ I think I’ve heard enough and don’t want to try out their ‘new’ solution if it means that only some parts will be replaced. Thankfully there are other networking solutions on the market!

Darkrift2

Enter the Rift – Mohammad Qureshi

Darkrift2 is meeting my expectations in every detail. This part may seem like a sponsored praise of a library, but it’s just a praise. As far as I know, Darkrift2 is created and maintained by only one human being and that’s why it’s breathtaking comparing to UNET provided by whole company.

Darkrift:

comes with phenomenal documentation, as well as great tutorial, which introduces new concepts as you go but also makes space for your own brain work,

understands the need of closely managing the messages transported via network,

abstracts message sending and receiving API in a beautiful manner. You closely work with exact amount of bytes being transport via network,

supports sending both TCP and UDP packets based on the needs of the message which is a handy solution,

provides client-server architecture and comes with an server executable file. Running it on windows machine is effortless. Server code is supposed to be written as a standalone C# library, which is then compiled into .dll and copied into Darkrift server folder,

engineers events-based-communication which makes code easily readable,

tags each message. Tags are assigned numbers to assert what is the content of the message, e.g. ConnectTag or SpawnPlayerTag. Mapping to tags unfortunately makes space for errors, cause it needs to be both in the separate mapping file in Server Plugin and a in Unity, but hell, hit me with such problems, after I had to deal with UNET, I’ll take them,

does probably a whole lot more which I didn’t even touch yet and can’t wait to get my hands on.

What may be special about Stellar Asylum is that I want to have both local games and online games made with the same building blocks, having the parts of the code especially for networked games or especially for local games be reduced to the bare minimum. Right now Darkrift2 managed to help me in building a system which does exactly that. Prisoner prefabs are completely unaware if they’re in a local or an online game. What changes is the call structure and that’s the only thing that should change. I want to describe the solution in detail cause I believe there is a lesson to be taken from that, but apparently it’s already a hell of a post and I think enough is enough. Closer look on the Darkrift2 incorporation in Stellar Asylum will be covered in the future.

Thanks for reading 🙂

Łukasz