/* The entities are directly placed in the array, rather than allocated with ED_Alloc, because otherwise an error loading the map would have entity number references out of order. Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. Used for both fresh maps and savegame loads. A fresh map would also need to call ED_CallSpawnFunctions () to let the objects initialize themselves. */ void ED_LoadFromFile(char *data) { ServerEntity_t *eEntity = NULL; for(;;) { // parse the opening brace data = COM_Parse(data); if(!data) break; if(com_token[0] != '{') Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); if(!eEntity) eEntity = EDICT_NUM(0); else eEntity = ED_Alloc(); data = ED_ParseEdict(data,eEntity); // Immediately call spawn function if(!Game->Server_SpawnEntity(eEntity)) { if(developer.value) Edict_Print(eEntity); ED_Free(eEntity); continue; } } }
/* DESCRIPTION: ED_LoadFromFile // LOCATION: pr_edict.c, but it's conspicuously absent in FTEQW. // PATH: SV_LoadEntities // // To quote the text block that came with it: // The entities are directly placed in the array, rather than allocated with // ED_Alloc, because otherwise an error loading the map would have entity // number references out of order. // // Creates a server's entity / program execution context by // parsing textual entity definitions out of an ent file. // // Used for both fresh maps and savegame loads. A fresh map would also need // to call ED_CallSpawnFunctions () to let the objects initialize themselves. */ void ED_LoadFromFile(const char *data) { edict_t *ent; int inhibit; ent = NULL; inhibit = 0; gGlobalVariables.time = global_sv.time0c; //parse ents while(1) { // parse the opening brace data = COM_Parse(data); if(data == NULL) { break; } if(global_com_token[0] != '{') { Sys_Error ("%s: found %s when expecting {", __FUNCTION__, global_com_token); } if(ent == NULL) { ent = &(global_sv.edicts[0]); ReleaseEntityDLLFields(ent); InitEntityDLLFields(ent); } else { ent = ED_Alloc(); } data = ED_ParseEdict(data, ent); // remove things from different skill levels or deathmatch if(cvar_deathmatch.value != 0) { if((ent->v.spawnflags & 0x800) != 0) { //SPAWNFLAG_NOT_DEATHMATCH ED_Free(ent); inhibit++; continue; } } // immediately call spawn function if(ent->v.classname == 0) { Con_Printf("%s: Ent with no classname.\n", __FUNCTION__); ED_Free(ent); continue; } if(gEntityInterface.pfnSpawn(ent) < 0 || ent->v.flags & FL_KILLME) { ED_Free(ent); } } Con_Printf("%i entities inhibited\n", inhibit); }
/* ================ ED_LoadFromFile The entities are directly placed in the array, rather than allocated with ED_Alloc, because otherwise an error loading the map would have entity number references out of order. Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. Used for both fresh maps and savegame loads. A fresh map would also need to call ED_CallSpawnFunctions () to let the objects initialize themselves. ================ */ void ED_LoadFromFile (char *data) { extern cvar_t cl_curlybraces; edict_t *ent; int inhibit; dfunction_t *func; float curlybraces_oldvalue = cl_curlybraces.value; if (curlybraces_oldvalue) { Cvar_SetValue(&cl_curlybraces, 0); } ent = NULL; inhibit = 0; pr_global_struct->time = sv.time; // parse ents while (1) { // parse the opening brace data = COM_Parse (data); if (!data) break; if (com_token[0] != '{') SV_Error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = EDICT_NUM(0); else ent = ED_Alloc (); data = ED_ParseEdict (data, ent); // remove things from different skill levels or deathmatch if ((int)deathmatch.value) { if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) { ED_Free (ent); inhibit++; continue; } } else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) { ED_Free (ent); inhibit++; continue; } // // immediately call spawn function // if (!ent->v.classname) { Con_Printf ("No classname for:\n"); ED_Print (ent); ED_Free (ent); continue; } // look for the spawn function func = ED_FindFunction ( PR_GetString(ent->v.classname) ); if (!func) { Con_Printf ("No spawn function for:\n"); ED_Print (ent); ED_Free (ent); continue; } pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (func - pr_functions); SV_FlushSignon(); } Con_DPrintf ("%i entities inhibited\n", inhibit); if (curlybraces_oldvalue) { Cvar_SetValue(&cl_curlybraces, curlybraces_oldvalue); } }
/* =============== Host_Loadgame_f =============== */ void Host_Loadgame_f (void) { char name[MAX_OSPATH]; FILE *f; char mapname[MAX_QPATH]; float time, tfloat; char *str, *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 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); COM_DefaultExtension (name, ".sav"); #define LOAD_BUFFER_SIZE (4096) str = (char*)malloc(LOAD_BUFFER_SIZE); if(str == 0) { Con_Printf ("ERROR: couldn't malloc %d.\n",LOAD_BUFFER_SIZE); goto cleanup; } // 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"); goto cleanup; //return; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); goto cleanup; //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) { Con_Printf ("Couldn't load map\n"); goto cleanup; //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] = (char *)Hunk_Alloc (strlen(str)+1); strcpy (sv.lightstyles[i], str); } //Con_Printf("%d\n",__LINE__); //waitforit(); // load the edicts out of the savegame file entnum = -1; // -1 is the globals while (!feof(f)) { for (i=0 ; i<LOAD_BUFFER_SIZE-1 ; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (i == LOAD_BUFFER_SIZE-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 while(entnum >= sv.num_edicts) { ED_Alloc(); } 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; //waitforit(); 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 (); } cleanup: if(str) free(str); }