ET TV Design Document

Master-Slave Architecture



ETTV Master
Server where the actual game to be broadcast takes place. Engine is ettv, which runs normal qagame.

ETTV Slave
Server which broadcasts the game to spectators. Engine is ettv, which runs a special "tvgame". It connects up to the master and pretends to be a normal client. The slave mirrors the entire state of the master server -- entities and configstrings. Snaps are automatically parsed by the ettv engine into g_entities, reliable commands, etc.

The only function of tvgame is to handle spectators -- connecting, disconnecting, following, free floating, chat, and any special mod-specific support required.

Caveats:
tvgame must not:
spawn any entities (they would interfere with entities from the master)
set any configstrings (again, interfering with configstrings from the master)
change any cvars (not _strictly_ true, but a good general policy)
there may be more than 64 clients!

In addition to performing server tasks for spectators, tvgame must also perform some client tasks when talking to the master.

Reliable server commands from the master to the slave are sent to tvgame as a GAME_CLIENT_COMMAND with a clientnum of -2 to identify it as a command from the master, instead of a command from a spectator client.

In most cases tvgame will pass reliable commands it receives directly through to spectators, however mod specific issues may require tvgame to parse or 'eat' them some reliable commands. In general, configstring reliable commands should be 'eaten' by tvgame, as configstring updates will be passed to clients in the normal network protocol.

tvgame may also send reliable commands back to the master. This is accomplished by calling trap_SendServerCommand() with a clientnum of -2.

player following
On a "normal" server running qagame, when a spectator wants to follow another player, qagame copies most of the followed player's playerstate into the spectator's playerstate, replacing a few fields along the way.

With ettv, players on the master don't actually exist on the slave. For example, the ettv slave has 200 spectator clients 0-199. Say spectator 46 on the ettv slave wants to follow player 12's actions on the master. Slot 12 on the ettv slave is actually ettv spectator 12. Oops! How can this possibly work?

For ettv slave spectator following support, a new trap is required.
#define ETTV_GET_PLAYERSTATE 600

// rain - returns a playerstate for clientNum on the master, or for
// the slave itself (on the master) if clientNum is -1
// returns qtrue if a valid playerstate was found, qfalse otherwise
qboolean trap_ETTV_GetPlayerState(int clientNum, playerState_t *ps)
{
        return syscall(ETTV_GET_PLAYERSTATE, clientNum, ps);
}
The ettv slave engine receives a copy of every player's playerstate from the master and stores it locally in an internal buffer. tvgame may request a copy of a master player's playerstate via trap_ETTV_GetPlayerState.