void Host_LoadStrings (void) { int i, count, start; signed char newline_char; host_strings = (char *)FS_LoadHunkFile ("strings.txt", NULL); if (!host_strings) Host_Error ("%s: couldn't load strings.txt", __thisfunc__); newline_char = -1; for (i = count = 0; host_strings[i] != 0; i++) { if (host_strings[i] == '\r' || host_strings[i] == '\n') { if (newline_char == host_strings[i] || newline_char == -1) { newline_char = host_strings[i]; count++; } } } if (!count) { Host_Error ("%s: no string lines found", __thisfunc__); } host_string_index = (int *)Hunk_AllocName ((count + 1)*sizeof(int), "string_index"); for (i = count = start = 0; host_strings[i] != 0; i++) { if (host_strings[i] == '\r' || host_strings[i] == '\n') { if (newline_char == host_strings[i]) { host_string_index[count] = start; start = i + 1; count++; } else { start++; } host_strings[i] = 0; } #if defined(H2W) /* Hexenworld: translate '^' to * '\n' for indexed prints */ else if (host_strings[i] == '^') { host_strings[i] = '\n'; } #endif /* H2W */ } host_string_count = count; Con_DPrintf("Read in %d string lines\n", count); }
/* =============== Cmd_Exec_f =============== */ void Cmd_Exec_f (void) { char *f; int mark; if (Cmd_Argc () != 2) { Con_Printf ("exec <filename> : execute a script file\n"); return; } // FIXME: is this safe freeing the hunk here??? mark = Hunk_LowMark (); f = (char *)FS_LoadHunkFile (Cmd_Argv(1), NULL); if (!f) { Con_Printf ("couldn't exec %s\n",Cmd_Argv(1)); return; } Con_Printf ("execing %s\n",Cmd_Argv(1)); Cbuf_InsertText (f); Hunk_FreeToLowMark (mark); }
static unsigned SV_CheckModel(char *mdl) { unsigned char *buf; unsigned short crc; int filesize; int mark; mark = Hunk_LowMark (); buf = (byte *) FS_LoadHunkFile (mdl, &filesize); if (!buf) { if (!strcmp (mdl, "progs/player.mdl")) return 33168; else if (!strcmp (mdl, "progs/newplayer.mdl")) return 62211; else if (!strcmp (mdl, "progs/eyes.mdl")) return 6967; else SV_Error ("SV_CheckModel: could not load %s\n", mdl); } crc = CRC_Block (buf, filesize); Hunk_FreeToLowMark (mark); return crc; }
/* =============== Cmd_Exec_f =============== */ void Cmd_Exec_f (void) { char *f; int mark; char name[MAX_OSPATH]; if (Cmd_Argc () != 2) { Com_Printf ("exec <filename> : execute a script file\n"); return; } strlcpy (name, Cmd_Argv(1), sizeof(name) - 4); mark = Hunk_LowMark (); f = (char *)FS_LoadHunkFile (name); if (!f) { char *p; p = COM_SkipPath (name); if (!strchr (p, '.')) { // no extension, so try the default (.cfg) strcat (name, ".cfg"); f = (char *)FS_LoadHunkFile (name); } if (!f) { Com_Printf ("couldn't exec %s\n", Cmd_Argv(1)); return; } } if (cl_warncmd.value || developer.value) Com_Printf ("execing %s\n", name); #ifndef SERVERONLY if (cbuf_current == &cbuf_svc) { Cbuf_AddText (f); Cbuf_AddText ("\n"); } else #endif { Cbuf_InsertText ("\n"); Cbuf_InsertText (f); } Hunk_FreeToLowMark (mark); }
void PR_LoadProgs (void) { int i; char num[32]; char name[MAX_OSPATH]; int filesize; // flush the non-C variable lookup cache for (i = 0; i < GEFV_CACHESIZE; i++) gefvCache[i].field[0] = 0; // clear pr_newstrtbl PF_clear_strtbl(); snprintf(name, sizeof(name), "%s.dat", sv_progsname.string); progs = (dprograms_t *)FS_LoadHunkFile (name, &filesize); if (!progs) progs = (dprograms_t *)FS_LoadHunkFile ("qwprogs.dat", &filesize); if (!progs) progs = (dprograms_t *)FS_LoadHunkFile ("spprogs.dat", &filesize); #ifdef WITH_NQPROGS pr_nqprogs = false; if (!progs || Cvar_Value("sv_forcenqprogs")) { progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat", &filesize); if (progs) pr_nqprogs = true; } #endif if (!progs) SV_Error ("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf ("Programs occupy %iK.\n", filesize/1024); // add prog crc to the serverinfo snprintf (num, sizeof(num), "%i", CRC_Block ((byte *)progs, filesize)); #ifdef USE_PR2 Info_SetStar( &_localinfo_, "*qvm", "DAT" ); // Info_SetValueForStarKey (svs.info, "*qvm", "DAT", MAX_SERVERINFO_STRING); #endif Info_SetValueForStarKey (svs.info, "*progs", num, MAX_SERVERINFO_STRING); // byte swap the header for (i = 0; i < (int) sizeof(*progs) / 4 ; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) SV_Error ("qwprogs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != (pr_nqprogs ? NQ_PROGHEADER_CRC : PROGHEADER_CRC)) SV_Error ("You must have the qwprogs.dat from QuakeWorld installed"); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); num_prstr = 0; pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); // byte swap the lumps for (i = 0; i < progs->numstatements; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i = 0; i < progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i = 0; i < progs->numglobaldefs; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } for (i = 0; i < progs->numfielddefs; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) SV_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); } for (i = 0; i < progs->numglobals; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); #ifdef WITH_NQPROGS PR_InitPatchTables(); #endif // find optional QC-exported functions SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); ChatMessage = ED_FindFunctionOffset ("ChatMessage"); UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed"); mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd"); mod_UserCmd = ED_FindFunctionOffset ("UserCmd"); localinfoChanged = ED_FindFunctionOffset ("localinfoChanged"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); CheckKTPro (); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is only called from the SV_Map_f() function. ================ */ void SV_SpawnServer (char *mapname, qbool devmap, char* entityfile) { extern func_t ED_FindFunctionOffset (char *name); edict_t *ent; int i; extern cvar_t sv_loadentfiles, sv_loadentfiles_dir; char *entitystring; char oldmap[MAP_NAME_LEN]; extern qbool sv_allow_cheats; extern cvar_t sv_cheats, sv_paused, sv_bigcoords; #ifndef SERVERONLY extern void CL_ClearState (void); #endif // store old map name snprintf (oldmap, MAP_NAME_LEN, "%s", sv.mapname); Con_DPrintf ("SpawnServer: %s\n",mapname); #ifndef SERVERONLY // As client+server we do it here. // As serveronly we do it in NET_Init(). NET_InitServer(); #endif SV_SaveSpawnparms (); SV_LoadAccounts(); #ifdef USE_PR2 // remove bot clients for (i = 0; i < MAX_CLIENTS; i++) { if( sv_vm && svs.clients[i].isBot ) { svs.clients[i].old_frags = 0; svs.clients[i].edict->v.frags = 0.0; svs.clients[i].name[0] = 0; svs.clients[i].state = cs_free; Info_RemoveAll(&svs.clients[i]._userinfo_ctx_); Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_); SV_FullClientUpdate(&svs.clients[i], &sv.reliable_datagram); svs.clients[i].isBot = 0; } } #endif // Shutdown game. PR_GameShutDown(); PR_UnLoadProgs(); svs.spawncount++; // any partially connected client will be restarted #ifndef SERVERONLY com_serveractive = false; #endif sv.state = ss_dead; sv.paused = false; Cvar_SetROM(&sv_paused, "0"); Host_ClearMemory(); #ifdef FTE_PEXT_FLOATCOORDS if (sv_bigcoords.value) { msg_coordsize = 4; msg_anglesize = 2; } else { msg_coordsize = 2; msg_anglesize = 1; } #endif if ((int)coop.value) Cvar_Set (&deathmatch, "0"); current_skill = (int) (skill.value + 0.5); if (current_skill < 0) current_skill = 0; Cvar_Set (&skill, va("%d", current_skill)); if (current_skill > 3) current_skill = 3; if ((sv_cheats.value || devmap) && !sv_allow_cheats) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) { sv_allow_cheats = false; Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } // wipe the entire per-level structure // NOTE: this also set sv.mvdrecording to false, so calling SV_MVD_Record() at end of function memset (&sv, 0, sizeof(sv)); sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.data = sv.datagram_buf; sv.datagram.allowoverflow = true; sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); sv.reliable_datagram.data = sv.reliable_datagram_buf; sv.multicast.maxsize = sizeof(sv.multicast_buf); sv.multicast.data = sv.multicast_buf; sv.signon.maxsize = sizeof(sv.signon_buffers[0]); sv.signon.data = sv.signon_buffers[0]; sv.num_signon_buffers = 1; sv.time = 1.0; // load progs to get entity field count // which determines how big each edict is // and allocate edicts PR_LoadProgs (); #ifdef WITH_NQPROGS PR_InitPatchTables(); #endif PR_InitProg(); for (i = 0; i < MAX_EDICTS; i++) { ent = EDICT_NUM(i); ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t ent->e->entnum = i; ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t) } fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension fofs_maxspeed = ED_FindFieldOffset ("maxspeed"); fofs_gravity = ED_FindFieldOffset ("gravity"); fofs_movement = ED_FindFieldOffset ("movement"); fofs_vw_index = ED_FindFieldOffset ("vw_index"); fofs_hideentity = ED_FindFieldOffset ("hideentity"); fofs_trackent = ED_FindFieldOffset ("trackent"); // find optional QC-exported functions. // we have it here, so we set it to NULL in case of PR2 progs. mod_SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); mod_SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); mod_SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); mod_ChatMessage = ED_FindFunctionOffset ("ChatMessage"); mod_UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed"); mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd"); mod_UserCmd = ED_FindFunctionOffset ("UserCmd"); mod_localinfoChanged = ED_FindFunctionOffset ("localinfoChanged"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); // leave slots at start for clients only sv.num_edicts = MAX_CLIENTS+1; for (i=0 ; i<MAX_CLIENTS ; i++) { ent = EDICT_NUM(i+1); // restore client name. ent->v.netname = PR_SetString(svs.clients[i].name); // reserve edict. svs.clients[i].edict = ent; //ZOID - make sure we update frags right svs.clients[i].old_frags = 0; } // fill sv.mapname and sv.modelname with new map name strlcpy (sv.mapname, mapname, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); #ifndef SERVERONLY // set cvar Cvar_ForceSet (&host_mapname, mapname); #endif if (!(sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2))) // true if bad map { Con_Printf ("Cant load map %s, falling back to %s\n", mapname, oldmap); // fill mapname, sv.mapname and sv.modelname with old map name strlcpy (sv.mapname, oldmap, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); mapname = oldmap; // and re-load old map sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2); // this should never happen if (!sv.worldmodel) SV_Error ("CM_LoadMap: bad map"); } sv.map_checksum2 = Com_TranslateMapChecksum (sv.mapname, sv.map_checksum2); SV_ClearWorld (); // clear physics interaction links #ifdef USE_PR2 if ( sv_vm ) { sv.sound_precache[0] = ""; sv.model_precache[0] = ""; } else #endif { sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; } sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; for (i=1 ; i< CM_NumInlineModels() ; i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i+1] = CM_InlineModel (localmodels[i]); } //check player/eyes models for hacks sv.model_player_checksum = SV_CheckModel("progs/player.mdl"); sv.model_newplayer_checksum = SV_CheckModel("progs/newplayer.mdl"); sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl"); // // spawn the rest of the entities on the map // // precache and static commands can be issued during // map initialization sv.state = ss_loading; #ifndef SERVERONLY com_serveractive = true; #endif ent = EDICT_NUM(0); ent->e->free = false; ent->v.model = PR_SetString(sv.modelname); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; // information about the server ent->v.netname = PR_SetString(VersionStringFull()); ent->v.targetname = PR_SetString(SERVER_NAME); ent->v.impulse = VERSION_NUM; ent->v.items = pr_numbuiltins - 1; PR_GLOBAL(mapname) = PR_SetString(sv.mapname); // serverflags are for cross level information (sigils) PR_GLOBAL(serverflags) = svs.serverflags; if (pr_nqprogs) { pr_globals[35] = deathmatch.value; pr_globals[36] = coop.value; pr_globals[37] = teamplay.value; NQP_Reset (); } if (pr_nqprogs) { // register the cvars that NetQuake provides for mod use const char **var, *nqcvars[] = {"gamecfg", "scratch1", "scratch2", "scratch3", "scratch4", "saved1", "saved2", "saved3", "saved4", "savedgamecfg", "temp1", NULL}; for (var = nqcvars; *var; var++) Cvar_Create((char *)/*stupid const warning*/ *var, "0", 0); } // run the frame start qc function to let progs check cvars if (!pr_nqprogs) SV_ProgStartFrame (); // ********* External Entity support (.ent file(s) in gamedir/maps) pinched from ZQuake ********* // load and spawn all other entities entitystring = NULL; if ((int)sv_loadentfiles.value) { char ent_path[1024] = {0}; if (!entityfile || !entityfile[0]) entityfile = sv.mapname; // first try maps/sv_loadentfiles_dir/ if (sv_loadentfiles_dir.string[0]) { snprintf(ent_path, sizeof(ent_path), "maps/%s/%s.ent", sv_loadentfiles_dir.string, entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } // try maps/ if not loaded yet. if (!entitystring) { snprintf(ent_path, sizeof(ent_path), "maps/%s.ent", entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } if (entitystring) { Con_DPrintf ("Using entfile %s\n", ent_path); } } if (!entitystring) { entitystring = CM_EntityString(); } PR_LoadEnts(entitystring); // ********* End of External Entity support code ********* // look up some model indexes for specialized message compression SV_FindModelNumbers (); // all spawning is completed, any further precache statements // or prog writes to the signon message are errors sv.state = ss_active; // run two frames to allow everything to settle SV_Physics (); sv.time += 0.1; SV_Physics (); sv.time += 0.1; sv.old_time = sv.time; // save movement vars SV_SetMoveVars(); // create a baseline for more efficient communications SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize; Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING); // calltimeofday. { extern void PF_calltimeofday (void); pr_global_struct->time = sv.time; pr_global_struct->self = 0; PF_calltimeofday(); } Con_DPrintf ("Server spawned.\n"); // we change map - clear whole demo struct and sent initial state to all dest if any (for QTV only I thought) SV_MVD_Record(NULL, true); #ifndef SERVERONLY CL_ClearState (); #endif }
/* =============== PR_LoadProgs =============== */ void PR_LoadProgs (void) { int i; char num[32]; static int lumpsize[6] = { sizeof(dstatement_t), sizeof(ddef_t), sizeof(ddef_t), sizeof(dfunction_t), 4, 4 }; int filesize = 0; const char *progsname; progs = NULL; // decide whether to load qwprogs.dat, progs.dat or spprogs.dat #ifdef WITH_NQPROGS if (Cvar_Value("sv_forcenqprogs")) goto use_progs; #endif if (!deathmatch.value) { if (Q_stricmp(com_gamedirfile, "qw") && strcmp(com_gamedirfile, "")) { // if we're using a custom mod, anything // in gamedir is preferred to stock *progs.dat qbool check; check = FS_FindFile ("spprogs.dat"); if (check && file_from_gamedir) goto use_spprogs; #ifdef WITH_NQPROGS check = FS_FindFile ("progs.dat"); if (check && file_from_gamedir) goto use_progs; #endif check = FS_FindFile ("qwprogs.dat"); if (check && file_from_gamedir) goto use_qwprogs; } use_spprogs: progs = (dprograms_t *) FS_LoadHunkFile ("spprogs.dat"); progsname = "spprogs.dat"; pr_nqprogs = false; if (!progs) { #ifdef WITH_NQPROGS use_progs: progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat"); progsname = "progs.dat"; pr_nqprogs = true; } #endif if (!progs) { use_qwprogs: progs = (dprograms_t *)FS_LoadHunkFile ("qwprogs.dat"); progsname = "qwprogs.dat"; pr_nqprogs = false; } } else // deathmatch { if (Q_stricmp(com_gamedirfile, "qw") && strcmp(com_gamedirfile, "")) { qbool check; check = FS_FindFile ("qwprogs.dat"); if (check && file_from_gamedir) goto dm_use_qwprogs; #ifdef WITH_NQPROGS check = FS_FindFile ("progs.dat"); if (check && file_from_gamedir) goto dm_use_progs; #endif } dm_use_qwprogs: progs = (dprograms_t *) FS_LoadHunkFile ("qwprogs.dat"); progsname = "qwprogs.dat"; pr_nqprogs = false; if (!progs) { #ifdef WITH_NQPROGS dm_use_progs: progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat"); progsname = "progs.dat"; pr_nqprogs = true; } #endif } if (!progs) Host_Error ("PR_LoadProgs: couldn't load progs.dat"); filesize = fs_filesize; if (filesize < (int)sizeof(*progs)) Host_Error("%s is corrupt", progsname); Com_DPrintf ("Using %s (%i bytes).\n", progsname, filesize); // add prog crc to the serverinfo sprintf (num, "%i", CRC_Block ((byte *)progs, filesize)); svs.info.set("*progs", num); // byte swap the header for (i = 0; i < sizeof(*progs)/4; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != (pr_nqprogs ? NQ_PROGHEADER_CRC : PROGHEADER_CRC)) Host_Error ("You must have the qwprogs.dat from QuakeWorld installed"); // check lump offsets and sizes for (i = 0; i < 6; i ++) { if (((int *)progs)[i*2 + 2] < sizeof(*progs) || ((int *)progs)[i*2 + 2] + ((int *)progs)[i*2 + 3]*lumpsize[i] > filesize) Host_Error("progs.dat is corrupt"); } pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; PR_InitStrings (); pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); // byte swap the lumps for (i=0 ; i<progs->numstatements ; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i=0 ; i<progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i=0 ; i<progs->numglobaldefs ; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } for (i=0 ; i<progs->numfielddefs ; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); } for (i=0 ; i<progs->numglobals ; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); #ifdef WITH_NQPROGS if (pr_nqprogs) { memcpy (pr_globaloffsetpatch, pr_globaloffsetpatch_nq, sizeof(pr_globaloffsetpatch)); for (i = 0; i < 106; i++) { pr_fieldoffsetpatch[i] = (i < 8) ? i : (i < 25) ? i + 1 : (i < 28) ? i + (102 - 25) : (i < 73) ? i - 2 : (i < 74) ? i + (105 - 73) : (i < 105) ? i - 3 : /* (i == 105) */ 8; } for (i=0 ; i<progs->numfielddefs ; i++) pr_fielddefs[i].ofs = PR_FIELDOFS(pr_fielddefs[i].ofs); } else { memset (pr_globaloffsetpatch, 0, sizeof(pr_globaloffsetpatch)); for (i = 0; i < 106; i++) pr_fieldoffsetpatch[i] = i; } #endif // find optional QC-exported functions SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_ConsoleCommand = ED_FindFunctionOffset ("GE_ConsoleCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); // find optional QC-exported fields fofs_maxspeed = ED_FindFieldOffset ("maxspeed"); fofs_gravity = ED_FindFieldOffset ("gravity"); fofs_items2 = ED_FindFieldOffset ("items2"); fofs_movement = ED_FindFieldOffset ("movement"); fofs_vw_index = ED_FindFieldOffset ("vw_index"); for (i = 3; i < 8; i++) fofs_buttonX[i-3] = ED_FindFieldOffset(va("button%i", i)); // reset stuff like ZQ_CLIENTCOMMAND, progs must enable it explicitly memset (&pr_ext_enabled, sizeof(pr_ext_enabled), 0); PR_Exec_Init (); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is only called from the SV_Map_f() function. ================ */ void SV_SpawnServer (char *mapname, qbool devmap) { char *entitystring; edict_t *ent; int i; extern qbool sv_allow_cheats; extern cvar_t sv_cheats; Com_DPrintf ("SpawnServer: %s\n", mapname); NET_InitServer(); SV_SaveSpawnparms (); svs.spawncount++; // any partially connected client will be restarted sv.state = ss_dead; com_serveractive = false; Cvar_ForceSet (&sv_paused, "0"); Host_ClearMemory(); if (deathmatch.value) Cvar_Set (&coop, "0"); current_skill = (int)(skill.value + 0.5); if (current_skill < 0) current_skill = 0; if (current_skill > 3) current_skill = 3; Cvar_Set (&skill, va("%d", (int)current_skill)); if ((sv_cheats.value || devmap) && !sv_allow_cheats) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) { sv_allow_cheats = false; Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } // wipe the entire per-level structure memset (&sv, 0, sizeof(sv)); SZ_Init (&sv.datagram, sv.datagram_buf, sizeof(sv.datagram_buf)); sv.datagram.allowoverflow = true; SZ_Init (&sv.reliable_datagram, sv.reliable_datagram_buf, sizeof(sv.reliable_datagram_buf)); SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); SZ_Init (&sv.signon, sv.signon_buffers[0], sizeof(sv.signon_buffers[0])); sv.num_signon_buffers = 1; // load progs to get entity field count // which determines how big each edict is PR_LoadProgs (); // allocate edicts sv.edicts = (edict_t *) Hunk_AllocName (SV_MAX_EDICTS*pr_edict_size, "edicts"); // leave slots at start for clients only sv.num_edicts = MAX_CLIENTS+1; for (i = 0; i < MAX_CLIENTS; i++) { ent = EDICT_NUM(i+1); svs.clients[i].edict = ent; svs.clients[i].old_frags = 0; //ZOID - make sure we update frags right } sv.time = 1.0; #ifndef SERVERONLY { void R_PreMapLoad (char *mapname); R_PreMapLoad (mapname); } #endif strlcpy (sv.mapname, mapname, sizeof(sv.mapname)); Cvar_ForceSet (&host_mapname, mapname); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", mapname); sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2); // clear physics interaction links SV_ClearWorld (); sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; for (i = 1; i < CM_NumInlineModels(); i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i + 1] = CM_InlineModel (localmodels[i]); } //check player/eyes models for hacks sv.model_player_checksum = SV_CheckModel("progs/player.mdl"); sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl"); // spawn the rest of the entities on the map // precache and static commands can be issued during map initialization sv.state = ss_loading; com_serveractive = true; ent = EDICT_NUM(0); ent->free = false; ent->v.model = PR_SetString(sv.modelname); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; pr_global_struct->mapname = PR_SetString(sv.mapname); // serverflags are for cross level information (sigils) pr_global_struct->serverflags = svs.serverflags; // run the frame start qc function to let progs check cvars SV_ProgStartFrame (); // load and spawn all other entities entitystring = NULL; if ((int) sv_loadentfiles.value) { int filesize; entitystring = (char *)FS_LoadHunkFile (va("maps/%s.ent", sv.mapname), &filesize); if (entitystring) { Com_DPrintf ("Using entfile maps/%s.ent\n", sv.mapname); Info_SetValueForStarKey (svs.info, "*entfile", va("%i", CRC_Block((byte *)entitystring, filesize)), MAX_SERVERINFO_STRING); } } if (!entitystring) { Info_SetValueForStarKey (svs.info, "*entfile", "", MAX_SERVERINFO_STRING); entitystring = CM_EntityString(); } ED_LoadFromFile (entitystring); // look up some model indexes for specialized message compression SV_FindModelNumbers (); // all spawning is completed, any further precache statements // or prog writes to the signon message are errors sv.state = ss_active; // run two frames to allow everything to settle SV_Physics (); sv.time += 0.1; SV_Physics (); sv.time += 0.1; sv.old_time = sv.time; // save movement vars SV_SetMoveVars(); // create a baseline for more efficient communications SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers - 1] = sv.signon.cursize; Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING); Com_DPrintf ("Server spawned.\n"); #ifndef SERVERONLY if (!dedicated) { void CL_ClearState (void); CL_ClearState (); } #endif }