/* 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); }
void Server_MakeStatic(ServerEntity_t *ent) { int i,bits=0; if(ent->alpha == ENTALPHA_ZERO) { ED_Free(ent); return; } if(SV_ModelIndex(ent->v.model) & 0xFF00) bits |= B_LARGEMODEL; if((int)(ent->v.frame) & 0xFF00) bits |= B_LARGEFRAME; if(ent->alpha != ENTALPHA_DEFAULT) bits |= B_ALPHA; if(bits) { MSG_WriteByte(&sv.signon, SVC_SPAWNSTATIC2); MSG_WriteByte(&sv.signon, bits); } else MSG_WriteByte(&sv.signon, svc_spawnstatic); if(bits & B_LARGEMODEL) MSG_WriteShort(&sv.signon, SV_ModelIndex(ent->v.model)); else MSG_WriteByte(&sv.signon, SV_ModelIndex(ent->v.model)); if(bits & B_LARGEFRAME) MSG_WriteShort(&sv.signon,ent->v.frame); else MSG_WriteByte(&sv.signon,ent->v.frame); MSG_WriteByte(&sv.signon,ent->Model.fScale); MSG_WriteByte(&sv.signon,ent->v.colormap); MSG_WriteByte(&sv.signon,ent->Model.iSkin); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, ent->v.origin[i]); MSG_WriteAngle(&sv.signon, ent->v.angles[i]); } if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, ent->alpha); ED_Free (ent); }
/** * @brief free the mapbrush_t::nearBrushes, compositeSides and entitiesdef.h stuff. */ void Check_Free (void) { int i; ED_Free(); for (i = 0; i < nummapbrushes; i++) { mapbrush_t *iBrush = &mapbrushes[i]; if (iBrush->numNear) { assert(iBrush->nearBrushes); Mem_Free(iBrush->nearBrushes); iBrush->numNear = 0; iBrush->nearBrushes = NULL; } } for (i = 0; i < numCompositeSides; i++) { compositeSide_t *cs = &compositeSides[i]; if (cs->numMembers) { assert(cs->memberSides); Mem_Free(cs->memberSides); cs->numMembers = 0; cs->memberSides = NULL; } } }
/* 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; } } }
void EntityClassScannerUFO::scanFile (EntityClassCollector& collector) { const std::string& filename = getFilename(); AutoPtr<ArchiveTextFile> file(GlobalFileSystem().openTextFile(filename)); if (!file) { std::string buffer = "Could not load " + filename; gtkutil::errorDialog(buffer); return; } const std::size_t size = file->size(); char* entities = (char*) malloc(size + 1); TextInputStream &stream = file->getInputStream(); const std::size_t realsize = stream.read(entities, size); entities[realsize] = '\0'; if (ED_Parse(entities) == ED_ERROR) { std::string buffer = "Parsing of entities definition file failed, returned error was " + std::string( ED_GetLastError()); gtkutil::errorDialog(buffer); } else { for (int i = 0; i < numEntityDefs; i++) { EntityClass *e = initFromDefinition(&entityDefs[i]); if (e) collector.insert(e); } } free(entities); ED_Free(); }
/* ================ 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[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 (); } }