void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) { if ( qbLoadTransition ) { //loadtransitions do not need to read the objectives and client data from the level they're going to //In a loadtransition, client data is carried over on the server and will be stomped later anyway. //The objective info (in client->sess data), however, is read in from G_ReadSessionData which is called before this func, //we do NOT want to stomp that session data when doing a load transition //However, we should still save this info out because these savegames may need to be //loaded normally later- perhaps if you die and need to respawn, perhaps as some kind //of emergency savegame for resuming, etc. //SO: We read it in, but throw it away. //Read & throw away gclient info gclient_t junkClient; EvaluateFields(savefields_gClient, (byte *)&junkClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse); //Read & throw away objective info objectives_t junkObj[MAX_MISSION_OBJ]; gi.ReadFromSaveGame('OBJT', (void *) &junkObj, 0, NULL); ReadLevelLocals(); // level_locals_t level } else { if (!qbAutosave )//always load the client unless it's an autosave { assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way things work gclient_t GClient; EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse); level.clients[0] = GClient; // struct copy ReadLevelLocals(); // level_locals_t level } OBJ_LoadObjectiveData();//loads mission objectives AND tactical info } ///////////// ReadGEntities(qbAutosave); Q3_VariableLoad(); G_LoadSave_ReadMiscData(); extern void CG_ReadTheEvilCGHackStuff(void); CG_ReadTheEvilCGHackStuff(); // (Do NOT put any read-code below this line) // // check that the whole file content was loaded by specifically requesting an end-marker... // static int iDONE = 1234; gi.ReadFromSaveGame('DONE', &iDONE, sizeof(iDONE), NULL); }
/* ================= ReadLevel SpawnEntities will allready have been called on the level the same way it was when the level was saved. That is necessary to get the baselines set up identically. The server will have cleared all of the world links before calling ReadLevel. No clients are connected yet. ================= */ void ReadLevel (char *filename) { int entnum; FILE *f; int i; void *base; edict_t *ent; f = fopen (filename, "rb"); if (!f) gi.error ("Couldn't open %s", filename); // free any dynamic memory allocated by loading the level // base state gi.FreeTags (TAG_LEVEL); // wipe all the entities memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0])); globals.num_edicts = maxclients->value+1; // check edict size fread (&i, sizeof(i), 1, f); if (i != sizeof(edict_t)) { fclose (f); gi.error ("ReadLevel: mismatched edict size"); } // check function pointer base address fread (&base, sizeof(base), 1, f); if (base != (void *)InitGame) { fclose (f); gi.error ("ReadLevel: function pointers have moved"); } // load the level locals ReadLevelLocals (f); // load all the entities while (1) { if (fread (&entnum, sizeof(entnum), 1, f) != 1) { fclose (f); gi.error ("ReadLevel: failed to read entnum"); } if (entnum == -1) break; if (entnum >= globals.num_edicts) globals.num_edicts = entnum+1; ent = &g_edicts[entnum]; ReadEdict (f, ent); // let the server rebuild world links for this ent memset (&ent->area, 0, sizeof(ent->area)); gi.linkentity (ent); } fclose (f); // mark all clients as unconnected for (i=0 ; i<maxclients->value ; i++) { ent = &g_edicts[i+1]; ent->client = game.clients + i; ent->client->pers.connected = false; } // do any load time things at this point for (i=0 ; i<globals.num_edicts ; i++) { ent = &g_edicts[i]; if (!ent->inuse) continue; // fire any cross-level triggers if (ent->classname) if (strcmp(ent->classname, "target_crosslevel_target") == 0) ent->nextthink = level.time + ent->delay; } }
void ReadLevel (char *filename) { int entnum; FILE *f; int i; void *base; edict_t *ent; if(developer->value) gi.dprintf ("==== ReadLevel ====\n"); f = fopen (filename, "rb"); if (!f) gi.error ("Couldn't open %s", filename); // free any dynamic memory allocated by loading the level // base state gi.FreeTags (TAG_LEVEL); // wipe all the entities memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0])); globals.num_edicts = maxclients->value+1; // check edict_t size fread (&i, sizeof(i), 1, f); if (i != sizeof(edict_t)) { fclose (f); gi.error ("ReadLevel: mismatched edict_t size"); } // check function pointer base address fread (&base, sizeof(base), 1, f); /* Lazarus: The __DATE__ check in ReadGame is sufficient for a version check. The following is reported to fail under some circumstances (though I've never seen it). #ifdef _WIN32 if (base != (void *)InitGame) { fclose (f); gi.error ("ReadLevel: function pointers have moved"); } #else gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame)); #endif */ // load the level locals ReadLevelLocals (f); // load all the entities while (1) { if (fread (&entnum, sizeof(entnum), 1, f) != 1) { fclose (f); gi.error ("ReadLevel: failed to read entnum"); } if (entnum == -1) break; if (entnum >= globals.num_edicts) globals.num_edicts = entnum+1; ent = &g_edicts[entnum]; ReadEdict(f, ent); // let the server rebuild world links for this ent memset (&ent->area, 0, sizeof(ent->area)); gi.linkentity (ent); } fclose (f); // mark all clients as unconnected for (i=0 ; i<maxclients->value ; i++) { ent = &g_edicts[i+1]; ent->client = game.clients + i; ent->client->pers.connected = false; } // do any load time things at this point for (i=0 ; i<globals.num_edicts ; i++) { ent = &g_edicts[i]; if (!ent->inuse) continue; // fire any cross-level triggers if (ent->classname) if (strcmp(ent->classname, "target_crosslevel_target") == 0) ent->nextthink = level.time + ent->delay; } // DWH: Load transition entities if(game.transition_ents) { LoadTransitionEnts(); actor_files(); } }
/* * Reads a level back into the memory. * SpawnEntities were allready called * in the same way when the level was * saved. All world links were cleared * befor this function was called. When * this function is called, no clients * are connected to the server. */ void ReadLevel(const char *filename) { int entnum; FILE *f; int i; edict_t *ent; f = fopen(filename, "rb"); if (!f) { gi.error("Couldn't open %s", filename); } /* free any dynamic memory allocated by loading the level base state */ gi.FreeTags(TAG_LEVEL); /* wipe all the entities */ memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); globals.num_edicts = maxclients->value + 1; /* check edict size */ fread(&i, sizeof(i), 1, f); if (i != sizeof(edict_t)) { fclose(f); gi.error("ReadLevel: mismatched edict size"); } /* load the level locals */ ReadLevelLocals(f); /* load all the entities */ while (1) { if (fread(&entnum, sizeof(entnum), 1, f) != 1) { fclose(f); gi.error("ReadLevel: failed to read entnum"); } if (entnum == -1) { break; } if (entnum >= globals.num_edicts) { globals.num_edicts = entnum + 1; } ent = &g_edicts[entnum]; ReadEdict(f, ent); /* let the server rebuild world links for this ent */ memset(&ent->area, 0, sizeof(ent->area)); gi.linkentity(ent); } fclose(f); /* mark all clients as unconnected */ for (i = 0; i < maxclients->value; i++) { ent = &g_edicts[i + 1]; ent->client = game.clients + i; ent->client->pers.connected = false; } /* do any load time things at this point */ for (i = 0; i < globals.num_edicts; i++) { ent = &g_edicts[i]; if (!ent->inuse) { continue; } /* fire any cross-level triggers */ if (ent->classname) { if (strcmp(ent->classname, "target_crosslevel_target") == 0) { ent->nextthink = level.time + ent->delay; } } } }
void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) { if ( qbLoadTransition ) { // I STRONGLY SUSPECT THAT THIS WILL JUST ERR_DROP BECAUSE OF THE LOAD SWAPPING OF THE CHUNK-ORDER // BELOW BETWEEN OBJECTIVES AND LEVEL_LOCALS, SO I'M GUESSING THIS IS SOME OLD EF1 JUNK? // IN ANY CASE, LET'S MAKE SURE... // -ste (no idea who wrote the comment stuff below, did it ever work?) // assert(0); // //loadtransitions do not need to read the objectives and client data from the level they're going to //In a loadtransition, client data is carried over on the server and will be stomped later anyway. //The objective info (in client->sess data), however, is read in from G_ReadSessionData which is called before this func, //we do NOT want to stomp that session data when doing a load transition //However, we should still save this info out because these savegames may need to be //loaded normally later- perhaps if you die and need to respawn, perhaps as some kind //of emergency savegame for resuming, etc. //SO: We read it in, but throw it away. //Read & throw away gclient info gclient_t junkClient; EvaluateFields(savefields_gClient, (byte *)&junkClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qtrue);//qfalse); ReadLevelLocals(); // level_locals_t level //Read & throw away objective info objectives_t junkObj[MAX_MISSION_OBJ]; gi.ReadFromSaveGame('OBJT', (void *) &junkObj, 0); } else { if (!qbAutosave )//always load the client unless it's an autosave { assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way things work gclient_t GClient; EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qtrue);//qfalse); level.clients[0] = GClient; // struct copy ReadLevelLocals(); // level_locals_t level } OBJ_LoadObjectiveData();//loads mission objectives AND tactical info } FX_Read(); ///////////// ReadGEntities(qbAutosave); Quake3Game()->VariableLoad(); G_LoadSave_ReadMiscData(); extern void CG_ReadTheEvilCGHackStuff(void); CG_ReadTheEvilCGHackStuff(); // (Do NOT put any read-code below this line) // // check that the whole file content was loaded by specifically requesting an end-marker... // static int iDONE = 1234; gi.ReadFromSaveGame('DONE', &iDONE, sizeof(iDONE)); }