]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
326
[xonotic/darkplaces.git] / sv_main.c
index dc717643f737377f610c82df3e893ba1a7416fd1..a1dab0066d348063dc6c7d59b7bf0f383dc655a3 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -32,6 +32,8 @@ static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0"}; // tend
 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"};
 static cvar_t sv_entpatch = {0, "sv_entpatch", "1"};
 
+extern cvar_t sys_ticrate;
+
 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1"};
 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1"};
 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "1"};
@@ -279,8 +281,29 @@ void SV_SendServerinfo (client_t *client)
        char                    message[128];
 
        // edicts get reallocated on level changes, so we need to update it here
-       client->edict = EDICT_NUM(client->number + 1);
+       client->edict = EDICT_NUM((client - svs.clients) + 1);
+
+       // if client is a botclient coming from a level change, we need to set up
+       // client info that normally requires networking
+       if (!client->netconnection)
+       {
+               int i;
+
+               // set up the edict
+               ED_ClearEdict(client->edict);
+
+               // copy spawn parms out of the client_t
+               for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
+                       (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
 
+               // call the spawn function
+               pr_global_struct->time = sv.time;
+               pr_global_struct->self = EDICT_TO_PROG(client->edict);
+               PR_ExecuteProgram (pr_global_struct->ClientConnect, "QC function ClientConnect is missing");
+               PR_ExecuteProgram (pr_global_struct->PutClientInServer, "QC function PutClientInServer is missing");
+               host_client->spawned = true;
+               return;
+       }
 
        // LordHavoc: clear entityframe tracking
 
@@ -360,16 +383,21 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
        client->active = true;
        client->netconnection = netconnection;
 
-       Con_DPrintf("Client %s connected\n", client->netconnection->address);
+       Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
 
        strcpy(client->name, "unconnected");
        strcpy(client->old_name, "unconnected");
-       client->number = clientnum;
        client->spawned = false;
        client->edict = EDICT_NUM(clientnum+1);
        client->message.data = client->msgbuf;
        client->message.maxsize = sizeof(client->msgbuf);
        client->message.allowoverflow = true;           // we can catch it
+       // updated by receiving "rate" command from client
+       client->rate = NET_MINRATE;
+       // no limits for local player
+       if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
+               client->rate = 1000000000;
+       client->connecttime = realtime;
 
        if (sv.loadgame)
                memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
@@ -381,7 +409,12 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
                        client->spawn_parms[i] = (&pr_global_struct->parm1)[i];
        }
 
-       SV_SendServerinfo (client);
+       // don't call SendServerinfo for a fresh botclient because its fields have
+       // not been set up by the qc yet
+       if (client->netconnection)
+               SV_SendServerinfo (client);
+       else
+               client->spawned = true;
 }
 
 
@@ -1060,8 +1093,8 @@ qboolean SV_SendClientDatagram (client_t *client)
                if (sv_maxrate.integer != maxrate)
                        Cvar_SetValueQuick(&sv_maxrate, maxrate);
 
-               rate = bound(NET_MINRATE, client->netconnection->rate, maxrate);
-               rate = (int)(client->netconnection->rate * sys_ticrate.value);
+               rate = bound(NET_MINRATE, client->rate, maxrate);
+               rate = (int)(client->rate * sys_ticrate.value);
                maxsize = bound(100, rate, 1400);
                maxsize2 = 1400;
        }
@@ -1115,65 +1148,54 @@ void SV_UpdateToReliableMessages (void)
        int i, j;
        client_t *client;
        eval_t *val;
-       char *s;
+       char *name;
 
 // check for changes to be sent over the reliable streams
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
        {
                // update the host_client fields we care about according to the entity fields
-               sv_player = EDICT_NUM(i+1);
-               s = PR_GetString(sv_player->v->netname);
-               if (s != host_client->name)
-               {
-                       if (s == NULL)
-                               s = "";
-                       // point the string back at host_client->name to keep it safe
-                       strlcpy (host_client->name, s, sizeof (host_client->name));
-                       sv_player->v->netname = PR_SetString(host_client->name);
-               }
-               if ((val = GETEDICTFIELDVALUE(sv_player, eval_clientcolors)) && host_client->colors != val->_float)
-                       host_client->colors = val->_float;
-               host_client->frags = sv_player->v->frags;
-               if (gamemode == GAME_NEHAHRA)
-                       if ((val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)) && host_client->pmodel != val->_float)
-                               host_client->pmodel = val->_float;
-
-               // if the fields changed, send messages about the changes
+               host_client->edict = EDICT_NUM(i+1);
+
+               // DP_SV_CLIENTNAME
+               name = PR_GetString(host_client->edict->v->netname);
+               if (name == NULL)
+                       name = "";
+               // always point the string back at host_client->name to keep it safe
+               strlcpy (host_client->name, name, sizeof (host_client->name));
+               host_client->edict->v->netname = PR_SetString(host_client->name);
                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);
                        strcpy(host_client->old_name, host_client->name);
-                       for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
-                       {
-                               if (!client->netconnection)
-                                       continue;
-                               MSG_WriteByte (&client->message, svc_updatename);
-                               MSG_WriteByte (&client->message, i);
-                               MSG_WriteString (&client->message, host_client->name);
-                       }
+                       // send notification to all clients
+                       MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
+                       MSG_WriteByte (&sv.reliable_datagram, i);
+                       MSG_WriteString (&sv.reliable_datagram, host_client->name);
                }
+
+               // DP_SV_CLIENTCOLORS
+               // this is always found (since it's added by the progs loader)
+               if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
+                       host_client->colors = (int)val->_float;
                if (host_client->old_colors != host_client->colors)
                {
                        host_client->old_colors = host_client->colors;
-                       for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
-                       {
-                               if (!client->netconnection)
-                                       continue;
-                               MSG_WriteByte (&client->message, svc_updatecolors);
-                               MSG_WriteByte (&client->message, i);
-                               MSG_WriteByte (&client->message, host_client->colors);
-                       }
+                       // send notification to all clients
+                       MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
+                       MSG_WriteByte (&sv.reliable_datagram, i);
+                       MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
                }
+
+               // frags
+               host_client->frags = (int)host_client->edict->v->frags;
                if (host_client->old_frags != host_client->frags)
                {
                        host_client->old_frags = host_client->frags;
-                       for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
-                       {
-                               if (!client->netconnection)
-                                       continue;
-                               MSG_WriteByte (&client->message, svc_updatefrags);
-                               MSG_WriteByte (&client->message, i);
-                               MSG_WriteShort (&client->message, host_client->frags);
-                       }
+                       // send notification to all clients
+                       MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
+                       MSG_WriteByte (&sv.reliable_datagram, i);
+                       MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
                }
        }
 
@@ -1622,6 +1644,10 @@ void SV_SpawnServer (const char *server)
                ent->v = (void *)((qbyte *)sv.edictsfields + i * pr_edict_size);
        }
 
+       // fix up client->edict pointers for returning clients right away...
+       for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
+               host_client->edict = EDICT_NUM(i + 1);
+
        sv.datagram.maxsize = sizeof(sv.datagram_buf);
        sv.datagram.cursize = 0;
        sv.datagram.data = sv.datagram_buf;
@@ -1722,8 +1748,9 @@ void SV_SpawnServer (const char *server)
                SV_CreateBaseline ();
 
 // send serverinfo to all connected clients
+       // (note this also handles botclients coming back from a level change)
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
-               if (host_client->netconnection)
+               if (host_client->active)
                        SV_SendServerinfo(host_client);
 
        Con_DPrint("Server spawned.\n");