qboolean allowcheats = false;
extern qboolean host_shuttingdown;
+extern cvar_t developer_entityparsing;
/*
==================
void Host_Status_f (void)
{
client_t *client;
- int seconds, minutes, hours = 0, j, players;
+ int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
void (*print) (const char *fmt, ...);
-
+ char ip[22];
+
if (cmd_source == src_command)
{
// if running a client, try to send over network so the client's status report parser will see the report
if (!sv.active)
return;
+
+ in = 0;
+ if (Cmd_Argc() == 2)
+ {
+ if (strcmp(Cmd_Argv(1), "1") == 0)
+ in = 1;
+ else if (strcmp(Cmd_Argv(1), "2") == 0)
+ in = 2;
+ }
- for (players = 0, j = 0;j < svs.maxclients;j++)
- if (svs.clients[j].active)
+ for (players = 0, i = 0;i < svs.maxclients;i++)
+ if (svs.clients[i].active)
players++;
print ("host: %s\n", Cvar_VariableString ("hostname"));
print ("version: %s build %s\n", gamename, buildstring);
print ("map: %s\n", sv.name);
print ("timing: %s\n", Host_TimingReport());
print ("players: %i active (%i max)\n\n", players, svs.maxclients);
- for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
+
+ if (in == 1)
+ print ("^2IP %%pl ping time frags no name\n");
+ else if (in == 2)
+ print ("^5IP no name\n");
+
+ for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
if (!client->active)
continue;
- seconds = (int)(realtime - client->connecttime);
- minutes = seconds / 60;
- if (minutes)
+
+ ++k;
+
+ if (in == 0 || in == 1)
{
- seconds -= (minutes * 60);
- hours = minutes / 60;
- if (hours)
- minutes -= (hours * 60);
+ seconds = (int)(realtime - client->connecttime);
+ minutes = seconds / 60;
+ if (minutes)
+ {
+ seconds -= (minutes * 60);
+ hours = minutes / 60;
+ if (hours)
+ minutes -= (hours * 60);
+ }
+ else
+ hours = 0;
+
+ packetloss = 0;
+ if (client->netconnection)
+ for (j = 0;j < NETGRAPH_PACKETS;j++)
+ if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
+ packetloss++;
+ packetloss = packetloss * 100 / NETGRAPH_PACKETS;
+ ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
}
- else
- hours = 0;
- print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, client->frags, hours, minutes, seconds);
+
if(sv_status_privacy.integer && cmd_source != src_command)
- print (" %s\n", client->netconnection ? "hidden" : "botclient");
+ strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
else
- print (" %s\n", client->netconnection ? client->netconnection->address : "botclient");
+ strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
+
+ if (in == 0) // default layout
+ {
+ print ("#%-3u ", i+1);
+ print ("%-16.16s ", client->name);
+ print ("%3i ", client->frags);
+ print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
+ print ("%s\n", ip);
+ }
+ else if (in == 1) // extended layout
+ {
+ k%2 ? print("^3") : print("^7");
+ print ("%-21s ", ip);
+ print ("%2i ", packetloss);
+ print ("%4i ", ping);
+ print ("%2i:%02i:%02i ", hours, minutes, seconds);
+ print ("%4i ", client->frags);
+ print ("#%-3u ", i+1);
+ print ("^7%s\n", client->name);
+ }
+ else if (in == 2) // reduced layout
+ {
+ k%2 ? print("^3") : print("^7");
+ print ("%-21s ", ip);
+ print ("#%-3u ", i+1);
+ print ("^7%s\n", client->name);
+ }
}
}
void Host_Savegame_to (const char *name)
{
qfile_t *f;
- int i;
+ int i, lightstyles = 64;
char comment[SAVEGAME_COMMENT_LENGTH+1];
qboolean isserver;
+ // first we have to figure out if this can be saved in 64 lightstyles
+ // (for Quake compatibility)
+ for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
+ if (sv.lightstyles[i][0])
+ lightstyles = i+1;
+
isserver = !strcmp(PRVM_NAME, "server");
Con_Printf("Saving game to %s...\n", name);
// convert space to _ to make stdio happy
// LordHavoc: convert control characters to _ as well
for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
- if (comment[i] <= ' ')
+ if (ISWHITESPACEORCONTROL(comment[i]))
comment[i] = '_';
comment[SAVEGAME_COMMENT_LENGTH] = '\0';
}
// write the light styles
- for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
+ for (i=0 ; i<lightstyles ; i++)
{
if (isserver && sv.lightstyles[i][0])
FS_Printf(f, "%s\n", sv.lightstyles[i]);
PRVM_ED_WriteGlobals (f);
for (i=0 ; i<prog->num_edicts ; i++)
{
+ FS_Printf(f,"// edict %d\n", i);
//Con_Printf("edict %d...\n", i);
PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
}
+#if 1
+ FS_Printf(f,"/*\n");
+ FS_Printf(f,"// DarkPlaces extended savegame\n");
+ // darkplaces extension - extra lightstyles, support for color lightstyles
+ for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
+ if (isserver && sv.lightstyles[i][0])
+ FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
+
+ // darkplaces extension - model precaches
+ for (i=1 ; i<MAX_MODELS ; i++)
+ if (sv.model_precache[i][0])
+ FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
+
+ // darkplaces extension - sound precaches
+ for (i=1 ; i<MAX_SOUNDS ; i++)
+ if (sv.sound_precache[i][0])
+ FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
+ FS_Printf(f,"*/\n");
+#endif
+
FS_Close (f);
Con_Print("done.\n");
}
char mapname[MAX_QPATH];
float time;
const char *start;
+ const char *end;
const char *t;
- const char *oldt;
char *text;
prvm_edict_t *ent;
int i;
return;
}
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading version\n");
+
// version
COM_ParseToken_Simple(&t, false, false);
version = atoi(com_token);
return;
}
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading description\n");
+
// description
COM_ParseToken_Simple(&t, false, false);
current_skill = (int)(atof(com_token) + 0.5);
Cvar_SetValue ("skill", (float)current_skill);
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading mapname\n");
+
// mapname
COM_ParseToken_Simple(&t, false, false);
strlcpy (mapname, com_token, sizeof(mapname));
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading time\n");
+
// time
COM_ParseToken_Simple(&t, false, false);
time = atof(com_token);
allowcheats = sv_cheats.integer != 0;
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: spawning server\n");
+
SV_SpawnServer (mapname);
if (!sv.active)
{
sv.paused = true; // pause until all clients connect
sv.loadgame = true;
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading light styles\n");
+
// load the light styles
+ SV_VM_Begin();
+ // -1 is the globals
+ entnum = -1;
+
for (i = 0;i < MAX_LIGHTSTYLES;i++)
{
// light style
- oldt = t;
+ start = t;
COM_ParseToken_Simple(&t, false, false);
// if this is a 64 lightstyle savegame produced by Quake, stop now
- // we have to check this because darkplaces saves 256 lightstyle savegames
+ // we have to check this because darkplaces may save more than 64
if (com_token[0] == '{')
{
- t = oldt;
+ t = start;
break;
}
strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
}
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: skipping until globals\n");
+
// now skip everything before the first opening brace
// (this is for forward compatibility, so that older versions (at
// least ones with this fix) can load savegames with extra data before the
// first brace, as might be produced by a later engine version)
- for(;;)
+ for (;;)
{
- oldt = t;
- COM_ParseToken_Simple(&t, false, false);
+ start = t;
+ if (!COM_ParseToken_Simple(&t, false, false))
+ break;
if (com_token[0] == '{')
{
- t = oldt;
+ t = start;
break;
}
}
// load the edicts out of the savegame file
- SV_VM_Begin();
- // -1 is the globals
- entnum = -1;
+ end = t;
for (;;)
{
start = t;
if (entnum == -1)
{
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading globals\n");
+
// parse the global vars
PRVM_ED_ParseGlobals (start);
}
ent = PRVM_EDICT_NUM(entnum);
memset (ent->fields.server, 0, prog->progs->entityfields * 4);
ent->priv.server->free = false;
+
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
+
PRVM_ED_ParseEdict (start, ent);
// link it into the bsp tree
SV_LinkEdict (ent, false);
}
+ end = t;
entnum++;
}
- Mem_Free(text);
prog->num_edicts = entnum;
sv.time = time;
for (i = 0;i < NUM_SPAWN_PARMS;i++)
svs.clients[0].spawn_parms[i] = spawn_parms[i];
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: skipping until extended data\n");
+
+ // read extended data if present
+ // the extended data is stored inside a /* */ comment block, which the
+ // parser intentionally skips, so we have to check for it manually here
+ if(end)
+ {
+ while (*end == '\r' || *end == '\n')
+ end++;
+ if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
+ {
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: loading extended data\n");
+
+ Con_Printf("Loading extended DarkPlaces savegame\n");
+ t = end + 2;
+ memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
+ memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
+ memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
+ while (COM_ParseToken_Simple(&t, false, false))
+ {
+ if (!strcmp(com_token, "sv.lightstyles"))
+ {
+ COM_ParseToken_Simple(&t, false, false);
+ i = atoi(com_token);
+ COM_ParseToken_Simple(&t, false, false);
+ if (i >= 0 && i < MAX_LIGHTSTYLES)
+ strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
+ else
+ Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
+ }
+ else if (!strcmp(com_token, "sv.model_precache"))
+ {
+ COM_ParseToken_Simple(&t, false, false);
+ i = atoi(com_token);
+ COM_ParseToken_Simple(&t, false, false);
+ if (i >= 0 && i < MAX_MODELS)
+ {
+ strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
+ sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
+ }
+ else
+ Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
+ }
+ else if (!strcmp(com_token, "sv.sound_precache"))
+ {
+ COM_ParseToken_Simple(&t, false, false);
+ i = atoi(com_token);
+ COM_ParseToken_Simple(&t, false, false);
+ if (i >= 0 && i < MAX_SOUNDS)
+ strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
+ else
+ Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
+ }
+ // skip any trailing text or unrecognized commands
+ while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
+ ;
+ }
+ }
+ }
+ Mem_Free(text);
+
+ if(developer_entityparsing.integer)
+ Con_Printf("Host_Loadgame_f: finished\n");
+
SV_VM_End();
// make sure we're connected to loopback
if (strcmp(host_client->old_name, host_client->name))
{
if (host_client->spawned)
- SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
+ SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
// send notification to all clients
MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
if(svs.clients[i].active && svs.clients[i].netconnection)
{
host_client = &svs.clients[i];
- Host_ClientCommands(va("sendcvar %s\n", cvarname));
+ Host_ClientCommands("sendcvar %s\n", cvarname);
}
host_client = old;
}
for (i = 0;rcon_password.string[i];i++)
{
- if (rcon_password.string[i] <= ' ')
+ if (ISWHITESPACE(rcon_password.string[i]))
{
Con_Printf("rcon_password is not allowed to have any whitespace.\n");
return;