/* ====================== Host_Name_f ====================== */ static void Host_Name_f (void) { char newName[32]; char *pdest; if (Cmd_Argc () == 1) { Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); return; } if (Cmd_Argc () == 2) q_strlcpy (newName, Cmd_Argv(1), sizeof(newName)); else q_strlcpy (newName, Cmd_Args(), sizeof(newName)); newName[15] = 0; // client_t structure actually says name[32]. //this is for the fuckers who put braces in the name causing loadgame to crash. pdest = strchr(newName,'{'); if (pdest) { *pdest = 0; //zap the brace Con_Printf ("Illegal char in name removed!\n"); } if (cmd_source == src_command) { if (strcmp(cl_name.string, newName) == 0) return; Cvar_Set ("_cl_name", newName); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; } if (host_client->name[0] && strcmp(host_client->name, "unconnected") ) if (strcmp(host_client->name, newName) != 0) Con_Printf ("%s renamed to %s\n", host_client->name, newName); strcpy (host_client->name, newName); host_client->edict->v.netname = PR_SetEngineString(host_client->name); // send notification to all clients MSG_WriteByte (&sv.reliable_datagram, svc_updatename); MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); MSG_WriteString (&sv.reliable_datagram, host_client->name); }
static void RestoreClients (int ClientsMode) { int i, j; edict_t *ent; double time_diff; if (LoadGamestate(NULL, NULL, 1) != 0) return; /* O.S. -- mode 3 is only in response to the single player game "restart restore" * command issued by progs.dat::client.hc::respawn() function. No level change, * just respawning in the same map with the same playtime from when clients.gip * was saved, therefore there _CANNOT_ be a time_diff. See uhexen2 bug #2176023: * http://sourceforge.net/tracker/?group_id=124987&atid=701006&aid=2176023&func=detail */ time_diff = (ClientsMode == 3) ? 0 : sv.time - old_svtime; for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) { if (host_client->active) { ent = host_client->edict; //ent->v.colormap = NUM_FOR_EDICT(ent); ent->v.team = (host_client->colors & 15) + 1; ent->v.netname = PR_SetEngineString(host_client->name); ent->v.playerclass = host_client->playerclass; // copy spawn parms out of the client_t for (j = 0; j < NUM_SPAWN_PARMS; j++) sv_globals.parm[j] = host_client->spawn_parms[j]; // call the spawn function *sv_globals.time = sv.time; *sv_globals.self = EDICT_TO_PROG(ent); G_FLOAT(OFS_PARM0) = time_diff; PR_ExecuteProgram (*sv_globals.ClientReEnter); } } SaveGamestate (true); }
/* ====================== Host_Name_f ====================== */ void Host_Name_f (void) { char newName[32]; if (Cmd_Argc () == 1) { Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); return; } if (Cmd_Argc () == 2) q_strlcpy(newName, Cmd_Argv(1), sizeof(newName)); else q_strlcpy(newName, Cmd_Args(), sizeof(newName)); newName[15] = 0; // client_t structure actually says name[32]. if (cmd_source == src_command) { if (Q_strcmp(cl_name.string, newName) == 0) return; Cvar_Set ("_cl_name", newName); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; } if (host_client->name[0] && strcmp(host_client->name, "unconnected") ) { if (Q_strcmp(host_client->name, newName) != 0) Con_Printf ("%s renamed to %s\n", host_client->name, newName); } Q_strcpy (host_client->name, newName); host_client->edict->v.netname = PR_SetEngineString(host_client->name); // send notification to all clients MSG_WriteByte (&sv.reliable_datagram, svc_updatename); MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); MSG_WriteString (&sv.reliable_datagram, host_client->name); }
static int LoadGamestate (const char *level, const char *startspot, int ClientsMode) { FILE *f; char mapname[MAX_QPATH]; float playtime, sk; char str[32768]; const char *start; int i, r; edict_t *ent; int entnum; int version; // float spawn_parms[NUM_SPAWN_PARMS]; qboolean auto_correct = false; if (ClientsMode == 1) /* for RestoreClients() only: map must be active */ { if (!sv.active) { Con_Printf ("%s: server not active\n", __thisfunc__); return -1; } FS_MakePath_BUF (FS_USERDIR, &r, savename, sizeof(savename), "clients.gip"); if (r) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return -1; } } else { FS_MakePath_VABUF (FS_USERDIR, &r, savename, sizeof(savename), "%s.gip", level); if (r) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return -1; } if (ClientsMode != 2 && ClientsMode != 3) Con_Printf ("Loading game from %s...\n", savename); } f = fopen (savename, "r"); if (!f) { if (ClientsMode == 2) Con_Printf ("%s: ERROR: couldn't open savefile\n", __thisfunc__); return -1; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return -1; } if (ClientsMode != 1) { fscanf (f, "%s\n", str); // for (i = 0; i < NUM_SPAWN_PARMS; i++) // fscanf (f, "%f\n", &spawn_parms[i]); fscanf (f, "%f\n", &sk); Cvar_SetValue ("skill", sk); fscanf (f, "%s\n", mapname); fscanf (f, "%f\n", &playtime); SV_SpawnServer (mapname, startspot); if (!sv.active) { fclose (f); Con_Printf ("Couldn't load map\n"); return -1; } // 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"); } SV_LoadEffects (f); } // load the edicts out of the savegame file while (!feof(f)) { fscanf (f, "%i\n", &entnum); for (i = 0; i < (int) sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (i == (int) sizeof(str) - 1) { fclose (f); Host_Error ("%s: Loadgame buffer overflow", __thisfunc__); } str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) { fclose (f); Host_Error ("%s: First token isn't a brace", __thisfunc__); } // parse an edict if (entnum == -1) { ED_ParseGlobals (start); // Need to restore this *sv_globals.startspot = PR_SetEngineString(sv.startspot); } else { ent = EDICT_NUM(entnum); /* default to active edict: ED_ParseEdict() set it * to free if it really is free. cf. ED_Write() */ ent->free = false; /* ED_ParseEdict() will always memset ent->v to 0, * because SaveGamestate() doesn't write entnum 0 */ ED_ParseEdict (start, ent); if (ClientsMode == 1 || ClientsMode == 2 || ClientsMode == 3) ent->v.stats_restored = true; // link it into the bsp tree if (!ent->free) { if (entnum >= sv.num_edicts) { /* This is necessary to restore "generated" edicts which were * not available during the map parsing by ED_LoadFromFile(). * This includes items dropped by monsters, items "dropped" by * an item_spawner such as the "prizes" in the Temple of Mars * (romeric5), a health sphere generated by the Crusader's * Holy Strength ability, or a respawning-candidate killed * monster in the expansion pack's nightmare mode. -- THOMAS */ /* Moved this into the if (!ent->free) construct: less debug * chatter. Even if this skips a free edict in between, the * skipped free edict wasn't parsed by ED_LoadFromFile() and * it will remain as a freed edict. (There is no harm because * we are dealing with extra edicts not originally present in * the map.) -- O.S. */ Con_DPrintf("%s: entnum %d >= sv.num_edicts (%d)\n", __thisfunc__, entnum, sv.num_edicts); sv.num_edicts = entnum + 1; } SV_LinkEdict (ent, false); if (ent->v.modelindex && ent->v.model) { i = SV_ModelIndex(PR_GetString(ent->v.model)); if (i != ent->v.modelindex) { ent->v.modelindex = i; auto_correct = true; } } } } } fclose (f); if (ClientsMode == 0) { sv.time = playtime; sv.paused = true; *sv_globals.serverflags = svs.serverflags; RestoreClients (0); } else if (ClientsMode == 2) { sv.time = playtime; } else if (ClientsMode == 3) { sv.time = playtime; *sv_globals.serverflags = svs.serverflags; RestoreClients (3); } if (ClientsMode != 1 && auto_correct) { Con_DPrintf("*** Auto-corrected model indexes!\n"); } // for (i = 0; i < NUM_SPAWN_PARMS; i++) // svs.clients->spawn_parms[i] = spawn_parms[i]; return 0; }
/* =============== PR_LoadProgs =============== */ void PR_LoadProgs (void) { int i; // flush the non-C variable lookup cache for (i = 0; i < GEFV_CACHESIZE; i++) gefvCache[i].field[0] = 0; CRC_Init (&pr_crc); progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", NULL); if (!progs) Host_Error ("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024); for (i = 0; i < com_filesize; i++) CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]); // 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) Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != PROGHEADER_CRC) Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; if (progs->ofs_strings + progs->numstrings >= com_filesize) Host_Error ("progs.dat strings go past end of file\n"); // initialize the strings pr_numknownstrings = 0; pr_maxknownstrings = 0; pr_stringssize = progs->numstrings; if (pr_knownstrings) Z_Free ((void *)pr_knownstrings); pr_knownstrings = NULL; PR_SetEngineString(""); 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; // 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); } pr_alpha_supported = false; //johnfitz 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); //johnfitz -- detect alpha support in progs.dat if (!strcmp(pr_strings + pr_fielddefs[i].s_name,"alpha")) pr_alpha_supported = true; //johnfitz } for (i = 0; i < progs->numglobals; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t); // round off to next highest whole word address (esp for Alpha) // this ensures that pointers in the engine data area are always // properly aligned pr_edict_size += sizeof(void *) - 1; pr_edict_size &= ~(sizeof(void *) - 1); }
/* ================== SV_Spawn_f ================== */ static void SV_Spawn_f (void) { int i; client_t *client; edict_t *ent; eval_t *val; // Con_Printf("%s\n", __thisfunc__); if (host_client->state != cs_connected) { Con_Printf ("Spawn not valid -- already spawned\n"); return; } // handle the case of a level changing while a client was connecting if ( atoi(Cmd_Argv(1)) != svs.spawncount ) { Con_Printf ("%s from different level\n", __thisfunc__); SV_New_f (); return; } // set up the edict ent = host_client->edict; memset (&ent->v, 0, progs->entityfields * 4); ent->v.colormap = NUM_FOR_EDICT(ent); if (dmMode.integer == DM_SIEGE) ent->v.team = ent->v.siege_team; // FIXME else ent->v.team = 0; // FIXME ent->v.netname = PR_SetEngineString(host_client->name); //ent->v.playerclass = host_client->playerclass = ent->v.next_playerclass = host_client->next_playerclass; ent->v.has_portals = host_client->portals; host_client->entgravity = 1.0; val = GetEdictFieldValue(ent, "gravity"); if (val) val->_float = 1.0; host_client->maxspeed = sv_maxspeed.value; val = GetEdictFieldValue(ent, "maxspeed"); if (val) val->_float = sv_maxspeed.value; // send all current names, colors, and frag counts // FIXME: is this a good thing? SZ_Clear (&host_client->netchan.message); // send current status of all other players for (i = 0, client = svs.clients; i < MAX_CLIENTS; i++, client++) SV_FullClientUpdate (client, &host_client->netchan.message); // send all current light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { MSG_WriteByte (&host_client->netchan.message, svc_lightstyle); MSG_WriteByte (&host_client->netchan.message, (char)i); MSG_WriteString (&host_client->netchan.message, sv.lightstyles[i]); } // // force stats to be updated // memset (host_client->stats, 0, sizeof(host_client->stats)); MSG_WriteByte (&host_client->netchan.message, svc_updatestatlong); MSG_WriteByte (&host_client->netchan.message, STAT_TOTALSECRETS); MSG_WriteLong (&host_client->netchan.message, PR_GLOBAL_STRUCT(total_secrets)); MSG_WriteByte (&host_client->netchan.message, svc_updatestatlong); MSG_WriteByte (&host_client->netchan.message, STAT_TOTALMONSTERS); MSG_WriteLong (&host_client->netchan.message, PR_GLOBAL_STRUCT(total_monsters)); MSG_WriteByte (&host_client->netchan.message, svc_updatestatlong); MSG_WriteByte (&host_client->netchan.message, STAT_SECRETS); MSG_WriteLong (&host_client->netchan.message, PR_GLOBAL_STRUCT(found_secrets)); MSG_WriteByte (&host_client->netchan.message, svc_updatestatlong); MSG_WriteByte (&host_client->netchan.message, STAT_MONSTERS); MSG_WriteLong (&host_client->netchan.message, PR_GLOBAL_STRUCT(killed_monsters)); // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&host_client->netchan.message, svc_stufftext); MSG_WriteString (&host_client->netchan.message, va("skins\n") ); }