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"};
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
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));
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;
}
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;
}
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);
}
}
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;
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");