/* ===================== Host_Connect_f User command to connect to server ===================== */ void Host_Connect_f (void) { char name[MAX_QPATH]; cls.demonum = -1; // stop demo loop in case this fails if (cls.demoplayback) { CL_StopPlayback (); CL_Disconnect (); } q_strlcpy (name, Cmd_Argv(1), sizeof(name)); CL_EstablishConnection (name); Host_Reconnect_f (); }
/* ===================== Host_Connect_f User command to connect to server ===================== */ void Host_Connect_f (void) { char name[MAX_QPATH]; // if the video isn't initialized already, it needs to be Host_InitVideo(); cls.demonum = -1; // stop demo loop in case this fails if (cls.demoplayback) { CL_StopPlayback (); CL_Disconnect (); } strcpy (name, Cmd_Argv(1)); CL_EstablishConnection (name); Host_Reconnect_f (); }
/* =============== Host_Loadgame_f =============== */ void Host_Loadgame_f (void) { char name[MAX_OSPATH]; FILE *f; char mapname[MAX_QPATH]; float time, tfloat; char str[32768]; const char *start; int i, r; edict_t *ent; int entnum; int version; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("load <savename> : load a game\n"); return; } cls.demonum = -1; // stop demo loop in case this fails q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1)); COM_AddExtension (name, ".sav", sizeof(name)); // we can't call SCR_BeginLoadingPlaque, because too much stack space has // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); Con_Printf ("Loading game from %s...\n", name); f = fopen (name, "r"); if (!f) { Con_Printf ("ERROR: couldn't open.\n"); return; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } fscanf (f, "%s\n", str); for (i = 0; i < NUM_SPAWN_PARMS; i++) fscanf (f, "%f\n", &spawn_parms[i]); // this silliness is so we can load 1.06 save files, which have float skill values fscanf (f, "%f\n", &tfloat); current_skill = (int)(tfloat + 0.1); Cvar_SetValue ("skill", (float)current_skill); fscanf (f, "%s\n",mapname); fscanf (f, "%f\n",&time); CL_Disconnect_f (); SV_SpawnServer (mapname); if (!sv.active) { fclose (f); Con_Printf ("Couldn't load map\n"); return; } sv.paused = true; // pause until all clients connect sv.loadgame = true; // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { fscanf (f, "%s\n", str); sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles"); } // load the edicts out of the savegame file entnum = -1; // -1 is the globals while (!feof(f)) { qboolean inside_string = false; for (i = 0; i < (int) sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '"') { inside_string = !inside_string; } else if (r == '}' && !inside_string) // only handle } characters outside of quoted strings { i++; break; } } if (i == (int) sizeof(str) - 1) { fclose (f); Sys_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,"{")) { fclose (f); Sys_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->free = false; ED_ParseEdict (start, ent); // link it into the bsp tree if (!ent->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]; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } }
/* =============== Host_Loadgame_f =============== */ void Host_Loadgame_f (void) { char name[MAX_OSPATH], temp[MAX_OSPATH]; vfsfile_t *f; char mapname[MAX_QPATH]; float time, tfloat; char str[32768], *start, *c; int i, r, len, n; edict_t *ent; int entnum; int version; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("load <savename> : load a game\n"); return; } cls.demonum = -1; // stop demo loop in case this fails // sprintf (name, "%s", Cmd_Argv(1)); strcpy (name, Cmd_Argv(1)); COM_DefaultExtension (name, ".sav"); // we can't call SCR_BeginLoadingPlaque, because too much stack space has // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); Con_Printf ("Loading game from %s...\n", name); // f = fopen (name, "r"); f = FS_OpenVFS(name, "rb", FS_GAMEONLY); if (!f) { Con_Printf ("ERROR: couldn't open.\n"); return; } // fscanf (f, "%i\n", &version); version = atoi(VFS_GETS(f, name, sizeof(name))); if (version != SAVEGAME_VERSION) { // fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); VFS_CLOSE (f); return; } // fscanf (f, "%s\n", str); VFS_GETS(f, str, sizeof(str)); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) spawn_parms[i] = atof(VFS_GETS(f, temp, sizeof(temp))); // fscanf (f, "%f\n", &spawn_parms[i]); // this silliness is so we can load 1.06 save files, which have float skill values // fscanf (f, "%f\n", &tfloat); tfloat = atof(VFS_GETS(f, temp, sizeof(temp))); // temp buf current_skill = (int)(tfloat + 0.1); Cvar_SetValue ("skill", (float)current_skill); #ifdef QUAKE2 Cvar_SetValue ("deathmatch", 0); Cvar_SetValue ("coop", 0); Cvar_SetValue ("teamplay", 0); #endif // fscanf (f, "%s\n",mapname); // fscanf (f, "%f\n",&time); VFS_GETS(f, mapname, sizeof(mapname)); for (c = mapname+strlen(mapname)-1; c>=mapname && (*c == '\n' || *c == '\r'); *c--='\0'); time = atof(VFS_GETS(f, temp, sizeof(temp))); CL_Disconnect_f (); allowcheats = sv_cheats.value != 0; // sv_cheats // if the video isn't initialized already, it needs to be Host_InitVideo(); #ifdef QUAKE2 SV_SpawnServer (mapname, NULL); #else SV_SpawnServer (mapname); #endif if (!sv.active) { Con_Printf ("Couldn't load map\n"); VFS_CLOSE (f); return; } sv.paused = true; // pause until all clients connect sv.loadgame = true; // load the light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { // fscanf (f, "%s\n", str); VFS_GETS(f, str, sizeof(str)); // sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1); // this is no longer necessary, changed to straight array for (c = str+strlen(str)-1; c>=str && (*c == '\n' || *c == '\r'); *c--='\0'); strcpy (sv.lightstyles[i], str); } // load the edicts out of the savegame file entnum = -1; // -1 is the globals len = VFS_GETLEN(f); n = 0; // while (!feof(f)) for(;;) { for (i=0 ; i<sizeof(str)-1 ; i++) { // r = fgetc (f); r = VFS_GETC(f); if (r == -1 || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (r == -1 || !r) break; if (i == sizeof(str)-1) Sys_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,"{")) Sys_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->free = false; ED_ParseEdict (start, ent); // link it into the bsp tree if (!ent->free) SV_LinkEdict (ent, false); } entnum++; n++; } sv.num_edicts = entnum; sv.time = time; // fclose (f); VFS_CLOSE (f); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } }
/* =============== Host_Loadgame_f =============== */ void Host_Loadgame_f (void) { char name[MAX_OSPATH]; FILE *f; char mapname[MAX_QPATH]; float time, tfloat; char str[32768], *start; int i, r, line; // Current line # in savegame file edict_t *ent; int entnum, numedicts_save; int version; float spawn_parms[NUM_SPAWN_PARMS]; qboolean Quote; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("load <savename> : load a game\n"); return; } cls.demonum = -1; // stop demo loop in case this fails sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); COM_DefaultExtension (name, ".sav"); // we can't call SCR_BeginLoadingPlaque, because too much stack space has // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); Con_SafePrintf ("Loading game from %s...\n", name); f = fopen (name, "rb"); // Use binary mode to avoid EOF issues in savegame files if (!f) { Con_Printf ("ERROR: couldn't open.\n"); return; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } // Kludge to read saved games with newlines in title do fscanf (f, "%s\n", str); while (!feof(f) && !strstr(str, "kills:")); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) fscanf (f, "%f\n", &spawn_parms[i]); // this silliness is so we can load 1.06 save files, which have float skill values fscanf (f, "%f\n", &tfloat); current_skill = (int)(tfloat + 0.1); Cvar_SetValue ("skill", (float)current_skill); fscanf (f, "%s\n",mapname); fscanf (f, "%f\n",&time); CL_Disconnect_f (); #ifdef QUAKE2 SV_SpawnServer (mapname, NULL); #else SV_SpawnServer (mapname); #endif if (!sv.active) { Con_Printf ("Couldn't load map\n"); return; } sv.paused = true; // pause until all clients connect sv.loadgame = true; // load the light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { fscanf (f, "%s\n", str); sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1); strcpy (sv.lightstyles[i], str); } // load the edicts out of the savegame file entnum = -1; // -1 is the globals // Hack to avoid validation errors while parsing savegame file numedicts_save = sv.num_edicts; sv.num_edicts = MAX_EDICTS; line = 86; // 85 lines before globals in savegame while (!feof(f)) { for (i=0, Quote = false ; i<sizeof(str)-1 ; i++) { r = fgetc (f); if (r == EOF || !r) break; if (r == '\n') ++line; str[i] = r; // Handle multiline quoted strings containing '}' if (!Quote) { if (r == '\"') Quote = true; else if (r == '}') { i++; break; } } else if (Quote) { if (r == '\"') Quote = false; } } if (i == sizeof(str)-1) Sys_Error ("Loadgame buffer overflow (%d, max = %d) on line %d", i + 1, sizeof(str) - 1, line); if (Quote) Sys_Error ("Host_Loadgame_f: %s in quoted string on line %d", r == EOF ? "EOF" : "EOS", line); str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) Sys_Error ("First token (%s) isn't a brace on line %d", com_token, line); if (entnum == -1) { // parse the global vars ED_ParseGlobals (start, line); } else { // parse an edict ent = EDICT_NUM("Host_Loadgame_f1", entnum); if (!pr_free[entnum]) ED_Free (ent); // Unlink from world memset (&ent->v, 0, progs->entityfields * 4); pr_free[entnum] = false; ED_ParseEdict (start, ent, line); // link it into the bsp tree if (!pr_free[entnum]) { int mindx = ent->v.modelindex; model_t *model = sv.models[mindx]; char *mname = pr_String ("Host_Loadgame_f1", ent->v.model); char *cname = pr_String ("Host_Loadgame_f2", ent->v.classname); // Check for missing/invalid models (except e.g. player/eyes RoS switch) if (mindx != 0 && (model == NULL || *mname != 0 && strcmp(model->name, mname) && strcmp(cname, "player"))) { Con_Printf ("\x02Host_Loadgame_f: "); if (model == NULL) Con_Printf ("missing model"); else Con_Printf ("invalid model (%s)", model->name); Con_Printf (" for edict %d (%s)\n", entnum, ED_DbgEdict(&ent->v)); } SV_LinkEdict (ent, false); } } entnum++; } sv.num_edicts = numedicts_save; // Free edicts not present in the savegame, might // otherwise cause odd SV_TouchLinks errors for (i = entnum; i < sv.num_edicts; ++i) { if (!pr_free[i]) { ent = EDICT_NUM("Host_Loadgame_f2", i); // Don't warn if edict_reuse is disabled if (ent->area.prev && edict_reuse.value) { Con_Printf ("\002Host_Loadgame_f: "); Con_Printf ("invalid touched edict (%d, max = %d)\n", i, entnum); } ED_Free (ent); // Unlink from world } } sv.num_edicts = entnum; // Set new edict amount from savegame // Count active edicts for (i = sv.active_edicts = 0; i < sv.num_edicts; ++i) { if (!pr_free[i]) ++sv.active_edicts; } ED_ChkEdict (true, false); sv.time = time; fclose (f); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; // Chack for different saved game mode if (deathmatch.value != pr_global_struct->deathmatch || coop.value != pr_global_struct->coop || teamplay.value != pr_global_struct->teamplay) { Con_Printf ("\002Host_Loadgame_f: "); Con_Printf ("saved game mode different (dm=%g/%g, coop=%g/%g, team=%g/%g)\n", deathmatch.value, pr_global_struct->deathmatch, coop.value, pr_global_struct->coop, teamplay.value, pr_global_struct->teamplay); } if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } }
/* =============== Host_Loadgame_f =============== */ static void Host_Loadgame_f (void) { FILE *f; char mapname[MAX_QPATH]; float playtime; char str[32768]; int version; int i, error_state; int tempi; float tempf; edict_t *ent; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("load <savename> : load a game\n"); return; } cls.demonum = -1; // stop demo loop in case this fails CL_Disconnect(); Host_RemoveGIPFiles(NULL); Key_SetDest (key_game); // remove console or menu FS_MakePath_BUF (FS_USERDIR, &error_state, savename, sizeof(savename), Cmd_Argv(1)); if (error_state) { Con_Printf ("%s: save directory name too long\n", __thisfunc__); return; } Con_Printf ("Loading game from %s...\n", savename); if (q_snprintf(savedest, sizeof(savedest), "%s/info.dat", savename) >= (int)sizeof(savedest)) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return; } f = fopen (savedest, "r"); if (!f) { Con_Printf ("%s: ERROR: couldn't open savefile\n", __thisfunc__); return; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } fscanf (f, "%s\n", str); for (i = 0; i < NUM_SPAWN_PARMS; i++) fscanf (f, "%f\n", &spawn_parms[i]); // this silliness is so we can load 1.06 save files, which have float skill values fscanf (f, "%f\n", &tempf); current_skill = (int)(tempf + 0.1); Cvar_SetValue ("skill", current_skill); Cvar_Set ("deathmatch", "0"); Cvar_Set ("coop", "0"); Cvar_Set ("teamplay", "0"); Cvar_Set ("randomclass", "0"); fscanf (f, "%s\n", mapname); fscanf (f, "%f\n", &playtime); tempi = -1; fscanf (f, "%d\n", &tempi); if (tempi >= 1) svs.maxclients = tempi; tempf = -1; fscanf (f, "%f\n", &tempf); if (tempf >= 0) Cvar_SetValue ("deathmatch", tempf); tempf = -1; fscanf (f, "%f\n", &tempf); if (tempf >= 0) Cvar_SetValue ("coop", tempf); tempf = -1; fscanf (f, "%f\n", &tempf); if (tempf >= 0) Cvar_SetValue ("teamplay", tempf); tempf = -1; fscanf (f, "%f\n", &tempf); if (tempf >= 0) Cvar_SetValue ("randomclass", tempf); tempf = -1; fscanf (f, "%f\n", &tempf); if (tempf >= 0) Cvar_SetValue ("_cl_playerclass", tempf); // mission pack, objectives strings fscanf (f, "%u\n", &info_mask); fscanf (f, "%u\n", &info_mask2); fclose (f); Host_RemoveGIPFiles(FS_GetUserdir()); FS_MakePath_BUF (FS_USERDIR, NULL, savedest, sizeof(savedest), Cmd_Argv(1)); error_state = Host_CopyFiles(savedest, "*.gip", FS_GetUserdir()); if (error_state) { Host_Error ("%s: The game could not be loaded properly!", __thisfunc__); return; } if (LoadGamestate(mapname, NULL, 2) != 0) return; SV_SaveSpawnparms (); ent = EDICT_NUM(1); Cvar_SetValue ("_cl_playerclass", ent->v.playerclass);//this better be the same as above... // this may be rudundant with the setting in PR_LoadProgs, but not sure so its here too if (sv_globals.cl_playerclass) *sv_globals.cl_playerclass = ent->v.playerclass; svs.clients->playerclass = ent->v.playerclass; sv.paused = true; // pause until all clients connect sv.loadgame = true; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } }
static void Host_Loadgame_f (void) { dstring_t *name = 0; QFile *f; char *mapname = 0; script_t *script = 0; plitem_t *game = 0; plitem_t *list; plitem_t *item; char *script_data = 0; int i; int entnum; int count; int version; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) goto end; if (Cmd_Argc () != 2) { Sys_Printf ("load <savename> : load a game\n"); goto end; } cls.demonum = -1; // stop demo loop in case this fails name = dstring_newstr (); dsprintf (name, "%s/%s", qfs_gamedir->dir.def, Cmd_Argv (1)); QFS_DefaultExtension (name, ".sav"); cl.loading = true; CL_UpdateScreen (cl.time); Sys_Printf ("Loading game from %s...\n", name->str); f = QFS_Open (name->str, "rz"); if (!f) { Sys_Printf ("ERROR: couldn't open.\n"); goto end; } script_data = malloc (Qfilesize (f) + 1); i = Qread (f, script_data, Qfilesize (f)); script_data[i] = 0; Qclose (f); script = Script_New (); script->single = ""; // disable {}()': lexing Script_Start (script, name->str, script_data); Script_GetToken (script, 1); if (strequal (script->token->str, PACKAGE_NAME)) { if (!Script_TokenAvailable (script, 1)) { Sys_Printf ("Unexpected EOF reading %s\n", name->str); goto end; } game = PL_GetPropertyList (script->p); } else { sscanf (script->token->str, "%i", &version); if (version != SAVEGAME_VERSION) { Sys_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); goto end; } game = convert_to_game_dict (script); } item = PL_ObjectForKey (game, "spawn_parms"); for (i = 0; i < NUM_SPAWN_PARMS; i++) { if (i >= PL_A_NumObjects (item)) break; spawn_parms[i] = atof (PL_String (PL_ObjectAtIndex (item, i))); } current_skill = atoi (PL_String (PL_ObjectForKey (game, "current_skill"))); Cvar_SetValue (skill, current_skill); mapname = strdup (PL_String (PL_ObjectForKey (game, "name"))); CL_Disconnect_f (); SV_SpawnServer (mapname); if (!sv.active) { Sys_Printf ("Couldn't load map %s\n", mapname); goto end; } sv.paused = true; // pause until all clients connect sv.loadgame = true; list = PL_ObjectForKey (game, "lightstyles"); for (i = 0; i < MAX_LIGHTSTYLES; i++) { const char *style; char *str; if (i >= PL_A_NumObjects (list)) break; item = PL_ObjectAtIndex (list, i); style = PL_String (item); sv.lightstyles[i] = str = Hunk_Alloc (strlen (style) + 1); strcpy (str, style); } ED_InitGlobals (&sv_pr_state, PL_ObjectForKey (game, "globals")); list = PL_ObjectForKey (game, "entities"); entnum = 0; count = PL_A_NumObjects (list); if (count > sv.max_edicts) Host_Error ("too many entities in saved game. adjust max_edicts\n"); for (entnum = 0; entnum < count; entnum++) { plitem_t *entity = PL_ObjectAtIndex (list, entnum); edict_t *ent = EDICT_NUM (&sv_pr_state, entnum); memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); ent->free = false; ED_InitEntity (&sv_pr_state, entity, ent); // link it into the bsp tree if (!ent->free) SV_LinkEdict (ent, false); } sv.num_edicts = entnum; sv.time = atof (PL_String (PL_ObjectForKey (game, "time"))); for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } end: if (game) PL_Free (game); if (mapname) free (mapname); if (script) Script_Delete (script); if (script_data) free (script_data); if (name) dstring_delete (name); }