Background: I help develop a multiplayer game, written mostly in C++, that uses a standard client-server architecture. The server can be compiled by itself, and the client is compiled with the server so you can host games.
Problem
The game combines both client and server code into the same classes, and this is starting to be very cumbersome.
For example, the following is a small sample of something you may see in a common class:
// Server + client
Point Ship::calcPosition()
{
// Do position calculations; actual (server) and predictive (client)
}
// Server only
void Ship::explode()
{
// Communicate to the client that this ship has died
}
// Client only
#ifndef SERVER_ONLY
void Ship::renderExplosion()
{
// Renders explosion graphics and sound effects
}
#endif
And the header:
class Ship
{
// Server + client
Point calcPosition();
// Server only
void explode();
// Client only
#ifndef SERVER_ONLY
void renderExplosion();
#endif
}
As you can see, when compiling the server only, preprocessor definitions are used to exclude the graphics and sound code (which seems ugly).
Question:
What are some of the best practices for keeping code in a client-server architecture organized and clean?
Thanks!
Edit: Examples of open source projects that use good organization are also welcome :)
Define a client stub class that has the client API.
Define the server class that implements the server.
Define a server stub that maps incoming message to server calls.
The stub class has no implementation except to proxy commands to the server via what ever protocol you are using.
You can now change protocols without changing your design.
or
Use a library like MACE-RPC to automatically generate the client and server stubs from the server API.