Welcome to this tutorial on Core contexts!
In this tutorial, you will learn:
- How your computer communicates with the game server
- What contexts are
- What the different types of Core contexts are
- For each, what their best uses are
- General tips and best practices
- Basic Introduction - The architecture of a game engine
- Default Context
- Networked Context
- Client Context
- Server Context
- Static Context
- Useful resources
The key of understanding Core contexts is to know and understand how your computer, when connecting to a game, interacts with Manticore's servers.
This interaction is a result of a cooperation between two actors: the server and the client(s).
A client corresponds to a player computer. In the case of a multiplayer game, then, there are multiple clients.
Remember those two actors, client and server. They gave their name to the corresponding context so if you know what they are, you will know what their context purpose is!
The server, in our case one of Manticore's servers, hosts the game you want to play. Your computer connects to the server and downloads a copy of the game - not the full game, but only the files that are destined to the clients.
The separation between what files are destined to the clients and what files are destined to the server is up to the game creator, but usually follows a certain optimization logic. Usually, the server will handle most of the game logic (main scripts, ...), while the client will usually handle animations, music, user interface and visual effects.
In the game, when you move your character, your computer (a client) sends a message to the server, saying "hello, I moved to these cooordinates". The server, then, runs some verifications (mostly to avoid cheating - for example, if a player tries to move faster than the game allows them to do), and if everything seems ok, it sends a message back to every client. This way, other players computers will know you moved!
The server can also communicates by itself to the clients. When a game round starts, for example, an event will be broadcasted to every client. This way, a script hosted on client-side could do something when the server starts the game round.
Understanding the interactions between the clients and the server really is the key to properly using contexts. Now that we made everything clear, let's see how to specificy a certain object in your game belongs to a specific context.
It is very simple!
- In your project, go to the Hierarchy tab.
- Right-click and select "Create Network Context..."
- You can now choose from three different types of contexts: Client, Server, Static.
Each type of context has its own icon so you can easily recognize them even after renaming the objects:
Also, for Client and Server contexts, objects inside them will mention the type of context after their own name. ("Cube", put inside a Client context, will become "Cube (client)"):
As for the two remaining types of contexts, Default and Networked, they are obtained quite simply.
Default is the default context used in Core. If you do not create any context in the hierarchy, then consider your object belongs to the Default Context.
To create a Networked context, right-click any folder, group or object in your hierarchy and select "Enable Networking".
Note that if you make a folder or a group networked, every child of this folder or group will become networked. Networking has a performance cost, so be careful! See the Networked Context section below to learn how to make the best use of it.
Finally, an important rule to notice is that for nested contexts, only the outermost context has an effect. For example, in the screenshot below, the Cube was put inside a Client Context. However, this same Client Context belongs to a Server Context - the result will be that the Cube is on the server.
It does not make sense anyway to put a Client Context inside a Server Context, since those are destined to two different actors, clients and game server.
This tutorial will now cover the five different types of contexts in Core, to help you make the best use of them.
When you add an object to the hierarchy, it defaults to... the Default Context.
Objects in the Default Context are assumed to not change during the game session. This means their position, rotation, scale or any other property should stay the same throughout the whole session.
Default Context objects handle collision and exist both on the server and on the client.
Note, however, that a script in a Default Context will run on the server only.
Most of your level geometry will be placed under the Default Context: this includes platforms, walls, and furniture. The only condition is that they have to stay the same during the whole session of the game. If you need to change the objects during the session, for example do moving platforms, use Networked Context.
Using this context will allow the players to collide with the objects, rather than going through them.
Networked Context refers to an object in a Default Context that has been set as Networked.
Remember: to do so, right-click an object in the hierarchy and click "Enable Networking". Don't forget that every descendant of this object will become networked too!
A Networked object is assumed to change during the game session. This means their position, rotation, scale or any other property can be changed by a server script.
Only a script located on the server can change a networked object. You cannot change a networked object from the client.
When a networked object changes, the server has to send the entire updated object to every client. This increases the network traffic, and could cause performance issues if your game contains many networked objects. Generally, you should reduce your use of networked objects to the bare minimum.
You can keep track of how much networked objects are in your game by looking at the performance limits bars above the editor main window.
Middle bar represents total count of networked objects. The maximum recommanded cap is set at 4,000.
The value is the result of the multiplication of the number of networked objects in your hierarchy and the maximum number of allowed players in your game.
As said above, this context suits perfectly for moving platforms. Imagine a 3D multiplayer platform game: everyone should see the platforms moving the same way!
Ennemies should also be placed in a Networked Context. This way, every client will see the ennemy move or attack.
If you need to spawn and despawn objects during the game session, use the Networked Context. For example, you may want to periodically spawn ennemies in a dungeon room.
Objects in a Client Context do not exist on the server, thus cannot be accessed by a script located on the server. They also do not handle collision, so do not use it for walls!
However, objects in a Client Context can be modified by a script located on the client.
Note that every client handles its own "version" of the game. This means if client number 1 changes an object through a client script, this modification will not be effective for client number 2.
This is how, for example, a User Interface shows specific data (i.e healthpoints) related to the player viewing it.
Since what happens in a Client Context happens on the player computer, you should be aware that performance issues could appear with very large scripts that run on a lower-end computer.
Also, even though protections are in place, keep in mind that a hacker could access and change data accessible on the client. Keep your sensible scripts on a Server Context, and, when sending data from a client to the server, always check if the data is valid. (For example, check if a player has enough money before giving him an equipment he bought in the shop)
The only way to interact with the server from a client context is to use the function Events.BroadcastToServer().
See more: Events - Core Documentation (coregames.com)
The Client Context will fit perfectly to the User Interface (UI). As said above, it is the only way to have each client see its own version of the UI, thus having data related to the individual player.
You will want to also use it for Visual Effects (VFX) as they tend to render better in this context, and you generally don't need VFX to be perfectly synced between each client.
Sound Effects (SFX), because they generally play for one player only (for examples, sounds in a 2D menu), should also be placed in a Client Context.
Finally, you will want to use Client Context for 3D Models that don't need collision. Imagine a scene of a landscape where the player can see way further than he actually can walk to. For the visual elements there, you may want to use Client Context since the models don't need collision (because the player will never access this area), this would be the most optimized context.
Objects in a Server Context do not exist on clients, thus cannot be accessed by a script located on the client. It also means they cannot be seen by clients, so don't put visual elements here! Players will not be able to see them.
Just like the Client Context, they don't handle collisions.
Keep in mind that objects in a Server Context, including scripts, are not send to clients. This is the perfet place to hide sensible game logic scripts, if you want to avoid users peeking into your game scripts.
In a Server Context, you can receive data from clients by using Events.
See more : Events - Core Documentation (coregames.com)
You will want to use Server Context for Game Logic, such as scripts.
For example, in a racing game, the chronometer could be a variable in a Server script that is incremented in the Tick(deltaTime) function. This way, you are sure the player times will not be rigged because they won't depend on the players different hardwares, but on the server. Also, it prevents cheaters from editing their time, possible with a timer-on-client approach.
Static Context could be seen as a mix of Client and Server Context.
Object in a Static Context are both on the server and on clients, but they cannot be modified.
Scripts run both on the server and on the clients.
Since scripts run both on the server and on the clients, they run independently. Keep in mind that this could cause de-sync issues and divergences between the two. This probably makes this context the most complex to understand, and an entire tutorial could be dedicated to it.
A very useful usage of the static context is to spawn objects during a game session, because it will not be marked as Networked, thus will not cause any additional networking cost once spawned. However, the condition is to not need to change the spawned object afterwards, since they cannot be modified.
Documentation also mentions this context is useful for procedurally generated maps.
Some tips to always keep in mind:
- In the API, some functions can only be called from the client or from the server. This is always specified in the "Tags" section of the property, found in the documentation.
- You'll mostly want to restrict your use of networked objects to the bare minimum, to avoid performance issues.
- When adding visual details and decor, try to use as much as possible the Client Context. The question you should ask yourself is, "Do I need collision on this object?. If the answer is no, then Client Context is probably the best idea!
As always, Core Documentation is the best place to learn.
Two articles that cover the subject of contexts and networking:
- Contexts - Core Documentation (coregames.com)
- Networking in Core - Core Documentation (coregames.com)
Core API, where you will find data about what function can be called in what context:
Thank you for reading this tutorial. I hope it was useful and taught you something.
If you have any question or suggestion, feel free to reach me on Discord or add a post below.