Dispatching Command in C# with expression tree
Every action a player performs is batched and sent to an authoritative server for validation in Metro Cityscape, this design resembles the command design pattern. The command object contains a command code that identifies the command and a payload that contains all the data needed to process a player's action. I estimate the game to have well over 100 commands, and the number will definitely increase as the game grows, so to make writing the handling code of the individual command easier, it would be best to have each command handled by a method, like a RPC. This way, related commands can be grouped in a single class for organizational benefits and can share the same set of dependencies. Now comes the technical challenge: how should these incoming requests be dispatched to their individual method in an efficient way? There are several ways to do this – reflection, delegates, expression, Reflection.Emit to name a few. After doing some research and testing I went with the cached compiled expression tree approach. I believe it is one of the fastest ways to call a dynamic method, the speed is comparable to a direct method call, and .NET Core Web API also uses this approach to handle the routing of HTTP requests.
Sharing of code between the server and the client
To avoid writing duplicate code, especially the core business logic, and to take advantage of the fact that the server and the client are both written in C#, I decided to put the core logic in a separate, shared library to be consumed. The logic code should have minimal concerns except for the core business logic. To illustrate, the logic code, with the help of interfaces, receives an input object, mutates the passed player state, and returns the mutated state. The consumer/client decides what to do with the state, for the server, it eventually gets persisted, for the client, it triggers a re-render to reflect what has changed.
The command code must remain consistent throughout the lifetime of the game, so instead of writing them manually, which is error-prone and tedious, I wrote a simple command generation console tool to be the single source of truth. It simplifies the workflow because now I only have to define the name and type of fields in a command. On insert, a unique ID along with the corresponding C# code will be generated and persisted.