The server is an instance of the game that does all the network management, sending network packets (small portions of data) to client game instances that are connected to that server.
What will be sent to clients and what will remain on the server is on the programmer to decide, that’s what network programming is.
It guarantees every client game instance is seeing the game game, otherwise it would be analogue as seeing two different games being played in two different PCs.
Code that runs on the server
Logic that will only run on the server game instance, so any information not networked from any clients are unknown to the server, we cannot just network everything, that's a lot of information to send over the network, we are here to manage what should be networked and what should not.
All the code run in the server, will only run on the server. If we were to set a variable on the server and not replicate that logic on the client, that means the client would never know that was changed.
Server Attribute
[Server]
The Server attribute is used when we want to run methods only in the server.
Examples
Setting a variable
With the example code, you can see the [Server] attribute, it always comes in the line above the method and has to be after the XML documentation of that method.
The server attribute, prevents anything that isn't the server to run that method.
This is done to prevent clients from setting who is controlling a player x, its a way to prevent exploiting.
Initializing the gamemode
This code is only run on the server, because it initializes the gamemode, if it ran in every client, we would initialize the gamemode in each client, instead of doing once in the server with trusted data.
ObserversRPC
Code that is called from the server to be run on the client, with the information from the server
Usually here is where things get messy for some people, but for starters, the attribute is [ObserversRpc], RPC stands for remote-procedure-call, this one is called by the server, which means the server decides when to run it, and makes the client run it, with the information it wants.
That information is only valid for params, as the logic inside the code is run by the client, everything there only exists for the client, excepts for the method parameters sent by the server.
Network Message
Network Messages
Network messages are a way to transmit data without having to worry about object relationships, they are basically global events, which anyone can subscribe and listen to. And we can create structures to send whatever we want via the network.
The downside of that is that it doesn’t support late joins, the client has to be connected in order to receive that, otherwise it would miss the message. We should only use them when we want to ask something for the server to do, without worrying about object relations.
/// <summary>
/// Sets a new controlling soul.
/// </summary>
[Server]
public void SetControllingSoul(Soul soul)
{
_controllingSoul = soul;
if (soul == null)
{
RemoveOwnership();
}
else
{
GiveOwnership(soul.Owner);
}
}
[Server]
private void InitializeGamemode()
{
// Creates an instance of the SO, to avoid using the file.
_gamemode = Instantiate(_gamemode);
_gamemode.OnInitialized += HandleGamemodeInitialized;
_gamemode.OnFinished += HandleGamemodeFinalized;
_gamemode.OnObjectiveUpdated += HandleObjectiveUpdated;
_gamemode.InitializeGamemode();
}
Server RPC
Code that is called from the client to be run in the server, with the client information
Continuing the disgrace, there’s code that the client decides when to run and the server actually executes it, with the information the client gave it.
This is probably one of the most critical parts when we think about security, we sometimes we have to trust the client with what they are sending the server, so extra validation can be welcoming.
Anyways the attribute is [ServerRpc] this one has another trick at its sleeve, we have to own the object that we are trying to call the method, this can however be completed ignored by using [ServerRpc(ignoreAuthority = true)].
To guarantee you got it right, the params of the call will use data from the client, and the logic will be executed with the server’s data.
FishNet Networking
In order to network stuff we need a framework. We aren't doing it from scratch (again). We used to use Mirror but I found FishNet Networking, and I haven't used anything else since. It has free and paid features, which is lame, but we can use it at our favour.
I'll add important notes about developing with in the next sections.
The client is a game instance that is connected to a server game instance, it receives all network packets the server wants to send it, so a character position is set by the server so every client sees your player in the same position.
Code that runs on the client
Logic that will only run on the client game instance. Usually in Unity game development we use attributes for defining those rules, they are little tags that go above the method declaration, which does depend a lot on the networking framework you’re using in your game.
We are using FishNet Networking, the attribute is [Client], but code that is not sent to either clients or the server is always local to that game instance, so you only use that when you want to prevent the server game instance running that code.
Client attribute
[Client]
The client attribute prevents the server from running a method.
Examples
Initializing a game screen
The [Client] attribute is preventing a server from preparing an UI, as it should not exist in a headless server. The server doesn't play the game, it manages the game.