X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=host_cmd.c;h=b5a4047b2bbc17e69a295a97dfc0de4ea636f09a;hp=cdf3315a192565d09141fe181c7f17dbe05bbb15;hb=4923f258e0c7d504f77770c7571ebeadd5537660;hpb=9c6e251d8acae148c5f0554f3492f3795d7aee12 diff --git a/host_cmd.c b/host_cmd.c index cdf3315a..b5a4047b 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -19,17 +19,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "sv_demo.h" +#include "image.h" int current_skill; cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"}; cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"}; +cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"}; cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands"}; cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"}; cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"}; cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"}; cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"}; +cvar_t r_fixtrans_auto = {0, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"}; qboolean allowcheats = false; +extern qboolean host_shuttingdown; +extern cvar_t developer_entityparsing; + /* ================== Host_Quit_f @@ -38,10 +45,12 @@ Host_Quit_f void Host_Quit_f (void) { - Sys_Quit (0); + if(host_shuttingdown) + Con_Printf("shutting down already!\n"); + else + Sys_Quit (0); } - /* ================== Host_Status_f @@ -50,9 +59,10 @@ Host_Status_f 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 @@ -68,32 +78,92 @@ void Host_Status_f (void) 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 ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol)); 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); } + + if(sv_status_privacy.integer && cmd_source != src_command) + strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22); else - hours = 0; - print ("#%-3u %-16.16s^%i %3i %2i:%02i:%02i\n", j+1, client->name, STRING_COLOR_DEFAULT, client->frags, hours, minutes, seconds); - 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); + } } } @@ -225,7 +295,8 @@ void Host_Ping_f (void) } // now call the Pings command also, which will send a report that contains packet loss for the scoreboard (as well as a simpler ping report) - Host_Pings_f(); + // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console) + //Host_Pings_f(); } /* @@ -255,6 +326,10 @@ void Host_Map_f (void) return; } + // GAME_DELUXEQUAKE - clear warpmark (used by QC) + if (gamemode == GAME_DELUXEQUAKE) + Cvar_Set("warpmark", ""); + cls.demonum = -1; // stop demo loop in case this fails CL_Disconnect (); @@ -422,32 +497,101 @@ LOAD / SAVE GAME #define SAVEGAME_VERSION 5 -/* -=============== -Host_SavegameComment - -Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current -=============== -*/ -void Host_SavegameComment (char *text) +void Host_Savegame_to (const char *name) { - int i; - char kills[20]; + qfile_t *f; + int i, lightstyles = 64; + char comment[SAVEGAME_COMMENT_LENGTH+1]; + qboolean isserver; - for (i=0 ; iedicts->fields.server->message), (int)prog->globals.server->killed_monsters, (int)prog->globals.server->total_monsters); + else + dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME); // convert space to _ to make stdio happy // LordHavoc: convert control characters to _ as well for (i=0 ; inum_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 ; ifields.server->deadflag) { - if (i > 0) - { - Con_Print("Can't save multiplayer games.\n"); - return; - } - if (svs.clients[i].edict->fields.server->deadflag) - { - Con_Print("Can't savegame with a dead player\n"); - return; - } + Con_Print("Can't savegame with a dead player\n"); + return; } } + else + Con_Print("Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n"); if (Cmd_Argc() != 2) { @@ -505,42 +641,9 @@ void Host_Savegame_f (void) strlcpy (name, Cmd_Argv(1), sizeof (name)); FS_DefaultExtension (name, ".sav", sizeof (name)); - Con_Printf("Saving game to %s...\n", name); - f = FS_Open (name, "wb", false, false); - if (!f) - { - Con_Print("ERROR: couldn't open.\n"); - return; - } - - FS_Printf(f, "%i\n", SAVEGAME_VERSION); - Host_SavegameComment (comment); - FS_Printf(f, "%s\n", comment); - for (i=0 ; inum_edicts ; i++) - PRVM_ED_Write (f, PRVM_EDICT_NUM(i)); - + Host_Savegame_to(name); SV_VM_End(); - - FS_Close (f); - Con_Print("done.\n"); } @@ -555,8 +658,8 @@ void Host_Loadgame_f (void) 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; @@ -575,6 +678,13 @@ void Host_Loadgame_f (void) Con_Printf("Loading game from %s...\n", filename); + // stop playing demos + if (cls.demoplayback) + CL_Disconnect (); + + // remove menu + key_dest = key_game; + cls.demonum = -1; // stop demo loop in case this fails t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL); @@ -584,8 +694,11 @@ void Host_Loadgame_f (void) return; } + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading version\n"); + // version - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false, false); version = atoi(com_token); if (version != SAVEGAME_VERSION) { @@ -594,32 +707,42 @@ void Host_Loadgame_f (void) return; } + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading description\n"); + // description - // this is a little hard to parse, as : is a separator in COM_ParseToken, - // so use the console parser instead - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false, false); for (i = 0;i < NUM_SPAWN_PARMS;i++) { - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false, false); spawn_parms[i] = atof(com_token); } // skill - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false, false); // this silliness is so we can load 1.06 save files, which have float skill values 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_ParseTokenConsole(&t); + 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_ParseTokenConsole(&t); + 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) { @@ -630,49 +753,58 @@ void Host_Loadgame_f (void) 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; - COM_ParseTokenConsole(&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_ParseTokenConsole(&t); + 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; - while (COM_ParseTokenConsole(&t)) + while (COM_ParseToken_Simple(&t, false, false)) if (!strcmp(com_token, "}")) break; - if (!COM_ParseTokenConsole(&start)) + if (!COM_ParseToken_Simple(&start, false, false)) { // end of file break; @@ -685,6 +817,9 @@ void Host_Loadgame_f (void) if (entnum == -1) { + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading globals\n"); + // parse the global vars PRVM_ED_ParseGlobals (start); } @@ -697,11 +832,14 @@ void Host_Loadgame_f (void) Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS); } while (entnum >= prog->max_edicts) - //SV_IncreaseEdicts(); PRVM_MEM_IncreaseEdicts(); 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 @@ -709,9 +847,9 @@ void Host_Loadgame_f (void) SV_LinkEdict (ent, false); } + end = t; entnum++; } - Mem_Free(text); prog->num_edicts = entnum; sv.time = time; @@ -719,10 +857,76 @@ void Host_Loadgame_f (void) 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 (cls.state == ca_disconnected || !(cls.state == ca_connected && cls.netcon != NULL && LHNETADDRESS_GetAddressType(&cls.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP)) + if (sv.active && cls.state == ca_disconnected) CL_EstablishConnection("local:1"); } @@ -737,6 +941,7 @@ cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "intern void Host_Name_f (void) { int i, j; + qboolean valid_colors; char newName[sizeof(host_client->name)]; if (Cmd_Argc () == 1) @@ -750,11 +955,6 @@ void Host_Name_f (void) else strlcpy (newName, Cmd_Args(), sizeof (newName)); - for (i = 0, j = 0;newName[i];i++) - if (newName[i] != '\r' && newName[i] != '\n') - newName[j++] = newName[i]; - newName[j] = 0; - if (cmd_source == src_command) { Cvar_Set ("_cl_name", newName); @@ -771,6 +971,66 @@ void Host_Name_f (void) // point the string back at updateclient->name to keep it safe strlcpy (host_client->name, newName, sizeof (host_client->name)); + + for (i = 0, j = 0;host_client->name[i];i++) + if (host_client->name[i] != '\r' && host_client->name[i] != '\n') + host_client->name[j++] = host_client->name[i]; + host_client->name[j] = 0; + + if(host_client->name[0] == 1 || host_client->name[0] == 2) + // may interfere with chat area, and will needlessly beep; so let's add a ^7 + { + memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2); + host_client->name[sizeof(host_client->name) - 1] = 0; + host_client->name[0] = STRING_COLOR_TAG; + host_client->name[1] = '0' + STRING_COLOR_DEFAULT; + } + + COM_StringLengthNoColors(host_client->name, 0, &valid_colors); + if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string + { + size_t l; + l = strlen(host_client->name); + if(l < sizeof(host_client->name) - 1) + { + // duplicate the color tag to escape it + host_client->name[i] = STRING_COLOR_TAG; + host_client->name[i+1] = 0; + //Con_DPrintf("abuse detected, adding another trailing color tag\n"); + } + else + { + // remove the last character to fix the color code + host_client->name[l-1] = 0; + //Con_DPrintf("abuse detected, removing a trailing color tag\n"); + } + } + + // find the last color tag offset and decide if we need to add a reset tag + for (i = 0, j = -1;host_client->name[i];i++) + { + if (host_client->name[i] == STRING_COLOR_TAG) + { + if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9') + { + j = i; + // if this happens to be a reset tag then we don't need one + if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT) + j = -1; + i++; + continue; + } + if (host_client->name[i+1] == STRING_COLOR_TAG) + { + i++; + continue; + } + } + } + // does not end in the default color string, so add it + if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2) + memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1); + host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name); if (strcmp(host_client->old_name, host_client->name)) { @@ -781,6 +1041,7 @@ void Host_Name_f (void) MSG_WriteByte (&sv.reliable_datagram, svc_updatename); MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); MSG_WriteString (&sv.reliable_datagram, host_client->name); + SV_WriteNetnameIntoDemo(host_client); } } @@ -945,13 +1206,13 @@ void Host_Say(qboolean teamonly) } // note this uses the chat prefix \001 if (!fromServer && !teamonly) - dpsnprintf (text, sizeof(text), "\001%s" STRING_COLOR_DEFAULT_STR ": %s", host_client->name, p1); + dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1); else if (!fromServer && teamonly) - dpsnprintf (text, sizeof(text), "\001(%s" STRING_COLOR_DEFAULT_STR "): %s", host_client->name, p1); + dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1); else if(*(sv_adminnick.string)) - dpsnprintf (text, sizeof(text), "\001<%s" STRING_COLOR_DEFAULT_STR "> %s", sv_adminnick.string, p1); + dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1); else - dpsnprintf (text, sizeof(text), "\001<%s" STRING_COLOR_DEFAULT_STR "> %s", hostname.string, p1); + dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1); p2 = text + strlen(text); while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted))) { @@ -1013,11 +1274,11 @@ void Host_Tell_f(void) // note this uses the chat prefix \001 if (!fromServer) - sprintf (text, "\001%s tells you: ", host_client->name); + dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name); else if(*(sv_adminnick.string)) - sprintf (text, "\001<%s tells you> ", sv_adminnick.string); + dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string); else - sprintf (text, "\001<%s tells you> ", hostname.string); + dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string); p1 = Cmd_Args(); p2 = p1 + strlen(p1); @@ -1223,7 +1484,7 @@ void Host_BottomColor_f(void) Host_Color(-1, atoi(Cmd_Argv(1))); } -cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "10000", "internal storage cvar for current rate (changed by rate command)"}; +cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"}; void Host_Rate_f(void) { int rate; @@ -1339,6 +1600,7 @@ void Host_PreSpawn_f (void) SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize); MSG_WriteByte (&host_client->netconnection->message, svc_signonnum); MSG_WriteByte (&host_client->netconnection->message, 2); + host_client->sendsignon = 0; // enable unlimited sends again } // reset the name change timer because the client will send name soon @@ -1375,9 +1637,6 @@ void Host_Spawn_f (void) if (sv.loadgame) { // loaded games are fully initialized already - // if this is the last client to be connected, unpause - sv.paused = false; - if (prog->funcoffsets.RestoreGame) { Con_DPrint("Calling RestoreGame\n"); @@ -1400,8 +1659,8 @@ void Host_Spawn_f (void) prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing"); - if (svs.maxclients > 1 || cls.state == ca_dedicated) - Con_Printf("%s^%i entered the game\n", host_client->name, STRING_COLOR_DEFAULT); + if (cls.state == ca_dedicated) + Con_Printf("%s connected\n", host_client->name); PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing"); } @@ -1468,7 +1727,6 @@ void Host_Spawn_f (void) MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol); MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol); MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol); - sv.loadgame = false; // we're basically done with loading now } else { @@ -1492,6 +1750,20 @@ Host_Begin_f void Host_Begin_f (void) { host_client->spawned = true; + + // LordHavoc: note: this code also exists in SV_DropClient + if (sv.loadgame) + { + int i; + for (i = 0;i < svs.maxclients;i++) + if (svs.clients[i].active && !svs.clients[i].spawned) + break; + if (i == svs.maxclients) + { + Con_Printf("Loaded game, everyone rejoined - unpausing\n"); + sv.paused = sv.loadgame = false; // we're basically done with loading now + } + } } //=========================================================================== @@ -1555,7 +1827,7 @@ void Host_Kick_f (void) if (Cmd_Argc() > 2) { message = Cmd_Args(); - COM_ParseTokenConsole(&message); + COM_ParseToken_Simple(&message, false, false); if (byNumber) { message++; // skip the # @@ -1759,7 +2031,7 @@ Host_Viewmodel_f void Host_Viewmodel_f (void) { prvm_edict_t *e; - model_t *m; + dp_model_t *m; if (!sv.active) return; @@ -1790,7 +2062,7 @@ void Host_Viewframe_f (void) { prvm_edict_t *e; int f; - model_t *m; + dp_model_t *m; if (!sv.active) return; @@ -1810,7 +2082,7 @@ void Host_Viewframe_f (void) } -void PrintFrameName (model_t *m, int frame) +void PrintFrameName (dp_model_t *m, int frame) { if (m->animscenes) Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name); @@ -1826,7 +2098,7 @@ Host_Viewnext_f void Host_Viewnext_f (void) { prvm_edict_t *e; - model_t *m; + dp_model_t *m; if (!sv.active) return; @@ -1853,7 +2125,7 @@ Host_Viewprev_f void Host_Viewprev_f (void) { prvm_edict_t *e; - model_t *m; + dp_model_t *m; if (!sv.active) return; @@ -1891,7 +2163,7 @@ void Host_Startdemos_f (void) { int i, c; - if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo")) + if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo")) return; c = Cmd_Argc() - 1; @@ -1900,7 +2172,7 @@ void Host_Startdemos_f (void) Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS); c = MAX_DEMOS; } - Con_Printf("%i demo(s) in loop\n", c); + Con_DPrintf("%i demo(s) in loop\n", c); for (i=1 ; iflags & CVAR_PRIVATE)) - Cmd_ForwardStringToServer(va("sentcvar %s\n", cvarname)); + Cmd_ForwardStringToServer(va("sentcvar %s", cvarname)); else - Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"\n", c->name, c->string)); + Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string)); return; } if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand) @@ -1984,7 +2256,7 @@ void Host_SendCvar_f (void) 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; } @@ -2296,6 +2568,8 @@ void Host_Packet_f (void) // credit: taken from QuakeWorld } mysocket = NetConn_ChooseClientSocketForAddress(&address); + if (!mysocket) + mysocket = NetConn_ChooseServerSocketForAddress(&address); if (mysocket) NetConn_Write(mysocket, send, out - send, &address); } @@ -2371,7 +2645,7 @@ Host_InitCommands */ void Host_InitCommands (void) { - dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\%s", engineversion); + dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp"); Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information"); Cmd_AddCommand ("quit", Host_Quit_f, "quit the game"); @@ -2456,11 +2730,18 @@ void Host_InitCommands (void) Cmd_AddCommand_WithClientCommand ("pings", NULL, Host_Pings_f, "command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)"); Cmd_AddCommand ("pingplreport", Host_PingPLReport_f, "command sent by server containing client ping and packet loss values for scoreboard, triggered by pings command from client (not used by QW servers)"); + Cmd_AddCommand ("fixtrans", Image_FixTransparentPixels_f, "change alpha-zero pixels in an image file to sensible values, and write out a new TGA (warning: SLOW)"); + Cvar_RegisterVariable (&r_fixtrans_auto); + Cvar_RegisterVariable (&team); Cvar_RegisterVariable (&skin); Cvar_RegisterVariable (&noaim); Cvar_RegisterVariable(&sv_cheats); Cvar_RegisterVariable(&sv_adminnick); + Cvar_RegisterVariable(&sv_status_privacy); } +void Host_NoOperation_f(void) +{ +}