Client development
Last updated
Last updated
Some basic project configuration is required to avoid some common errors.
You should go to Player Settings and make sure you have 'Run in Background' checked to allow the networking system work even in background.
Also, allow the Dispatcher and NetManager run before the rest of the code. Under project settings, go to Script Execution Order and place them like in the image.
The first step is to add a NetManager, which will manage all the basics of the server connection.
The steps to add a NetManager are:
Add a new empty GameObject by right-clicking on hierarchy
Name it as NetManager
Click on 'Add Component' and look for NetManager
Now, lets fill the Host field with the address of our server. If you are running it on your local machine with the default configuration, just type "ws://localhost:7537". We will just leave the NetEntities empty for now.
It's time to check if everything is running fine, lets connect to the server and print a message.
Create a new C# script by right-clicking on the file inspector
Name it as you want (i.e. ConnectionTest)
Remove the Update block as we won't use it this time
Use the Connect() method from the NetManager instance to connect:
If you attach the ConnectionTest script to a GameObject and run the project, you won't see anything. Lets add some juice to our script.
You can subscribe to different events over the networking system, so modify your code with the OnOpen event subscription:
If everything is correct, when you run the project, you should see this message on the debug console.
Now we are going to send a message to the server asking for the version, and then wait for an answer.
The communication in Socks works with JSON messages, so you need to construct an appropiate message that the server can recognise and process. Lucky you, Socks provides a NetMessage class for that!
Lets create a new object with NetMessage type, and use the correct Net Type (check Net Types section) to let the server know that you are asking for the version. You can extend the script used in the previous example.
The type 100 is the net type that says to the server 'hey, send me the version you are running". Now, just send the message.
We are close to the goal. If you subscribe to the OnMessage event, you will be able to read the bunch of bytes sent by the server. So, parse them by creating a new NetMessage with those bytes, and do some basic stuff to read the version.
Once again, if everything is running fine, you should see the message on console.
Some functions in Socks (those related with inventories, roles, etc) requires user authentication. To get the auth access, you just have to provide a correct user/password combination, then the server will keep in the session our authentication state.
The approach is simple, we just need to build a NetMessage with the appropiate type (300 in this case) and then assign the message data to push it to the server.
Then, just subscribe to the OnMessage event and check if the authentication process went fine.
After that, you can just send message types that require authentication and will work on their own.
In the previous examples, you have learned to work with net messages. But, what about syncing GameObjects?
NetEntity is a base class that provides the basic networking functionality for GameObject syncing, and can be easily extended by overriding its methods.
Lets add some objects to the scene:
Add a plane as a floor
Add a Capsule that will act as our player
Remove the Capsule collider
Add a Character Controller to it
To control it, you can just add the provided Basic Movement script
It's time to learn how to synchronize the position of the players.
Create a new script and call it 'CapsulePlayer'. It should inherit from NetEntityBase, not from MonoBehaviour, so change it.
Now, just override two methods:
NetOutput: add the data you want to send over the net for the GameObject its attached to
NetUpdate: will be called with the received data from other players GameObjects, so use it to update the position with that data
Attach the created NetEntity script to your capsule player.
Since it inherits from NetEntityBase, it will have a NetRate property. It specifies how many messages will be sent over the net per second. A value between 5 to 10 has a good balance between smoothness and network saturation.
Make a prefab by dragging the GameObject to the file explorer, then remove it from the scene. Add it to the Net Entities list of the Net Manager to allow it to be instantiated over the network.
Now, create a new script, call it Spawner, and attach it to an empty GameObject on the scene.
Maybe you have noticed that we are using OnConnect now instead of OnOpen. The difference between these two events is that in the case of OnConnect, we have received our client id, so we are ready to instantiate networked GameObjects.
Build the project and run two instances, if you didn't forgot anything, it will look similar to the video.
Voilà! You have realtime network communication. Well, maybe the players smoothness could be improved, but we will talk about it later...
Online games are as good as their netcode is. While usually a game in your machine can generate 60 images (frames) per second, sending a packet to a server, broadcasting to all other clients and processing them 60 times per second is inviable. So, what can we do?
Go to your previously created player prefab, remove the NetEntity script (CapsulePlayer) and add a NetTransform.
NetTransform is a script that extends the NetEntityBase and takes care of synchronizing x, y and z axis of GameObject's position and the y axis of rotation, which usually will be enough for most use cases. Also let us decide how many decimals use to sync and if it should apply interpolation functions to make them smooth.
Set the net rate to 10, make sure smooth function is enabled and try to re-run the project by launching 2 instances. A value of 10 should be enough for most fast-paced games.
As you can see, it is now way more smooth than before. The provided smooth function is simple and works well for a general use, but you can write your own smooth, interpolation or prediction algorithm that fits better in your project.
Remote Procedure Calls or RPCs are the way to call functions in GameObjects over the network. Think in a player with a gun, if that player wants to shot a bullet, then he needs to tell all other players that is about to fire its gun. He will send a RPC with the required data and then, on all other players machines, the GameObject that represent that player will be calling the gun fire function.
RPCs on Socks are also easy to manage.
Start by adding the provided Bullet prefab (which basically includes a script that moves it forward and destroy it after few seconds) to the list of Local Entities on the NetManager. You can instantiate local entities from anywhere, NetManager includes a local entity list just for avoid you creating one.
Now, create a new script, call it CapsulePlayerWithGun, make it inherit from NetEntityBase and copy all the content from the NetTransform script to get a good starting point.
RPCs should be defined as a void with a name that starts with "Rpc". Define a method called RpcFire and fill it with code.
The resulting script should look like this:
Now, lets make a way to shoot. Get the BasicMovement script and edit it to send the fire RPC when pressing the space bar.
And we are ready to go.
If you followed correctly all the steps, you should have learnt the basics of networking and will be ready to develop your own networked game!