/* ================== SV_CheckTimeouts If a packet has not been received from a client in timeout.value seconds, drop the conneciton. When a client is normally dropped, the client_t goes into a zombie state for a few seconds to make sure any final reliable message gets resent if necessary ================== */ void SV_CheckTimeouts (void) { int i; client_t *cl; float droptime; int nclients; droptime = curtime - sv_timeout.value; nclients = 0; for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++) { if (cl->state == cs_connected || cl->state == cs_spawned) { if (!cl->spectator) nclients++; if (cl->netchan.last_received < droptime) { SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name); SV_DropClient (cl); cl->state = cs_free; // don't bother with zombie state } } if (cl->state == cs_zombie && svs.realtime - cl->connection_started > sv_zombietime.value) { cl->state = cs_free; // can now be reused } } if (((int) sv_paused.value & 1) && !nclients) { // nobody left, unpause the server SV_TogglePause("Pause released since no players are left.\n"); } }
/* ================== SV_CheckTimeouts If a packet has not been received from a client for timeout->value seconds, drop the conneciton. Server frames are used instead of realtime to avoid dropping the local client while debugging. When a client is normally dropped, the sv_client_t goes into a zombie state for a few seconds to make sure any final reliable message gets resent if necessary ================== */ void SV_CheckTimeouts( void ) { sv_client_t *cl; float droppoint; float zombiepoint; int i, numclients = 0; droppoint = host.realtime - timeout->value; zombiepoint = host.realtime - zombietime->value; for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if( cl->state >= cs_connected ) { if( cl->edict && !( cl->edict->v.flags & (FL_SPECTATOR|FL_FAKECLIENT))) numclients++; } // fake clients do not timeout if( cl->fakeclient ) cl->lastmessage = host.realtime; // message times may be wrong across a changelevel if( cl->lastmessage > host.realtime ) cl->lastmessage = host.realtime; if( cl->state == cs_zombie && cl->lastmessage < zombiepoint ) { cl->state = cs_free; // can now be reused continue; } if(( cl->state == cs_connected || cl->state == cs_spawned ) && cl->lastmessage < droppoint ) { SV_BroadcastPrintf( PRINT_HIGH, "%s timed out\n", cl->name ); SV_DropClient( cl ); cl->state = cs_free; // don't bother with zombie state } } if( sv.paused && !numclients ) { // nobody left, unpause the server SV_TogglePause( "Pause released since no players are left." ); } }
void SV_Pause_f (void) { int i; client_t *cl; char st[sizeof(host_client->name) + 32]; if (!pausable.value) { SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n"); return; } if (host_client->spectator) { SV_ClientPrintf (host_client, PRINT_HIGH, "Spectators can not pause.\n"); return; } if (sv.paused) sprintf (st, "%s paused the game\n", host_client->name); else sprintf (st, "%s unpaused the game\n", host_client->name); SV_TogglePause(st); }
void SV_LoadGame_f (void) { extern cvar_t sv_progtype; char name[MAX_OSPATH], mapname[MAX_QPATH], str[32 * 1024], *start; FILE *f; float time, tfloat, spawn_parms[NUM_SPAWN_PARMS]; edict_t *ent; int entnum, version, r; unsigned int i; if (Cmd_Argc() != 2) { Com_Printf ("Usage: %s <savename> : load a game\n", Cmd_Argv(0)); return; } snprintf (name, sizeof (name), "%s/save/%s", com_gamedir, Cmd_Argv(1)); COM_DefaultExtension (name, ".sav"); Com_Printf ("Loading game from %s...\n", name); if (!(f = fopen (name, "rb"))) { Com_Printf ("ERROR: couldn't open.\n"); return; } if (fscanf (f, "%i\n", &version) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } if (version != SAVEGAME_VERSION) { fclose (f); Com_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } if (fscanf (f, "%s\n", str) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } for (i = 0; i < NUM_SPAWN_PARMS; i++) { if (fscanf (f, "%f\n", &spawn_parms[i]) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } } // this silliness is so we can load 1.06 save files, which have float skill values if (fscanf (f, "%f\n", &tfloat) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } current_skill = (int)(tfloat + 0.1); Cvar_Set (&skill, va("%i", current_skill)); Cvar_SetValue (&deathmatch, 0); Cvar_SetValue (&coop, 0); Cvar_SetValue (&teamplay, 0); Cvar_SetValue (&maxclients, 1); Cvar_Set (&sv_progsname, "spprogs"); // force progsname #ifdef USE_PR2 Cvar_Set (&sv_progtype, "0"); // force .dat #endif if (fscanf (f, "%s\n", mapname) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } if (fscanf (f, "%f\n", &time) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } Host_EndGame(); CL_BeginLocalConnection (); SV_SpawnServer (mapname, false); if (sv.state != ss_active) { Com_Printf ("Couldn't load map\n"); fclose (f); return; } // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { if (fscanf (f, "%s\n", str) != 1) { Com_Printf("Couldn't read lightstyles\n"); fclose (f); return; } sv.lightstyles[i] = (char *) Hunk_Alloc (strlen(str) + 1); strlcpy (sv.lightstyles[i], str, strlen(str) + 1); } // pause until all clients connect if (!(sv.paused & 1)) SV_TogglePause (NULL, 1); sv.loadgame = true; // load the edicts out of the savegame file entnum = -1; // -1 is the globals while (!feof(f)) { for (i = 0; i < sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (i == sizeof(str)-1) Host_Error ("Loadgame buffer overflow"); str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) Host_Error ("First token isn't a brace"); if (entnum == -1) { // parse the global vars ED_ParseGlobals (start); } else { // parse an edict ent = EDICT_NUM(entnum); memset (&ent->v, 0, progs->entityfields * 4); ent->e->free = false; ED_ParseEdict (start, ent); // link it into the bsp tree if (!ent->e->free) SV_LinkEdict (ent, false); } entnum++; } sv.num_edicts = entnum; sv.time = time; fclose (f); for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; }