void HL2Rcon_SourceRconSendChatToEachClient( const char *text, rconUser_t *self, int cid, qboolean onlyme){ rconUser_t* user; int i; msg_t msg; int32_t *updatelen; byte sourcemsgbuf[MAX_MSGLEN]; for(i = 0, user = sourceRcon.activeRconUsers; i < MAX_RCONUSERS; i++, user++ ){ if(!user->streamchat) continue; MSG_Init(&msg, sourcemsgbuf, sizeof(sourcemsgbuf)); MSG_WriteLong(&msg, 0); //writing 0 for now MSG_WriteLong(&msg, 0); MSG_WriteLong(&msg, SERVERDATA_CHAT); if(self){ if(self == user) { MSG_WriteByte(&msg, -2); }else{ MSG_WriteByte(&msg, -1); if(onlyme) { continue; } } MSG_WriteBigString(&msg, user->rconUsername); }else{ MSG_WriteByte(&msg, cid); } MSG_WriteBigString(&msg, text); MSG_WriteByte(&msg, 0); //Adjust the length updatelen = (int32_t*)msg.data; *updatelen = msg.cursize - 4; NET_SendData(user->remote.sock, &msg); } }
void HL2Rcon_SourceRconFlushRedirect(char* outputbuf, qboolean lastcommand){ rconUser_t* user; if(sourceRcon.redirectUser < 1 || sourceRcon.redirectUser > MAX_RCONUSERS) return; user = &sourceRcon.activeRconUsers[sourceRcon.redirectUser -1]; msg_t msg; int32_t *updatelen; byte sourcemsgbuf[HL2RCON_SOURCEOUTPUTBUF_LENGTH+16]; MSG_Init(&msg, sourcemsgbuf, sizeof(sourcemsgbuf)); MSG_WriteLong(&msg, 0); //writing 0 for now MSG_WriteLong(&msg, user->lastpacketid); MSG_WriteLong(&msg, SERVERDATA_RESPONSE_VALUE); MSG_WriteBigString(&msg, outputbuf); MSG_WriteByte(&msg, 0); //Adjust the length updatelen = (int32_t*)msg.data; *updatelen = msg.cursize - 4; NET_SendData(user->remote.sock, &msg); }
static void demoFramePack( msg_t *msg, const demoFrame_t *newFrame, const demoFrame_t *oldFrame ) { int i; /* Full or delta frame marker */ MSG_WriteBits( msg, oldFrame ? 0 : 1, 1 ); MSG_WriteLong( msg, newFrame->serverTime ); /* Add the config strings */ for (i = 0;i<MAX_CONFIGSTRINGS;i++) { const char *oldString = !oldFrame ? "" : &oldFrame->string.data[oldFrame->string.offsets[i]]; const char *newString = newFrame->string.data + newFrame->string.offsets[i]; if (strcmp( oldString, newString)) { MSG_WriteShort( msg, i ); MSG_WriteBigString( msg, newString ); } } MSG_WriteShort( msg, MAX_CONFIGSTRINGS ); /* Add the playerstates */ for (i=0; i<MAX_CLIENTS; i++) { const playerState_t *oldPlayer, *newPlayer; if (!newFrame->clientData[i]) continue; oldPlayer = (!oldFrame || !oldFrame->clientData[i]) ? &demoNullPlayerState : &oldFrame->clients[i]; newPlayer = &newFrame->clients[i]; MSG_WriteByte( msg, i ); MSG_WriteDeltaPlayerstate( msg, oldPlayer, newPlayer ); } MSG_WriteByte( msg, MAX_CLIENTS ); /* Add the entities */ for (i=0; i<MAX_GENTITIES-1; i++) { const entityState_t *oldEntity, *newEntity; newEntity = &newFrame->entities[i]; if (oldFrame) { oldEntity = &oldFrame->entities[i]; if (oldEntity->number == (MAX_GENTITIES -1)) oldEntity = 0; } else { oldEntity = 0; } if (newEntity->number != i || newEntity->number >= (MAX_GENTITIES -1)) { newEntity = 0; } else { if (!oldEntity) { oldEntity = &demoNullEntityState; } } MSG_WriteDeltaEntity( msg, oldEntity, newEntity, qfalse ); } MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS ); /* Add the area mask */ MSG_WriteByte( msg, newFrame->areaUsed ); MSG_WriteData( msg, newFrame->areamask, newFrame->areaUsed ); /* Add the command string data */ MSG_WriteLong( msg, newFrame->commandUsed ); MSG_WriteData( msg, newFrame->commandData, newFrame->commandUsed ); }
void SV_CreateClientGameStateMessage( client_t *client, msg_t *msg ) { int start; entityState_t *base, nullstate; // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( msg, client->lastClientCommand ); // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side SV_UpdateServerCommandsToClient( client, msg ); // send the gamestate MSG_WriteByte( msg, svc_gamestate ); MSG_WriteLong( msg, client->reliableSequence ); // write the configstrings for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { if (sv.configstrings[start][0]) { MSG_WriteByte( msg, svc_configstring ); MSG_WriteShort( msg, start ); MSG_WriteBigString( msg, sv.configstrings[start] ); } } // write the baselines Com_Memset( &nullstate, 0, sizeof( nullstate ) ); for ( start = 0 ; start < MAX_GENTITIES; start++ ) { base = &sv.svEntities[start].baseline; if ( !base->number ) { continue; } MSG_WriteByte( msg, svc_baseline ); MSG_WriteDeltaEntity( msg, &nullstate, base, qtrue ); } MSG_WriteByte( msg, svc_EOF ); MSG_WriteLong( msg, client - svs.clients); // write the checksum feed MSG_WriteLong( msg, sv.checksumFeed); // For old RMG system. MSG_WriteShort ( msg, 0 ); }
void HL2Rcon_SourceRconSendDataToEachClient( const byte* data, int msglen, int type){ rconUser_t* user; int i; msg_t msg; int32_t *updatelen; byte sourcemsgbuf[MAX_MSGLEN]; qboolean msgbuild = qfalse; for(i = 0, user = sourceRcon.activeRconUsers; i < MAX_RCONUSERS; i++, user++ ){ if(!user->streamgamelog && type == SERVERDATA_GAMELOG) continue; if(!user->streamlog && type == SERVERDATA_CONLOG) continue; if(!user->streamevents && type == SERVERDATA_EVENT) continue; if(!msgbuild){ MSG_Init(&msg, sourcemsgbuf, sizeof(sourcemsgbuf)); MSG_WriteLong(&msg, 0); //writing 0 for now MSG_WriteLong(&msg, 0); MSG_WriteLong(&msg, type); if(type == SERVERDATA_EVENT) MSG_WriteData(&msg, data, msglen); else MSG_WriteBigString(&msg, (char*)data); MSG_WriteByte(&msg, 0); //Adjust the length updatelen = (int32_t*)msg.data; *updatelen = msg.cursize - 4; msgbuild = qtrue; } NET_SendData(user->remote.sock, &msg); } }
/* ==================== CL_Record_f record <slot> [<demoname>] Begins recording a demo from the current position ==================== */ void CL_Record( client_t *cl, char *s ) { char name[MAX_OSPATH]; char name_zip[MAX_OSPATH]; byte bufData[MAX_MSGLEN]; msg_t buf; int i; int len; entityState_t *ent; entityState_t nullstate; int clientnum; char *guid; char prefix[MAX_OSPATH]; clientnum = cl - svs.clients; if ( cl->demorecording ) { Com_Printf ("Already recording client %i.\n", clientnum); return; } // if ( cl->state != CA_ACTIVE ) { // Com_Printf ("You must be in a level to record.\n"); // return; // } // // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 .. // if ( NET_IsLocalAddress( cl->serverAddress ) && !Cvar_VariableValue( "g_synchronousClients" ) ) { // Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n"); // } if ( s ) { Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", s, PROTOCOL_VERSION ); } else { int number,n,a,b,c,d; guid = Info_ValueForKey(cl->userinfo, "cl_guid"); if (!Q_stricmp(guid, "")) { guid = "LONGGONE"; } Q_strncpyz(prefix, guid, 9); // scan for a free demo name for ( number = 0 ; number <= 9999 ; number++ ) { if(number < 0 || number > 9999) number = 9999; n = number; a = n / 1000; n -= a*1000; b = n / 100; n -= b*100; c = n / 10; n -= c*10; d = n; Com_sprintf (name, sizeof(name), "demos/%s_%s_%i%i%i%i.dm_%d", prefix, sv_mapname->string, a, b, c, d, PROTOCOL_VERSION ); Com_sprintf (name_zip, sizeof(name_zip), "demos/%s_%s_%i%i%i%i.dm_%d.zip", prefix, sv_mapname->string, a, b, c, d, PROTOCOL_VERSION ); Q_strlwr(name); Q_strlwr(name_zip); if (!FS_FileExists(name) && !FS_FileExists(name_zip)) { break; // file doesn't exist } } } // open the demo file if (!sv_autorecord->integer) { Com_Printf ("recording client %i to %s.\n", clientnum, name); } else { Com_Printf ("Record: %i: %s\n", clientnum, name); } cl->demofile = FS_FOpenFileWrite( name ); if ( !cl->demofile ) { Com_Printf ("ERROR: couldn't open.\n"); return; } // don't start saving messages until a non-delta compressed message is received cl->demowaiting = qtrue; cl->savedemo = qfalse; // demo will not be saved if sv_autorecord 1 and cl's score is too low Q_strncpyz( cl->demoName, name, sizeof( cl->demoName ) ); // write out the gamestate message MSG_Init (&buf, bufData, sizeof(bufData)); MSG_Bitstream(&buf); // NOTE, MRE: all server->client messages now acknowledge MSG_WriteLong( &buf, cl->lastClientCommand );// 0007 - 000A MSG_WriteByte (&buf, svc_gamestate);// 000B MSG_WriteLong (&buf, cl->reliableSequence );// 000C - 000F // write the configstrings for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if (sv.configstrings[i][0]) { MSG_WriteByte( &buf, svc_configstring ); MSG_WriteShort( &buf, i ); MSG_WriteBigString( &buf, sv.configstrings[i] ); } } // write the baselines Com_Memset( &nullstate, 0, sizeof( nullstate ) ); for ( i = 0 ; i < MAX_GENTITIES; i++ ) { ent = &sv.svEntities[i].baseline; if ( !ent->number ) { continue; } MSG_WriteByte( &buf, svc_baseline ); MSG_WriteDeltaEntity( &buf, &nullstate, ent, qtrue ); } MSG_WriteByte( &buf, svc_EOF ); // finished writing the gamestate stuff // write the client num MSG_WriteLong(&buf, clientnum); // write the checksum feed MSG_WriteLong(&buf, sv.checksumFeed); // finished writing the client packet MSG_WriteByte( &buf, svc_EOF ); // write it to the demo file len = LittleLong( cl->netchan.outgoingSequence-1 ); FS_Write (&len, 4, cl->demofile);// 0000 - 0003 len = LittleLong (buf.cursize); FS_Write (&len, 4, cl->demofile);// 0004 - 0007 FS_Write (buf.data, buf.cursize, cl->demofile);// 0007 - ... // the rest of the demo file will be copied from net messages cl->demorecording = qtrue; }
/* Start a server-side demo. This does it all, create the file and adjust the demo-related stuff in client_t. This is mostly ripped from sv_client.c/SV_SendClientGameState and cl_main.c/CL_Record_f. */ static void SVD_StartDemoFile(client_t *client, const char *path) { int i, len; entityState_t *base, nullstate; msg_t msg; byte buffer[MAX_MSGLEN]; fileHandle_t file; Com_DPrintf("SVD_StartDemoFile\n"); assert(!client->demo_recording); // create the demo file and write the necessary header file = FS_FOpenFileWrite(path); assert(file != 0); MSG_Init(&msg, buffer, sizeof(buffer)); MSG_Bitstream(&msg); // XXX server code doesn't do this, client code does MSG_WriteLong(&msg, client->lastClientCommand); // TODO: or is it client->reliableSequence? MSG_WriteByte(&msg, svc_gamestate); MSG_WriteLong(&msg, client->reliableSequence); for (i = 0; i < MAX_CONFIGSTRINGS; i++) { if (sv.configstrings[i][0]) { MSG_WriteByte(&msg, svc_configstring); MSG_WriteShort(&msg, i); MSG_WriteBigString(&msg, sv.configstrings[i]); } } Com_Memset(&nullstate, 0, sizeof(nullstate)); for (i = 0 ; i < MAX_GENTITIES; i++) { base = &sv.svEntities[i].baseline; if (!base->number) { continue; } MSG_WriteByte(&msg, svc_baseline); MSG_WriteDeltaEntity(&msg, &nullstate, base, qtrue); } MSG_WriteByte(&msg, svc_EOF); MSG_WriteLong(&msg, client - svs.clients); MSG_WriteLong(&msg, sv.checksumFeed); MSG_WriteByte(&msg, svc_EOF); // XXX server code doesn't do this, SV_Netchan_Transmit adds it! len = LittleLong(client->netchan.outgoingSequence-1); FS_Write(&len, 4, file); len = LittleLong (msg.cursize); FS_Write(&len, 4, file); FS_Write(msg.data, msg.cursize, file); FS_Flush(file); // adjust client_t to reflect demo started client->demo_recording = qtrue; client->demo_file = file; client->demo_waiting = qtrue; client->demo_backoff = 1; client->demo_deltas = 0; }
/* ================ SV_SendClientGameState Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each new map load. It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; byte msgBuffer[ MAX_MSGLEN ]; Log::Debug( "SV_SendClientGameState() for %s", client->name ); Log::Debug( "Going from CS_CONNECTED to CS_PRIMED for %s", client->name ); client->state = clientState_t::CS_PRIMED; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit client->gamestateMessageNum = client->netchan.outgoingSequence; MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) ); // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( &msg, client->lastClientCommand ); // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side SV_UpdateServerCommandsToClient( client, &msg ); // send the gamestate MSG_WriteByte( &msg, svc_gamestate ); MSG_WriteLong( &msg, client->reliableSequence ); // write the configstrings for ( start = 0; start < MAX_CONFIGSTRINGS; start++ ) { if ( sv.configstrings[ start ][ 0 ] ) { MSG_WriteByte( &msg, svc_configstring ); MSG_WriteShort( &msg, start ); MSG_WriteBigString( &msg, sv.configstrings[ start ] ); } } // write the baselines memset( &nullstate, 0, sizeof( nullstate ) ); for ( start = 0; start < MAX_GENTITIES; start++ ) { base = &sv.svEntities[ start ].baseline; if ( !base->number ) { continue; } MSG_WriteByte( &msg, svc_baseline ); MSG_WriteDeltaEntity( &msg, &nullstate, base, true ); } MSG_WriteByte( &msg, svc_EOF ); MSG_WriteLong( &msg, client - svs.clients ); // write the checksum feed MSG_WriteLong( &msg, sv.checksumFeed ); // NERVE - SMF - debug info Log::Debug( "Sending %i bytes in gamestate to client: %li", msg.cursize, ( long )( client - svs.clients ) ); // deliver this to the client SV_SendMessageToClient( &msg, client ); }
/* ================ SV_SendClientGameState Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each new map load. It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; byte msgBuffer[MAX_MSGLEN]; // MW - my attempt to fix illegible server message errors caused by // packet fragmentation of initial snapshot. while(client->state&&client->netchan.unsentFragments) { // send additional message fragments if the last message // was too large to send at once Com_Printf ("[ISM]SV_SendClientGameState() [2] for %s, writing out old fragments\n", client->name); SV_Netchan_TransmitNextFragment(&client->netchan); } Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name); Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name ); client->state = CS_PRIMED; client->pureAuthentic = 0; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit client->gamestateMessageNum = client->netchan.outgoingSequence; MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) ); // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( &msg, client->lastClientCommand ); // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side SV_UpdateServerCommandsToClient( client, &msg ); // send the gamestate MSG_WriteByte( &msg, svc_gamestate ); MSG_WriteLong( &msg, client->reliableSequence ); // write the configstrings for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { if (sv.configstrings[start][0]) { MSG_WriteByte( &msg, svc_configstring ); MSG_WriteShort( &msg, start ); MSG_WriteBigString( &msg, sv.configstrings[start] ); } } // write the baselines Com_Memset( &nullstate, 0, sizeof( nullstate ) ); for ( start = 0 ; start < MAX_GENTITIES; start++ ) { base = &sv.svEntities[start].baseline; if ( !base->number ) { continue; } MSG_WriteByte( &msg, svc_baseline ); MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue ); } MSG_WriteByte( &msg, svc_EOF ); MSG_WriteLong( &msg, client - svs.clients); // write the checksum feed MSG_WriteLong( &msg, sv.checksumFeed); //rwwRMG - send info for the terrain if ( TheRandomMissionManager ) { z_stream zdata; // Send the height map memset(&zdata, 0, sizeof(z_stream)); deflateInit ( &zdata, Z_MAX_COMPRESSION ); unsigned char heightmap[15000]; zdata.next_out = (unsigned char*)heightmap; zdata.avail_out = 15000; zdata.next_in = TheRandomMissionManager->GetLandScape()->GetHeightMap(); zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea(); deflate(&zdata, Z_SYNC_FLUSH); MSG_WriteShort ( &msg, (unsigned short)zdata.total_out ); MSG_WriteBits ( &msg, 1, 1 ); MSG_WriteData ( &msg, heightmap, zdata.total_out); deflateEnd(&zdata); // Send the flatten map memset(&zdata, 0, sizeof(z_stream)); deflateInit ( &zdata, Z_MAX_COMPRESSION ); zdata.next_out = (unsigned char*)heightmap; zdata.avail_out = 15000; zdata.next_in = TheRandomMissionManager->GetLandScape()->GetFlattenMap(); zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea(); deflate(&zdata, Z_SYNC_FLUSH); MSG_WriteShort ( &msg, (unsigned short)zdata.total_out ); MSG_WriteBits ( &msg, 1, 1 ); MSG_WriteData ( &msg, heightmap, zdata.total_out); deflateEnd(&zdata); // Seed is needed for misc ents and noise MSG_WriteLong ( &msg, TheRandomMissionManager->GetLandScape()->get_rand_seed ( ) ); SV_WriteRMGAutomapSymbols ( &msg ); } else { MSG_WriteShort ( &msg, 0 ); } // deliver this to the client SV_SendMessageToClient( &msg, client ); }
/* Start a server-side demo. This does it all, create the file and adjust the demo-related stuff in client_t. This is mostly ripped from sv_client.c/SV_SendClientGameState and cl_main.c/CL_Record_f. */ static void SVD_StartDemoFile(client_t *client, const char *path) { int i, len; entityState_t *base, nullstate; msg_t msg; byte buffer[MAX_MSGLEN]; fileHandle_t file; #ifdef USE_DEMO_FORMAT_42 char *s; int v, size; #endif Com_DPrintf("SVD_StartDemoFile\n"); assert(!client->demo_recording); // create the demo file and write the necessary header file = FS_FOpenFileWrite(path); assert(file != 0); /* File_write_header_demo // ADD this fx */ /* HOLBLIN entete demo */ #ifdef USE_DEMO_FORMAT_42 //@Barbatos: get the mod version from the server s = Cvar_VariableString("g_modversion"); size = strlen( s ); len = LittleLong( size ); FS_Write( &len, 4, file ); FS_Write( s , size , file ); v = LittleLong( PROTOCOL_VERSION ); FS_Write ( &v, 4 , file ); len = 0; len = LittleLong( len ); FS_Write ( &len, 4 , file ); FS_Write ( &len, 4 , file ); #endif /* END HOLBLIN entete demo */ MSG_Init(&msg, buffer, sizeof(buffer)); MSG_Bitstream(&msg); // XXX server code doesn't do this, client code does MSG_WriteLong(&msg, client->lastClientCommand); // TODO: or is it client->reliableSequence? MSG_WriteByte(&msg, svc_gamestate); MSG_WriteLong(&msg, client->reliableSequence); for (i = 0; i < MAX_CONFIGSTRINGS; i++) { if (sv.configstrings[i][0]) { MSG_WriteByte(&msg, svc_configstring); MSG_WriteShort(&msg, i); MSG_WriteBigString(&msg, sv.configstrings[i]); } } Com_Memset(&nullstate, 0, sizeof(nullstate)); for (i = 0 ; i < MAX_GENTITIES; i++) { base = &sv.svEntities[i].baseline; if (!base->number) { continue; } MSG_WriteByte(&msg, svc_baseline); MSG_WriteDeltaEntity(&msg, &nullstate, base, qtrue); } MSG_WriteByte(&msg, svc_EOF); MSG_WriteLong(&msg, client - svs.clients); MSG_WriteLong(&msg, sv.checksumFeed); MSG_WriteByte(&msg, svc_EOF); // XXX server code doesn't do this, SV_Netchan_Transmit adds it! len = LittleLong(client->netchan.outgoingSequence-1); FS_Write(&len, 4, file); len = LittleLong (msg.cursize); FS_Write(&len, 4, file); FS_Write(msg.data, msg.cursize, file); #ifdef USE_DEMO_FORMAT_42 // add size of packet in the end for backward play /* holblin */ FS_Write(&len, 4, file); #endif FS_Flush(file); // adjust client_t to reflect demo started client->demo_recording = qtrue; client->demo_file = file; client->demo_waiting = qtrue; client->demo_backoff = 1; client->demo_deltas = 0; }
void demoCutWriteDemoHeader(fileHandle_t f, clientConnection_t *clcCut, clientActive_t *clCut) { byte bufData[MAX_MSGLEN]; msg_t buf; int i; int len; entityState_t *ent; entityState_t nullstate; char *s; // write out the gamestate message MSG_Init(&buf, bufData, sizeof(bufData)); MSG_Bitstream(&buf); // NOTE, MRE: all server->client messages now acknowledge MSG_WriteLong(&buf, clcCut->reliableSequence); MSG_WriteByte(&buf, svc_gamestate); MSG_WriteLong(&buf, clcCut->serverCommandSequence); // configstrings for (i = 0; i < MAX_CONFIGSTRINGS; i++) { if (!clCut->gameState.stringOffsets[i]) { continue; } s = clCut->gameState.stringData + clCut->gameState.stringOffsets[i]; MSG_WriteByte(&buf, svc_configstring); MSG_WriteShort(&buf, i); MSG_WriteBigString(&buf, s); } // baselines Com_Memset(&nullstate, 0, sizeof(nullstate)); for (i = 0; i < MAX_GENTITIES ; i++) { ent = &clCut->entityBaselines[i]; if ( !ent->number ) { continue; } MSG_WriteByte(&buf, svc_baseline); MSG_WriteDeltaEntity(&buf, &nullstate, ent, qtrue); } MSG_WriteByte(&buf, svc_EOF); // finished writing the gamestate stuff // write the client num MSG_WriteLong(&buf, clcCut->clientNum); // write the checksum feed MSG_WriteLong(&buf, clcCut->checksumFeed); // RMG stuff if ( clcCut->rmgHeightMapSize ) { // Height map MSG_WriteShort(&buf, (unsigned short)clcCut->rmgHeightMapSize); MSG_WriteBits(&buf, 0, 1 ); MSG_WriteData(&buf, clcCut->rmgHeightMap, clcCut->rmgHeightMapSize); // Flatten map MSG_WriteShort(&buf, (unsigned short)clcCut->rmgHeightMapSize); MSG_WriteBits(&buf, 0, 1 ); MSG_WriteData(&buf, clcCut->rmgFlattenMap, clcCut->rmgHeightMapSize); // Seed MSG_WriteLong (&buf, clcCut->rmgSeed); // Automap symbols MSG_WriteShort (&buf, (unsigned short)clcCut->rmgAutomapSymbolCount); for (i = 0; i < clcCut->rmgAutomapSymbolCount; i ++) { MSG_WriteByte(&buf, (unsigned char)clcCut->rmgAutomapSymbols[i].mType); MSG_WriteByte(&buf, (unsigned char)clcCut->rmgAutomapSymbols[i].mSide); MSG_WriteLong(&buf, (long)clcCut->rmgAutomapSymbols[i].mOrigin[0]); MSG_WriteLong(&buf, (long)clcCut->rmgAutomapSymbols[i].mOrigin[1]); } } else { MSG_WriteShort (&buf, 0); } // finished writing the client packet MSG_WriteByte(&buf, svc_EOF); // write it to the demo file len = LittleLong(clcCut->serverMessageSequence - 1); FS_Write(&len, 4, f); len = LittleLong(buf.cursize); FS_Write(&len, 4, f); FS_Write(buf.data, buf.cursize, f); }
/* ================ SV_SendClientGameState Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each new map load. It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; byte msgBuffer[MAX_MSGLEN]; // MW - my attempt to fix illegible server message errors caused by // packet fragmentation of initial snapshot. while(client->state&&client->netchan.unsentFragments) { // send additional message fragments if the last message // was too large to send at once Com_Printf ("[ISM]SV_SendClientGameState() [2] for %s, writing out old fragments\n", client->name); SV_Netchan_TransmitNextFragment(&client->netchan); } Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name); Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name ); client->state = CS_PRIMED; client->pureAuthentic = 0; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit client->gamestateMessageNum = client->netchan.outgoingSequence; MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) ); // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( &msg, client->lastClientCommand ); // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side SV_UpdateServerCommandsToClient( client, &msg ); // send the gamestate MSG_WriteByte( &msg, svc_gamestate ); MSG_WriteLong( &msg, client->reliableSequence ); // write the configstrings for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { if (sv.configstrings[start][0]) { MSG_WriteByte( &msg, svc_configstring ); MSG_WriteShort( &msg, start ); MSG_WriteBigString( &msg, sv.configstrings[start] ); } } // write the baselines Com_Memset( &nullstate, 0, sizeof( nullstate ) ); for ( start = 0 ; start < MAX_GENTITIES; start++ ) { base = &sv.svEntities[start].baseline; if ( !base->number ) { continue; } MSG_WriteByte( &msg, svc_baseline ); MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue ); } MSG_WriteByte( &msg, svc_EOF ); MSG_WriteLong( &msg, client - svs.clients); // write the checksum feed MSG_WriteLong( &msg, sv.checksumFeed); // deliver this to the client SV_SendMessageToClient( &msg, client ); }
/* ================ SV_SendClientGameState Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each new map load. It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ static void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; byte msgBuffer[MAX_MSGLEN]; Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name); Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name ); client->state = CS_PRIMED; client->pureAuthentic = 0; client->gotCP = qfalse; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit client->gamestateMessageNum = client->netchan.outgoingSequence; MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) ); // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( &msg, client->lastClientCommand ); // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side SV_UpdateServerCommandsToClient( client, &msg ); // send the gamestate MSG_WriteByte( &msg, svc_gamestate ); MSG_WriteLong( &msg, client->reliableSequence ); // write the configstrings for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { if (sv.configstrings[start][0]) { MSG_WriteByte( &msg, svc_configstring ); MSG_WriteShort( &msg, start ); MSG_WriteBigString( &msg, sv.configstrings[start] ); } } // write the baselines Com_Memset( &nullstate, 0, sizeof( nullstate ) ); for ( start = 0 ; start < MAX_GENTITIES; start++ ) { base = &sv.svEntities[start].baseline; if ( !base->number ) { continue; } MSG_WriteByte( &msg, svc_baseline ); MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue ); } MSG_WriteByte( &msg, svc_EOF ); MSG_WriteLong( &msg, client - svs.clients); // write the checksum feed MSG_WriteLong( &msg, sv.checksumFeed); // There's something unknown going on here at the moment. // For now we're just going with default of adding a 0 short to keep jampded compatability. MSG_WriteShort( &msg, 0); // deliver this to the client SV_SendMessageToClient( &msg, client ); }
void CL_Record(const char *name) { int i; msg_t buf; byte bufData[MAX_MSGLEN]; entityState_t *ent; entityState_t nullstate; char *s; int len; // open the demo file Com_FuncPrinf("Recording to %s.\n", name); clc.demofile = FS_FOpenFileWrite(name); if (!clc.demofile) { Com_FuncPrinf("ERROR: couldn't open.\n"); return; } clc.demorecording = qtrue; Cvar_Set("cl_demorecording", "1"); // fretn Q_strncpyz(clc.demoName, demoName, sizeof(clc.demoName)); Cvar_Set("cl_demofilename", clc.demoName); // bani Cvar_Set("cl_demooffset", "0"); // bani // don't start saving messages until a non-delta compressed message is received clc.demowaiting = qtrue; // write out the gamestate message MSG_Init(&buf, bufData, sizeof(bufData)); MSG_Bitstream(&buf); // NOTE: all server->client messages now acknowledge MSG_WriteLong(&buf, clc.reliableSequence); MSG_WriteByte(&buf, svc_gamestate); MSG_WriteLong(&buf, clc.serverCommandSequence); // configstrings for (i = 0; i < MAX_CONFIGSTRINGS; i++) { if (!cl.gameState.stringOffsets[i]) { continue; } s = cl.gameState.stringData + cl.gameState.stringOffsets[i]; MSG_WriteByte(&buf, svc_configstring); MSG_WriteShort(&buf, i); MSG_WriteBigString(&buf, s); } // baselines memset(&nullstate, 0, sizeof(nullstate)); for (i = 0; i < MAX_GENTITIES; i++) { ent = &cl.entityBaselines[i]; if (!ent->number) { continue; } MSG_WriteByte(&buf, svc_baseline); MSG_WriteDeltaEntity(&buf, &nullstate, ent, qtrue); } MSG_WriteByte(&buf, svc_EOF); // finished writing the gamestate stuff // write the client num MSG_WriteLong(&buf, clc.clientNum); // write the checksum feed MSG_WriteLong(&buf, clc.checksumFeed); // finished writing the client packet MSG_WriteByte(&buf, svc_EOF); // write it to the demo file len = LittleLong(clc.serverMessageSequence - 1); FS_Write(&len, 4, clc.demofile); len = LittleLong(buf.cursize); FS_Write(&len, 4, clc.demofile); FS_Write(buf.data, buf.cursize, clc.demofile); // the rest of the demo file will be copied from net messages }
void SV_CreateClientGameStateMessage( client_t *client, msg_t *msg, qboolean updateServerCommands ) { int start; entityState_t *base, nullstate; // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( msg, client->lastClientCommand ); if ( updateServerCommands ) { // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side SV_UpdateServerCommandsToClient( client, msg ); } // send the gamestate MSG_WriteByte( msg, svc_gamestate ); MSG_WriteLong( msg, client->reliableSequence ); // write the configstrings for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { if (sv.configstrings[start][0]) { MSG_WriteByte( msg, svc_configstring ); MSG_WriteShort( msg, start ); MSG_WriteBigString( msg, sv.configstrings[start] ); } } // write the baselines Com_Memset( &nullstate, 0, sizeof( nullstate ) ); for ( start = 0 ; start < MAX_GENTITIES; start++ ) { base = &sv.svEntities[start].baseline; if ( !base->number ) { continue; } MSG_WriteByte( msg, svc_baseline ); MSG_WriteDeltaEntity( msg, &nullstate, base, qtrue ); } MSG_WriteByte( msg, svc_EOF ); MSG_WriteLong( msg, client - svs.clients); // write the checksum feed MSG_WriteLong( msg, sv.checksumFeed); //rwwRMG - send info for the terrain if ( TheRandomMissionManager ) { z_stream zdata; // Send the height map memset(&zdata, 0, sizeof(z_stream)); deflateInit ( &zdata, Z_BEST_COMPRESSION ); unsigned char heightmap[15000]; zdata.next_out = (unsigned char*)heightmap; zdata.avail_out = 15000; zdata.next_in = TheRandomMissionManager->GetLandScape()->GetHeightMap(); zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea(); deflate(&zdata, Z_SYNC_FLUSH); MSG_WriteShort ( msg, (unsigned short)zdata.total_out ); MSG_WriteBits ( msg, 1, 1 ); MSG_WriteData ( msg, heightmap, zdata.total_out); deflateEnd(&zdata); // Send the flatten map memset(&zdata, 0, sizeof(z_stream)); deflateInit ( &zdata, Z_BEST_COMPRESSION ); zdata.next_out = (unsigned char*)heightmap; zdata.avail_out = 15000; zdata.next_in = TheRandomMissionManager->GetLandScape()->GetFlattenMap(); zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea(); deflate(&zdata, Z_SYNC_FLUSH); MSG_WriteShort ( msg, (unsigned short)zdata.total_out ); MSG_WriteBits ( msg, 1, 1 ); MSG_WriteData ( msg, heightmap, zdata.total_out); deflateEnd(&zdata); // Seed is needed for misc ents and noise MSG_WriteLong ( msg, TheRandomMissionManager->GetLandScape()->get_rand_seed ( ) ); SV_WriteRMGAutomapSymbols ( msg ); } else { MSG_WriteShort ( msg, 0 ); } }