/* * SNAP_BeginDemoRecording */ void SNAP_BeginDemoRecording( int demofile, unsigned int spawncount, unsigned int snapFrameTime, const char *sv_name, unsigned int sv_bitflags, purelist_t *purelist, char *configstrings, entity_state_t *baselines ) { unsigned int i; msg_t msg; uint8_t msg_buffer[MAX_MSGLEN]; purelist_t *purefile; entity_state_t nullstate; entity_state_t *base; MSG_Init( &msg, msg_buffer, sizeof( msg_buffer ) ); SNAP_DemoMetaDataMessage( &msg, "", 0 ); SNAP_RecordDemoMetaDataMessage( demofile, &msg ); // serverdata message MSG_WriteByte( &msg, svc_serverdata ); MSG_WriteLong( &msg, APP_DEMO_PROTOCOL_VERSION ); MSG_WriteLong( &msg, spawncount ); MSG_WriteShort( &msg, (unsigned short)snapFrameTime ); MSG_WriteString( &msg, FS_BaseGameDirectory() ); MSG_WriteString( &msg, FS_GameDirectory() ); MSG_WriteShort( &msg, -1 ); // playernum MSG_WriteString( &msg, sv_name ); // level name MSG_WriteByte( &msg, sv_bitflags & ~SV_BITFLAGS_HTTP ); // sv_bitflags // pure files i = Com_CountPureListFiles( purelist ); if( i > (short)0x7fff ) Com_Error( ERR_DROP, "Error: Too many pure files." ); MSG_WriteShort( &msg, i ); purefile = purelist; while( purefile ) { MSG_WriteString( &msg, purefile->filename ); MSG_WriteLong( &msg, purefile->checksum ); purefile = purefile->next; DEMO_SAFEWRITE( demofile, &msg, false ); } // config strings for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) { const char *configstring = configstrings + i * MAX_CONFIGSTRING_CHARS; if( configstring[0] ) { MSG_WriteByte( &msg, svc_servercs ); MSG_WriteString( &msg, va( "cs %i \"%s\"", i, configstring ) ); DEMO_SAFEWRITE( demofile, &msg, false ); } } // baselines memset( &nullstate, 0, sizeof( nullstate ) ); for( i = 0; i < MAX_EDICTS; i++ ) { base = &baselines[i]; if( base->modelindex || base->sound || base->effects ) { MSG_WriteByte( &msg, svc_spawnbaseline ); MSG_WriteDeltaEntity( &nullstate, base, &msg, true, true ); DEMO_SAFEWRITE( demofile, &msg, false ); } } // client expects the server data to be in a separate packet DEMO_SAFEWRITE( demofile, &msg, true ); MSG_WriteByte( &msg, svc_servercs ); MSG_WriteString( &msg, "precache" ); DEMO_SAFEWRITE( demofile, &msg, true ); }
/* * SV_New_f * * Sends the first message from the server to a connected client. * This will be sent on the initial connection and upon each server load. */ static void SV_New_f( client_t *client ) { int playernum; unsigned int numpure; purelist_t *purefile; edict_t *ent; int sv_bitflags = 0; Com_DPrintf( "New() from %s\n", client->name ); // if in CS_AWAITING we have sent the response packet the new once already, // but client might have not got it so we send it again if( client->state >= CS_SPAWNED ) { Com_Printf( "New not valid -- already spawned\n" ); return; } // // serverdata needs to go over for all types of servers // to make sure the protocol is right, and to set the gamedir // SV_InitClientMessage( client, &tmpMessage, NULL, 0 ); // send the serverdata MSG_WriteByte( &tmpMessage, svc_serverdata ); MSG_WriteLong( &tmpMessage, APP_PROTOCOL_VERSION ); MSG_WriteLong( &tmpMessage, svs.spawncount ); MSG_WriteShort( &tmpMessage, (unsigned short)svc.snapFrameTime ); MSG_WriteString( &tmpMessage, FS_BaseGameDirectory() ); MSG_WriteString( &tmpMessage, FS_GameDirectory() ); playernum = client - svs.clients; MSG_WriteShort( &tmpMessage, playernum ); // send full levelname MSG_WriteString( &tmpMessage, sv.mapname ); // // game server // if( sv.state == ss_game ) { // set up the entity for the client ent = EDICT_NUM( playernum+1 ); ent->s.number = playernum+1; client->edict = ent; if( sv_pure->integer ) sv_bitflags |= SV_BITFLAGS_PURE; if( client->reliable ) sv_bitflags |= SV_BITFLAGS_RELIABLE; if( SV_Web_Running() ) { const char *baseurl = SV_Web_UpstreamBaseUrl(); sv_bitflags |= SV_BITFLAGS_HTTP; if( baseurl[0] ) sv_bitflags |= SV_BITFLAGS_HTTP_BASEURL; } MSG_WriteByte( &tmpMessage, sv_bitflags ); } if( sv_bitflags & SV_BITFLAGS_HTTP ) { if( sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) MSG_WriteString( &tmpMessage, sv_http_upstream_baseurl->string ); else MSG_WriteShort( &tmpMessage, sv_http_port->integer ); // HTTP port number } // always write purelist numpure = Com_CountPureListFiles( svs.purelist ); if( numpure > (short)0x7fff ) Com_Error( ERR_DROP, "Error: Too many pure files." ); MSG_WriteShort( &tmpMessage, numpure ); purefile = svs.purelist; while( purefile ) { MSG_WriteString( &tmpMessage, purefile->filename ); MSG_WriteLong( &tmpMessage, purefile->checksum ); purefile = purefile->next; } SV_ClientResetCommandBuffers( client ); SV_SendMessageToClient( client, &tmpMessage ); Netchan_PushAllFragments( &client->netchan ); // don't let it send reliable commands until we get the first configstring request client->state = CS_CONNECTING; }
/* * TV_Downstream_New_f * * Sends the first message from the server to a connected client. * This will be sent on the initial upstream and upon each server load. */ void TV_Downstream_New_f( client_t *client ) { int playernum, numpure; int tv_bitflags; purelist_t *iter; msg_t message; uint8_t messageData[MAX_MSGLEN]; // if in CS_AWAITING we have sended the response packet the new once already, // but client might have not got it so we send it again if( client->state >= CS_SPAWNED ) { Com_DPrintf( "New not valid -- already spawned\n" ); return; } // relay is not ready yet if( client->relay && client->relay->state < CA_ACTIVE ) { TV_Relay_DelayNew( client ); return; } // // serverdata needs to go over for all types of servers // to make sure the protocol is right, and to set the gamedir // TV_Downstream_InitClientMessage( client, &message, messageData, sizeof( messageData ) ); // send the serverdata MSG_WriteByte( &message, svc_serverdata ); MSG_WriteLong( &message, APP_PROTOCOL_VERSION ); if( !client->relay ) { MSG_WriteLong( &message, tvs.lobby.spawncount ); MSG_WriteShort( &message, tvs.lobby.snapFrameTime ); MSG_WriteString( &message, FS_BaseGameDirectory() ); MSG_WriteString( &message, FS_GameDirectory() ); } else { MSG_WriteLong( &message, client->relay->servercount ); MSG_WriteShort( &message, client->relay->snapFrameTime ); MSG_WriteString( &message, client->relay->basegame ); MSG_WriteString( &message, client->relay->game ); } if( client->relay ) { // we use our own playernum on the relay server MSG_WriteShort( &message, client->relay->playernum ); } else { playernum = client - tvs.clients; MSG_WriteShort( &message, playernum ); } // send full levelname if( !client->relay ) MSG_WriteString( &message, tv_name->string ); else MSG_WriteString( &message, client->relay->levelname ); memset( &client->lastcmd, 0, sizeof( client->lastcmd ) ); tv_bitflags = SV_BITFLAGS_TVSERVER; if( client->reliable ) tv_bitflags |= SV_BITFLAGS_RELIABLE; MSG_WriteByte( &message, tv_bitflags ); // sv_bitflags // purelist if( !client->relay ) { MSG_WriteShort( &message, 0 ); } else { numpure = Com_CountPureListFiles( client->relay->purelist ); MSG_WriteShort( &message, numpure ); iter = client->relay->purelist; while( iter ) { MSG_WriteString( &message, iter->filename ); MSG_WriteLong( &message, iter->checksum ); iter = iter->next; } } TV_Downstream_ClientResetCommandBuffers( client, true ); TV_Downstream_SendMessageToClient( client, &message ); Netchan_PushAllFragments( &client->netchan ); // don't let it send reliable commands until we get the first configstring request client->state = CS_CONNECTING; }