I'm having trouble creating a reusable drawing for a game server in C #. Are there better models of architecture or design that could be used here?
If I group similar system features, it would look like this:
- Game (common for many types of games)
- Add player: The player is created with initialization information (player name), is added to the player list and receives a welcome message with the current status of the game. All other players are informed that the player current has joined the group. The current player is initially active if there is room and if the game allows it, otherwise a spectator.
- Delete a player: the player is deleted and all other players are warned that the player is gone
- Spectate: change a player so that he is a spectator
- Inspect: change a player to active
- PlayerState (common for several types of games)
- name (string)
- active (bool): active if true, viewer if false
- state (enum): active, inactive, intermission
- travel deadline (DateTime or DateTimeOffset): used to apply travel time limits
- if inactive and enough players join, enter the intermission state
- if you are paused for sufficient time, become active
- if paused and too many players leave, become inactive
- when the game ends, enter intermission
- updateInterval (TimeSpan): update the game at this interval
- networkUpdateInterval (TimeSpan): sends the current state to all players at this interval
- flow limit (TimeSpan)
- Send: If the rate limit allows, the message is broadcast to all readers and the last send time is updated.
- last message sent time of shipment (DateTime)
There are different types of games (
ChessGame, etc.), each of which is a combination of several types above (
TurnBasedGame) and specific states and operations to this game. It would also have a specific
SpecificGamePlayerState, with the state of the player specific to that game.
A server would be compiled for each specific game. In Visual Studio, the solution would include one project per game, which includes game-specific code with a reference to a shared project. The entry point is a class that redefines the methods of the frame to join, leave, message received. These methods have as their parameter a structure-specific reader object, which allows sending messages with the help of a structure-specific message object. My idea is that the entry-point class would implement the specific functions to process the framework, in order to separate the framework from the
SpecificGame classes, which only contain game logic and can be reused for other frameworks.
I've tried to design a generic class
Gamebut in his method of adding a player, he must send the current state of play to the new players. Yes
Game has a field with a
Listit should be shared with concrete games (public getter or protected field if inheritance is used), which is not good for encapsulation. The generation of the welcome message can not be performed in
Gameso we would have to call a method in an interface
IWelcomeProducer, but that would add additional generic type parameters to
Game for the type of message.
In addition, concrete classes must inherit several classes (such as
Chat), so one legacy would not be enough. With a "composition on inheritance" design in which game-specific classes instantiate these types in private fields, the game and player state classes must implement large interfaces with a lot of delegation (transfer methods), which generates a lot of code pasted.
With a naive design, it is possible to implement everything in one class for each game, but it would be the anti-pattern of the class of gods with code duplication between different games. Splitting this into the modules described above seems to require macros, multiple inheritance, or mixins, but in single inheritance languages that do not have these features, it may require reflection or code generation.
Is there a way to implement it securely against types (at compile time) and DRY (does not contain a lot of useless or unnecessary pasted code) without resorting to reflection or code generation ?