]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - host_cmd.c
reworked sendsignon logic so that unlimited sends are allowed once
[xonotic/darkplaces.git] / host_cmd.c
index 57859b5cf37abc2590cf2b28d44225852d0719a5..b69389c1d91ae43fd3145b51ba49274daf8eab13 100644 (file)
@@ -30,6 +30,8 @@ cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (exam
 cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
 qboolean allowcheats = false;
 
+extern qboolean host_shuttingdown;
+
 /*
 ==================
 Host_Quit_f
@@ -38,7 +40,10 @@ Host_Quit_f
 
 void Host_Quit_f (void)
 {
-       Sys_Quit ();
+       if(host_shuttingdown)
+               Con_Printf("shutting down already!\n");
+       else
+               Sys_Quit (0);
 }
 
 
@@ -225,7 +230,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();
 }
 
 /*
@@ -269,29 +275,6 @@ void Host_Map_f (void)
        SV_SpawnServer(level);
        if (sv.active && cls.state == ca_disconnected)
                CL_EstablishConnection("local:1");
-
-#ifdef AUTODEMO_BROKEN
-// if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already
-       if (cl_autodemo.integer && !cls.demorecording)
-       {
-               char demofile[MAX_OSPATH];
-
-               dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), level);
-
-               Con_Printf ("Recording to %s.\n", demofile);
-
-               cls.demofile = FS_Open (demofile, "wb", false, false);
-               if (cls.demofile)
-               {
-                       cls.forcetrack = -1;
-                       FS_Printf (cls.demofile, "%i\n", cls.forcetrack);
-               }
-               else
-                       Con_Print ("ERROR: couldn't open.\n");
-
-               cls.demorecording = true;
-       }
-#endif
 }
 
 /*
@@ -608,7 +591,7 @@ void Host_Loadgame_f (void)
        }
 
        // version
-       COM_ParseTokenConsole(&t);
+       COM_ParseToken_Simple(&t, false);
        version = atoi(com_token);
        if (version != SAVEGAME_VERSION)
        {
@@ -618,27 +601,25 @@ void Host_Loadgame_f (void)
        }
 
        // 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);
 
        for (i = 0;i < NUM_SPAWN_PARMS;i++)
        {
-               COM_ParseTokenConsole(&t);
+               COM_ParseToken_Simple(&t, false);
                spawn_parms[i] = atof(com_token);
        }
        // skill
-       COM_ParseTokenConsole(&t);
+       COM_ParseToken_Simple(&t, 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);
 
        // mapname
-       COM_ParseTokenConsole(&t);
+       COM_ParseToken_Simple(&t, false);
        strlcpy (mapname, com_token, sizeof(mapname));
 
        // time
-       COM_ParseTokenConsole(&t);
+       COM_ParseToken_Simple(&t, false);
        time = atof(com_token);
 
        allowcheats = sv_cheats.integer != 0;
@@ -659,7 +640,7 @@ void Host_Loadgame_f (void)
        {
                // light style
                oldt = t;
-               COM_ParseTokenConsole(&t);
+               COM_ParseToken_Simple(&t, false);
                // if this is a 64 lightstyle savegame produced by Quake, stop now
                // we have to check this because darkplaces saves 256 lightstyle savegames
                if (com_token[0] == '{')
@@ -677,7 +658,7 @@ void Host_Loadgame_f (void)
        for(;;)
        {
                oldt = t;
-               COM_ParseTokenConsole(&t);
+               COM_ParseToken_Simple(&t, false);
                if (com_token[0] == '{')
                {
                        t = oldt;
@@ -692,10 +673,10 @@ void Host_Loadgame_f (void)
        for (;;)
        {
                start = t;
-               while (COM_ParseTokenConsole(&t))
+               while (COM_ParseToken_Simple(&t, false))
                        if (!strcmp(com_token, "}"))
                                break;
-               if (!COM_ParseTokenConsole(&start))
+               if (!COM_ParseToken_Simple(&start, false))
                {
                        // end of file
                        break;
@@ -720,7 +701,6 @@ 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);
@@ -756,10 +736,11 @@ void Host_Loadgame_f (void)
 Host_Name_f
 ======================
 */
-cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
+cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
 void Host_Name_f (void)
 {
        int i, j;
+       qboolean valid_colors;
        char newName[sizeof(host_client->name)];
 
        if (Cmd_Argc () == 1)
@@ -781,20 +762,65 @@ void Host_Name_f (void)
        if (cmd_source == src_command)
        {
                Cvar_Set ("_cl_name", newName);
-               CL_SetInfo("name", newName, true, false, false, false);
                return;
        }
 
-       if (sv.time < host_client->nametime)
+       if (realtime < host_client->nametime)
        {
                SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
                return;
        }
 
-       host_client->nametime = sv.time + 5;
+       host_client->nametime = realtime + 5;
 
        // point the string back at updateclient->name to keep it safe
        strlcpy (host_client->name, newName, sizeof (host_client->name));
+
+       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))
        {
@@ -813,7 +839,7 @@ void Host_Name_f (void)
 Host_Playermodel_f
 ======================
 */
-cvar_t cl_playermodel = {CVAR_SAVE, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
+cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
 void Host_Playermodel_f (void)
 {
@@ -839,18 +865,17 @@ void Host_Playermodel_f (void)
        if (cmd_source == src_command)
        {
                Cvar_Set ("_cl_playermodel", newPath);
-               CL_SetInfo("playermodel", newPath, true, false, false, false);
                return;
        }
 
        /*
-       if (sv.time < host_client->nametime)
+       if (realtime < host_client->nametime)
        {
                SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
                return;
        }
 
-       host_client->nametime = sv.time + 5;
+       host_client->nametime = realtime + 5;
        */
 
        // point the string back at updateclient->name to keep it safe
@@ -872,7 +897,7 @@ void Host_Playermodel_f (void)
 Host_Playerskin_f
 ======================
 */
-cvar_t cl_playerskin = {CVAR_SAVE, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
+cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
 void Host_Playerskin_f (void)
 {
        int i, j;
@@ -897,18 +922,17 @@ void Host_Playerskin_f (void)
        if (cmd_source == src_command)
        {
                Cvar_Set ("_cl_playerskin", newPath);
-               CL_SetInfo("playerskin", newPath, true, false, false, false);
                return;
        }
 
        /*
-       if (sv.time < host_client->nametime)
+       if (realtime < host_client->nametime)
        {
                SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
                return;
        }
 
-       host_client->nametime = sv.time + 5;
+       host_client->nametime = realtime + 5;
        */
 
        // point the string back at updateclient->name to keep it safe
@@ -970,12 +994,14 @@ void Host_Say(qboolean teamonly)
                p1++;
        }
        // note this uses the chat prefix \001
-       if (!fromServer)
-               dpsnprintf (text, sizeof(text), "\001%s" STRING_COLOR_DEFAULT_STR ": %s", host_client->name, p1);
+       if (!fromServer && !teamonly)
+               dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
+       else if (!fromServer && teamonly)
+               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)))
        {
@@ -1144,7 +1170,7 @@ void Host_Tell_f(void)
 Host_Color_f
 ==================
 */
-cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
+cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
 void Host_Color(int changetop, int changebottom)
 {
        int top, bottom, playercolor;
@@ -1167,15 +1193,6 @@ void Host_Color(int changetop, int changebottom)
        if (cmd_source == src_command)
        {
                Cvar_SetValueQuick(&cl_color, playercolor);
-               if (changetop >= 0)
-                       CL_SetInfo("topcolor", va("%i", top), true, false, false, false);
-               if (changebottom >= 0)
-                       CL_SetInfo("bottomcolor", va("%i", bottom), true, false, false, false);
-               if (cls.protocol != PROTOCOL_QUAKEWORLD && cls.netcon)
-               {
-                       MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
-                       MSG_WriteString(&cls.netcon->message, va("color %i %i", top, bottom));
-               }
                return;
        }
 
@@ -1256,7 +1273,7 @@ void Host_BottomColor_f(void)
        Host_Color(-1, atoi(Cmd_Argv(1)));
 }
 
-cvar_t cl_rate = {CVAR_SAVE, "_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;
@@ -1273,7 +1290,6 @@ void Host_Rate_f(void)
        if (cmd_source == src_command)
        {
                Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
-               CL_SetInfo("rate", va("%i", rate), true, false, false, false);
                return;
        }
 
@@ -1325,7 +1341,7 @@ LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mind
 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
 ======================
 */
-cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
+cvar_t cl_pmodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
 static void Host_PModel_f (void)
 {
        int i;
@@ -1373,6 +1389,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
@@ -1434,7 +1451,7 @@ 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 ((Sys_DoubleTime() - host_client->connecttime) <= sv.time)
+               if (svs.maxclients > 1 || cls.state == ca_dedicated)
                        Con_Printf("%s entered the game\n", host_client->name);
 
                PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
@@ -1589,7 +1606,7 @@ void Host_Kick_f (void)
                if (Cmd_Argc() > 2)
                {
                        message = Cmd_Args();
-                       COM_ParseTokenConsole(&message);
+                       COM_ParseToken_Simple(&message, false);
                        if (byNumber)
                        {
                                message++;                                                      // skip the #
@@ -1925,7 +1942,7 @@ void Host_Startdemos_f (void)
 {
        int             i, c;
 
-       if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-demolooponly"))
+       if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
                return;
 
        c = Cmd_Argc() - 1;
@@ -1989,14 +2006,23 @@ void Host_SendCvar_f (void)
 {
        int             i;
        cvar_t  *c;
+       const char *cvarname;
        client_t *old;
 
        if(Cmd_Argc() != 2)
                return;
-       if(!(c = Cvar_FindVar(Cmd_Argv(1))) || (c->flags & CVAR_PRIVATE))
+       cvarname = Cmd_Argv(1);
+       if (cls.state == ca_connected)
+       {
+               c = Cvar_FindVar(cvarname);
+               // LordHavoc: if there is no such cvar or if it is private, send a
+               // reply indicating that it has no value
+               if(!c || (c->flags & CVAR_PRIVATE))
+                       Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
+               else
+                       Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
                return;
-       if (cls.state != ca_dedicated)
-               Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"\n", c->name, c->string));
+       }
        if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
                return;
 
@@ -2009,7 +2035,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", c->name));
+                       Host_ClientCommands(va("sendcvar %s\n", cvarname));
                }
        host_client = old;
 }
@@ -2349,8 +2375,10 @@ void Host_Pings_f (void)
        {
                packetloss = 0;
                if (svs.clients[i].netconnection)
-                       for (j = 0;j < 100;j++)
-                               packetloss += svs.clients[i].netconnection->packetlost[j];
+                       for (j = 0;j < NETGRAPH_PACKETS;j++)
+                               if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
+                                       packetloss++;
+               packetloss = packetloss * 100 / NETGRAPH_PACKETS;
                ping = (int)floor(svs.clients[i].ping*1000+0.5);
                ping = bound(0, ping, 9999);
                if (sv.protocol == PROTOCOL_QUAKEWORLD)
@@ -2394,7 +2422,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");
@@ -2462,7 +2490,7 @@ void Host_InitCommands (void)
        Cmd_AddCommand_WithClientCommand ("begin", NULL, Host_Begin_f, "signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)");
        Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
 
-       Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");       // By [515]
+       Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
 
        Cvar_RegisterVariable (&rcon_password);
        Cvar_RegisterVariable (&rcon_address);