Skip to content

Client-Server Architecture

Tip

If your plan on writing blocks or worlds, Empeld takes care of all multiplayer features for you! That said, if you plan on writing Entities or Game Mods, it's good to be aware of these concepts.

One of the key things you'll notice with the client-server architecture in Empeld is that we both try to reuse the same code wherever possible, while maintaining good separation where needed. One key example of this is using the same Entity classes for both client and server, but completely separating subsystems (that are only applicable to one or the other).

Communicating Between Client and Server

There are two ways to communicate between client and server. Both methods account for indianship of the operating system, and are very low-bandwidth in their operation.

Entity Syncables

Entity syncables are a special type of class that implements INetSyncable and that the server will automatically synchronize between client and server. There are several things to consider here, including security (We don't want cheaters), and frequency of the sync. These types of variables only work for Entities, and is the best way to communicate. Read more about them here: Syncables

Remote Procedure Call (RPC)

RPC is a simple method in which one class, can call a method on an instance of the same class on the server, or by getting a reference to another class that is registered on the server. See RPC for details on how to use this.

Eventing

Eventing is built on top of RPC, and it's a way to both broadcast application state to clients (for instance, if a new tower-defense wave is incoming!), as well as persisting state to disk, and replaying that state to new users who might join. See eventing for details.

Good Practices

Partial Breakup of Large Classes

One thing that we've found useful is to break up large classes, such as entities, by the type of service they provide. We can do this using partial classes. In the case of entities, we usually have 3 parts: Common, Client, and Server; so we can break up into 3 files, like this:

public partial class MyEntity : NewtonianBase
{
    //Common logic and syncables go here that both client and server access
} 
public partial class MyEntity
{
  //Client specific logic goes here, such as client RPC calls and 
  //Assume all logic here is subject to hacking and cheats
}
public partial class MyEntity
{
    //Server-specific logic goes here, such as RPC calls, simulation, and any specific validation
    //This logic should verify all actions
}