Network Architecture - Client Only, Server Only, Server with Local Client
Hey all, I'm looking to create an engine that allows client-only, server-only and server with local client networkability. I'm struggling to come up with a sort of architecture that allows this. My main areas of struggle are how to lay out a network manager that can be a server, a client or a server with a local client and at the same time, have an event manager that can do the same thing. The death of a player, for example, has to be broadcast to all players. If the server isn't running though, it only has to react to the event. If just the server is running, it only has to broadcast it. If the server has a local client, it has to do both. Does anyone have any articles, tutorials or is perhaps willing to go over their own architecture? Thanks.
What, specifically, drives this requirement?
Anyway, all games are simulations. Networked games are distributed simulations.
On the level of working with objects, you need to decide on a participating node in the distributed simulation to have authority for each individual object. That node is then responsible for collecting input somehow (could be by soliciting input from other nodes), feeding it to the object, and then broadcasting the resultant changes in state to all other nodes.
At its basic level, you can fairly easily separate the simulation part from the messaging part, and (re-)configure the running system to whatever topology you want. However, once you want to optimize the system to be competetive along some axes (simulation performance, networking usage, simulation integrity, what have you) it starts becoming more complicated.
Anyway, all games are simulations. Networked games are distributed simulations.
On the level of working with objects, you need to decide on a participating node in the distributed simulation to have authority for each individual object. That node is then responsible for collecting input somehow (could be by soliciting input from other nodes), feeding it to the object, and then broadcasting the resultant changes in state to all other nodes.
At its basic level, you can fairly easily separate the simulation part from the messaging part, and (re-)configure the running system to whatever topology you want. However, once you want to optimize the system to be competetive along some axes (simulation performance, networking usage, simulation integrity, what have you) it starts becoming more complicated.
enum Bool { True, False, FileNotFound };
When I said architecture, I was referring to the system-level programming code architecture, not the actual network architecture. I've been racking my brain all day and I think I've come up with a system that I like. Note that I'm only describing the network aspect of the system and not the other tasks it might handle (rendering, AI and such).
GameEvent (class)
- Contains ID (to convert to and from a byte-stream)
- Contains Event specific info
- Contains Origin (Server or Client)
Client (class)
- Listens for GameEvents with an Origin from the Server.
- Posts local client's input and other commands to the Server.
Server (class)
- Listens for GameEvents with an Origin from the Client.
- Runs / Updates the game and posts entity updates to the Client.
GameEventManager (singleton)
- Handles listening registration.
- Acts as the message pump for the game event queue.
A psuedo-code example of how the system would work:
---------------
[Client]
Scoreboard::Scoreboard()
- GameEventManager.RegisterListener(this.HandlePlayerDeath(), "player_death", Origin.Server)
[Server]
Player::Death()
- GameEvent death = GameEventManager.GetEvent("player_death")
- death.origin = origin.server;
- death.write_short(this.player_id)
- GameEventManager.PostEvent(death)
[Client]
Scoreboard::HandlePlayerDeath(GameEvent event)
- short player_id = event.read_short()
- Entity player = EntityManager.FindPlayer(player_id)
- player.deaths++
- RefreshScoreboard()
---------------
On paper the system seems feasible to me, but I'm hoping to get some feedback and criticism on it.
GameEvent (class)
- Contains ID (to convert to and from a byte-stream)
- Contains Event specific info
- Contains Origin (Server or Client)
Client (class)
- Listens for GameEvents with an Origin from the Server.
- Posts local client's input and other commands to the Server.
Server (class)
- Listens for GameEvents with an Origin from the Client.
- Runs / Updates the game and posts entity updates to the Client.
GameEventManager (singleton)
- Handles listening registration.
- Acts as the message pump for the game event queue.
A psuedo-code example of how the system would work:
---------------
[Client]
Scoreboard::Scoreboard()
- GameEventManager.RegisterListener(this.HandlePlayerDeath(), "player_death", Origin.Server)
[Server]
Player::Death()
- GameEvent death = GameEventManager.GetEvent("player_death")
- death.origin = origin.server;
- death.write_short(this.player_id)
- GameEventManager.PostEvent(death)
[Client]
Scoreboard::HandlePlayerDeath(GameEvent event)
- short player_id = event.read_short()
- Entity player = EntityManager.FindPlayer(player_id)
- player.deaths++
- RefreshScoreboard()
---------------
On paper the system seems feasible to me, but I'm hoping to get some feedback and criticism on it.
You'll have to work pretty hard to make that system deliver the events to the object replicas in the same order as they're delivered on the originating machine, although depending on what your game is, it might work just fine.
You might want to google for "a case for message passing architectures" which was a GDC presentation on this subject.
You might want to google for "a case for message passing architectures" which was a GDC presentation on this subject.
enum Bool { True, False, FileNotFound };
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement