cvar_t timestamps = {CVAR_SAVE, "timestamps", "0"};
cvar_t timeformat = {CVAR_SAVE, "timeformat", "[%b %e %X] "};
-cvar_t sv_maxplayers = {0, "maxplayers", "8"};
-
/*
================
Host_EndGame
longjmp (host_abortserver, 1);
}
+mempool_t *sv_clients_mempool = NULL;
+
void Host_ServerOptions (void)
{
int i, numplayers;
if (numplayers > 1 && !deathmatch.integer)
Cvar_SetValueQuick(&deathmatch, 1);
- Cvar_SetValueQuick(&sv_maxplayers, numplayers);
+ svs.maxclients = numplayers;
+ sv_clients_mempool = Mem_AllocPool("server clients");
+ svs.clients = Mem_Alloc(sv_clients_mempool, sizeof(client_t) * svs.maxclients);
}
/*
Cvar_RegisterVariable (×tamps);
Cvar_RegisterVariable (&timeformat);
- Cvar_RegisterVariable(&sv_maxplayers);
-
Host_ServerOptions ();
}
vsnprintf(string, sizeof(string), fmt,argptr);
va_end(argptr);
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
- if ((client = svs.connectedclients[i]) && client->spawned)
+ if (client->spawned)
{
MSG_WriteByte(&client->message, svc_print);
MSG_WriteString(&client->message, string);
}
// send notification to all clients
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
- if (!(client = svs.connectedclients[i]))
+ if (!client->active)
continue;
MSG_WriteByte(&client->message, svc_updatename);
MSG_WriteByte(&client->message, host_client->number);
// free the client now
if (host_client->entitydatabase4)
EntityFrame4_FreeDatabase(host_client->entitydatabase4);
- // remove the index reference
- svs.connectedclients[host_client->number] = NULL;
- Mem_Free(host_client);
+ // clear the client struct (this sets active to false)
+ memset(host_client, 0, sizeof(*host_client));
}
/*
int i, count;
sizebuf_t buf;
char message[4];
- double start;
if (!sv.active)
return;
NetConn_Heartbeat(2);
NetConn_Heartbeat(2);
-// flush any pending messages - like the score!!!
- start = Sys_DoubleTime();
- do
- {
- count = 0;
- NetConn_ClientFrame();
- NetConn_ServerFrame();
- for (i = 0;i < MAX_SCOREBOARD;i++)
- {
- host_client = svs.connectedclients[i];
- if (host_client && host_client->message.cursize)
- {
- if (NetConn_CanSendMessage(host_client->netconnection))
- {
- NetConn_SendReliableMessage(host_client->netconnection, &host_client->message);
- SZ_Clear(&host_client->message);
- }
- else
- count++;
- }
- }
- if ((Sys_DoubleTime() - start) > 3.0)
- break;
- }
- while(count);
-
// make sure all the clients know we're disconnecting
buf.data = message;
buf.maxsize = 4;
if (count)
Con_Printf("Host_ShutdownServer: NetConn_SendToAll failed for %u clients\n", count);
- for (i = 0;i < MAX_SCOREBOARD;i++)
- if ((host_client = svs.connectedclients[i]))
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
+ if (host_client->active)
SV_DropClient(crash); // server shutdown
NetConn_CloseServerPorts();
// clear structures
//
memset(&sv, 0, sizeof(sv));
+ memset(svs.clients, 0, svs.maxclients*sizeof(client_t));
}
timecount = 0;
timetotal = 0;
c = 0;
- for (i = 0;i < MAX_SCOREBOARD;i++)
- if (svs.connectedclients[i])
+ for (i=0 ; i<svs.maxclients ; i++)
+ {
+ if (svs.clients[i].active)
c++;
+ }
Con_Printf ("serverprofile: %2i clients %2i msec\n", c, m);
}
else
print = SV_ClientPrintf;
- for (players = 0, j = 0;j < MAX_SCOREBOARD;j++)
- if (svs.connectedclients[j])
+ for (players = 0, j = 0;j < svs.maxclients;j++)
+ if (svs.clients[j].active)
players++;
print ("host: %s\n", Cvar_VariableString ("hostname"));
print ("version: %s build %s\n", gamename, buildstring);
print ("map: %s\n", sv.name);
- print ("players: %i active (%i max)\n\n", players, min(sv_maxplayers.integer, MAX_SCOREBOARD));
- for (j = 0;j < MAX_SCOREBOARD;j++)
+ print ("players: %i active (%i max)\n\n", players, svs.maxclients);
+ for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
{
- if (!(client = svs.connectedclients[j]))
+ if (!client->active)
continue;
seconds = (int)(realtime - client->netconnection->connecttime);
minutes = seconds / 60;
}
SV_ClientPrintf ("Client ping times:\n");
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
- if (!(client = svs.connectedclients[i]))
+ if (!client->active)
continue;
total = 0;
for (j=0 ; j<NUM_PING_TIMES ; j++)
if (cmd_source != src_command)
return;
- if (!sv.active)
+ if (cls.state != ca_connected || !sv.active)
{
Con_Printf ("Not playing a local game.\n");
return;
return;
}
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0;i < svs.maxclients;i++)
{
- if (svs.connectedclients[i])
+ if (svs.clients[i].active)
{
if (i > 0)
{
Con_Printf("Can't save multiplayer games.\n");
return;
}
- if (svs.connectedclients[i]->edict->v->deadflag)
+ if (svs.clients[i].edict->v->deadflag)
{
Con_Printf("Can't savegame with a dead player\n");
return;
Host_SavegameComment (comment);
FS_Printf (f, "%s\n", comment);
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
- FS_Printf (f, "%f\n", svs.connectedclients[0]->spawn_parms[i]);
+ FS_Printf (f, "%f\n", svs.clients[0].spawn_parms[i]);
FS_Printf (f, "%d\n", current_skill);
FS_Printf (f, "%s\n", sv.name);
FS_Printf (f, "%f\n",sv.time);
FS_Close (f);
for (i = 0;i < NUM_SPAWN_PARMS;i++)
- svs.connectedclients[0]->spawn_parms[i] = spawn_parms[i];
+ svs.clients[0].spawn_parms[i] = spawn_parms[i];
// 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))
text[j++] = '\n';
text[j++] = 0;
- for (j = 0;j < MAX_SCOREBOARD;j++)
- if ((host_client = svs.connectedclients[j]) && host_client->spawned && (!teamplay.integer || host_client->edict->v->team == save->edict->v->team))
+ for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
+ if (host_client->spawned && (!teamplay.integer || host_client->edict->v->team == save->edict->v->team))
SV_ClientPrintf("%s", text);
host_client = save;
text[j++] = 0;
save = host_client;
- for (j = 0;j < MAX_SCOREBOARD;j++)
- if ((host_client = svs.connectedclients[j]) && host_client->spawned && !strcasecmp(host_client->name, Cmd_Argv(1)))
+ for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
+ if (host_client->spawned && !strcasecmp(host_client->name, Cmd_Argv(1)))
SV_ClientPrintf("%s", text);
host_client = save;
}
MSG_WriteByte (&host_client->message, svc_time);
MSG_WriteFloat (&host_client->message, sv.time);
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
- if (!(client = svs.connectedclients[i]))
+ if (!client->active)
continue;
MSG_WriteByte (&host_client->message, svc_updatename);
MSG_WriteByte (&host_client->message, i);
if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
{
i = atof(Cmd_Argv(2)) - 1;
- if (i < 0 || i >= MAX_SCOREBOARD || !(host_client = svs.connectedclients[i]))
+ if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
return;
byNumber = true;
}
else
{
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if (!(host_client = svs.connectedclients[i]))
+ if (!host_client->active)
continue;
if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
break;
}
}
- if (i < MAX_SCOREBOARD)
+ if (i < svs.maxclients)
{
if (cmd_source == src_command)
{
Cbuf_AddText ("connect local");
}
+static void MaxPlayers_f(void)
+{
+ int n;
+
+ if (Cmd_Argc() != 2)
+ {
+ Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
+ return;
+ }
+
+ if (sv.active)
+ {
+ Con_Printf("maxplayers can not be changed while a server is running.\n");
+ return;
+ }
+
+ n = atoi(Cmd_Argv(1));
+ n = bound(1, n, MAX_SCOREBOARD);
+ Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
+
+ if (svs.clients)
+ Mem_Free(svs.clients);
+ svs.maxclients = n;
+ svs.clients = Mem_Alloc(sv_clients_mempool, sizeof(client_t) * svs.maxclients);
+ if (n == 1)
+ Cvar_Set ("deathmatch", "0");
+ else
+ Cvar_Set ("deathmatch", "1");
+}
+
//=============================================================================
/*
Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
Cmd_AddCommand ("spawn", Host_Spawn_f);
Cmd_AddCommand ("begin", Host_Begin_f);
+ Cmd_AddCommand ("maxplayers", MaxPlayers_f);
Cvar_RegisterVariable(&sv_cheats);
}
m_state = m_gameoptions;
m_entersound = true;
if (maxplayers == 0)
- maxplayers = sv_maxplayers.integer;
+ maxplayers = svs.maxclients;
if (maxplayers < 2)
maxplayers = min(8, MAX_SCOREBOARD);
}
int NetConn_IsLocalGame(void)
{
- int i;
- if (cls.state == ca_connected && sv.active/* && LHNETADDRESS_GetAddressType(cl.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP*/)
- {
- // make sure there are no other connected clients
- for (i = 1;i < MAX_SCOREBOARD;i++)
- if (svs.connectedclients[i])
- return false;
+ if (cls.state == ca_connected && sv.active && cl.maxclients == 1)
return true;
- }
return false;
}
extern void SV_ConnectClient(int clientnum, netconn_t *netconnection);
int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, lhnetaddress_t *peeraddress)
{
- int i, n, ret, clientnum, responselength, best, clientcount;
+ int i, n, ret, clientnum, responselength, best;
double besttime;
client_t *client;
netconn_t *conn;
else
{
// see if this is a duplicate connection request
- for (clientnum = 0;clientnum < MAX_SCOREBOARD;clientnum++)
- if ((client = svs.connectedclients[clientnum]) && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0)
+ for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++)
+ if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0)
break;
- if (clientnum < MAX_SCOREBOARD)
+ if (clientnum < svs.maxclients)
{
// duplicate connection request
if (realtime - client->netconnection->connecttime < 2.0)
else
{
// this is a new client, find a slot
- for (clientcount = 0, clientnum = 0;clientnum < MAX_SCOREBOARD;clientnum++)
- if (svs.connectedclients[clientnum])
- clientcount++;
- for (clientnum = 0;clientnum < MAX_SCOREBOARD;clientnum++)
- if (!svs.connectedclients[clientnum])
+ for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++)
+ if (!client->active)
break;
- if (clientcount < max(1, sv_maxplayers.integer) && clientnum < MAX_SCOREBOARD)
+ if (clientnum < svs.maxclients)
{
- // allocate and prepare the client struct
- if ((client = Mem_Alloc(sv_clients_mempool, sizeof(client_t))))
+ // prepare the client struct
+ if ((client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool)))
{
- if ((client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool)))
+ if ((conn = NetConn_Open(mysocket, peeraddress)))
{
- if ((conn = NetConn_Open(mysocket, peeraddress)))
- {
- // allocated connection
- LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
- if (developer.integer)
- Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address);
- NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
- // now set up the client struct
- svs.connectedclients[clientnum] = client;
- SV_ConnectClient(clientnum, conn);
- NetConn_Heartbeat(1);
- }
- else
- {
- EntityFrame4_FreeDatabase(client->entitydatabase4);
- Mem_Free(client);
- }
+ // allocated connection
+ LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
+ if (developer.integer)
+ Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address);
+ NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
+ // now set up the client
+ SV_ConnectClient(clientnum, conn);
+ NetConn_Heartbeat(1);
}
else
- Mem_Free(client);
+ EntityFrame4_FreeDatabase(client->entitydatabase4);
}
}
else
// If there was a challenge in the getinfo message
if (length > 8 && string[7] == ' ')
challenge = string + 8;
- for (i = 0, n = 0;i < MAX_SCOREBOARD;i++)
- if (svs.connectedclients[i])
+ for (i = 0, n = 0;i < svs.maxclients;i++)
+ if (svs.clients[i].active)
n++;
responselength = snprintf(response, sizeof(response), "\377\377\377\377infoResponse\x0A"
"\\gamename\\%s\\modname\\%s\\sv_maxclients\\%d"
"\\clients\\%d\\mapname\\%s\\hostname\\%s\\protocol\\%d%s%s",
- gamename, com_modname, min(sv_maxplayers.integer, MAX_SCOREBOARD), n,
+ gamename, com_modname, svs.maxclients, n,
sv.name, hostname.string, NET_PROTOCOL_VERSION, challenge ? "\\challenge\\" : "", challenge ? challenge : "");
// does it fit in the buffer?
if (responselength < (int)sizeof(response))
else
{
// see if this is a duplicate connection request
- for (clientnum = 0;clientnum < MAX_SCOREBOARD;clientnum++)
- if ((client = svs.connectedclients[clientnum]) && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0)
+ for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++)
+ if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0)
break;
- if (clientnum < MAX_SCOREBOARD)
+ if (clientnum < svs.maxclients)
{
// duplicate connection request
if (realtime - client->netconnection->connecttime < 2.0)
else
{
// this is a new client, find a slot
- for (clientnum = 0;clientnum < MAX_SCOREBOARD;clientnum++)
- if (!(client = svs.connectedclients[clientnum]))
+ for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++)
+ if (!client->active)
break;
- // WARNING: this is broken code
- if (clientnum < MAX_SCOREBOARD && (client->netconnection = conn = NetConn_Open(mysocket, peeraddress)) != NULL)
+ if (clientnum < svs.maxclients && (client->netconnection = conn = NetConn_Open(mysocket, peeraddress)) != NULL)
{
// connect to the client
// everything is allocated, just fill in the details
MSG_WriteString(&net_message, hostname.string);
MSG_WriteString(&net_message, sv.name);
MSG_WriteByte(&net_message, net_activeconnections);
- MSG_WriteByte(&net_message, min(sv_maxplayers.integer, MAX_SCOREBOARD));
+ MSG_WriteByte(&net_message, svs.maxclients);
MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
}
}
#endif
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if ((host_client = svs.connectedclients[i]))
+ if (host_client->netconnection && host_client->netconnection->mysocket == mysocket && !LHNETADDRESS_Compare(&host_client->netconnection->peeraddress, peeraddress))
{
- if (host_client->netconnection)
- {
- if (host_client->netconnection->mysocket == mysocket && !LHNETADDRESS_Compare(&host_client->netconnection->peeraddress, peeraddress))
- {
- sv_player = host_client->edict;
- if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length)) == 2)
- SV_ReadClientMessage();
- return ret;
- }
- }
- else
- {
- Con_Printf("Removing client with no netconnection!\n");
- SV_DropClient(true);
- }
+ sv_player = host_client->edict;
+ if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length)) == 2)
+ SV_ReadClientMessage();
+ return ret;
}
}
}
for (i = 0;i < sv_numsockets;i++)
while (sv_sockets[i] && (length = NetConn_Read(sv_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0)
NetConn_ServerParsePacket(sv_sockets[i], readbuffer, length, &peeraddress);
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if ((host_client = svs.connectedclients[i]) && realtime > host_client->netconnection->timeout)
+ if (host_client->netconnection && realtime > host_client->netconnection->timeout)
{
Con_Printf("Client \"%s\" connection timed out\n", host_client->name);
sv_player = host_client->edict;
// make advertising optional and don't advertise singleplayer games, and
// only send a heartbeat as often as the admin wants
- if (sv.active && sv_public.integer && (!cl.islocalgame || sv_maxplayers.integer >= 2) && (priority > 1 || realtime > nextheartbeattime))
+ if (sv.active && sv_public.integer && svs.maxclients >= 2 && (priority > 1 || realtime > nextheartbeattime))
{
nextheartbeattime = realtime + sv_heartbeatperiod.value;
for (masternum = 0;sv_masters[masternum].name;masternum++)
count = 0;
NetConn_ClientFrame();
NetConn_ServerFrame();
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if ((host_client = svs.connectedclients[i]))
+ if (host_client->netconnection)
{
if (NetConn_CanSendMessage(host_client->netconnection))
{
entnum = G_EDICTNUM(OFS_PARM0);
s = PF_VarString(1);
- if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1])
+ if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
{
Con_Printf ("tried to sprint to a non-client\n");
return;
}
- client = svs.connectedclients[entnum-1];
+ client = svs.clients + entnum-1;
+ if (!client->netconnection)
+ return;
MSG_WriteChar(&client->message,svc_print);
MSG_WriteString(&client->message, s );
}
entnum = G_EDICTNUM(OFS_PARM0);
s = PF_VarString(1);
- if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1])
+ if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
{
Con_Printf ("tried to sprint to a non-client\n");
return;
}
- client = svs.connectedclients[entnum-1];
+ client = svs.clients + entnum-1;
+ if (!client->netconnection)
+ return;
MSG_WriteChar(&client->message,svc_centerprint);
MSG_WriteString(&client->message, s );
}
// cycle to the next one
- check = bound(1, check, MAX_SCOREBOARD);
- if (check == MAX_SCOREBOARD)
+ check = bound(1, check, svs.maxclients);
+ if (check == svs.maxclients)
i = 1;
else
i = check + 1;
// count the cost
pr_xfunction->builtinsprofile++;
// wrap around
- if (i == MAX_SCOREBOARD+1)
+ if (i == svs.maxclients+1)
i = 1;
// look up the client's edict
ent = EDICT_NUM(i);
client_t *old;
entnum = G_EDICTNUM(OFS_PARM0);
- if (entnum < 1 || entnum > MAX_SCOREBOARD)
- Host_Error ("Parm 0 not a client");
+ if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
+ {
+ Con_Printf("Can't stuffcmd to a non-client");
+ return;
+ }
str = G_STRING(OFS_PARM1);
old = host_client;
- if ((host_client = svs.connectedclients[entnum-1]))
+ if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
Host_ClientCommands ("%s", str);
host_client = old;
}
*/
void PF_localcmd (void)
{
- char *str;
-
- str = G_STRING(OFS_PARM0);
- Cbuf_AddText (str);
+ Cbuf_AddText(G_STRING(OFS_PARM0));
}
/*
*/
void PF_cvar (void)
{
- char *str;
-
- str = G_STRING(OFS_PARM0);
-
- G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
+ G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
}
/*
*/
void PF_cvar_set (void)
{
- char *var, *val;
-
- var = G_STRING(OFS_PARM0);
- val = G_STRING(OFS_PARM1);
-
- Cvar_Set (var, val);
+ Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
}
/*
ed = G_EDICT(OFS_PARM0);
if (ed == sv.edicts)
Host_Error("remove: tried to remove world\n");
- if (NUM_FOR_EDICT(ed) <= MAX_SCOREBOARD)
+ if (NUM_FOR_EDICT(ed) <= svs.maxclients)
Host_Error("remove: tried to remove a client\n");
ED_Free (ed);
}
if (sv.state != ss_active)
return;
- for (j = 0;j < MAX_SCOREBOARD;j++)
+ for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
{
- if ((client = svs.connectedclients[j]))
+ if (client->netconnection)
{
MSG_WriteChar (&client->message, svc_lightstyle);
MSG_WriteChar (&client->message,style);
case MSG_ONE:
ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
entnum = NUM_FOR_EDICT(ent);
- if (entnum < 1 || entnum > MAX_SCOREBOARD || svs.connectedclients[entnum-1] == NULL)
- Host_Error("WriteDest: not a client");
- return &svs.connectedclients[entnum-1]->message;
+ if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
+ Con_Printf("WriteDest: tried to write to non-client\n");
+ return &svs.clients[entnum-1].message;
case MSG_ALL:
return &sv.reliable_datagram;
ent = G_EDICT(OFS_PARM0);
i = NUM_FOR_EDICT(ent);
- if (i < 1 || i > MAX_SCOREBOARD || !svs.connectedclients[i-1])
- Host_Error ("Entity is not a client");
+ if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
+ {
+ Con_Printf("tried to setspawnparms on a non-client\n");
+ return;
+ }
// copy spawn parms out of the client_t
- client = svs.connectedclients[i-1];
+ client = svs.clients + i-1;
for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
(&pr_global_struct->parm1)[i] = client->spawn_parms[i];
}
entnum = G_EDICTNUM(OFS_PARM0);
i = G_FLOAT(OFS_PARM1);
- if (entnum < 1 || entnum > MAX_SCOREBOARD || !(client = svs.connectedclients[entnum-1]))
+ if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
{
Con_Printf ("tried to setcolor a non-client\n");
return;
}
+ client = svs.clients + entnum-1;
if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
val->_float = i;
client->colors = i;
//find client for this entity
i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
- if (i < 0 || i >= MAX_SCOREBOARD || !svs.connectedclients[i])
- Host_Error("PF_clientcommand: entity is not a client");
+ if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
+ {
+ Con_Printf("PF_clientcommand: entity is not a client");
+ return;
+ }
temp_client = host_client;
- host_client = svs.connectedclients[i];
+ host_client = svs.clients + i;
Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
host_client = temp_client;
}
e->e->free = false;
// LordHavoc: for consistency set these here
num = NUM_FOR_EDICT(e) - 1;
- if (num >= 0 && num < MAX_SCOREBOARD && svs.connectedclients[num])
+ if (num >= 0 && num < svs.maxclients)
{
e->v->colormap = num + 1;
- e->v->team = (svs.connectedclients[num]->colors & 15) + 1;
- e->v->netname = PR_SetString(svs.connectedclients[num]->name);
+ e->v->team = (svs.clients[num].colors & 15) + 1;
+ e->v->netname = PR_SetString(svs.clients[num].name);
}
}
int i;
edict_t *e;
- for (i = MAX_SCOREBOARD + 1;i < sv.num_edicts;i++)
+ for (i = svs.maxclients + 1;i < sv.num_edicts;i++)
{
e = EDICT_NUM(i);
// the first couple seconds of server time can involve a lot of
typedef struct
{
- // NULL pointers are non-existent clients
- struct client_s *connectedclients[MAX_SCOREBOARD];
+ // number of svs.clients slots (updated by maxplayers command)
+ int maxclients;
+ // client slots
+ struct client_s *clients;
// episode completion information
int serverflags;
// cleared when at SV_SpawnServer
typedef struct client_s
{
+ // false = empty client slot
+ qboolean active;
// false = don't send datagrams
qboolean spawned;
// has been told to go to another level
qboolean sendsignon;
// remove this client immediately
qboolean deadsocket;
- // index of this client in the svs.connectedclients pointer array
+ // index of this client in the svs.clients array
int number;
// reliable messages must be sent periodically
extern cvar_t sv_aim;
extern cvar_t sv_stepheight;
extern cvar_t sv_jumpstep;
-extern cvar_t sv_maxplayers;
extern mempool_t *sv_clients_mempool;
extern mempool_t *sv_edicts_mempool;
static char localmodels[MAX_MODELS][5]; // inline model names for precache
mempool_t *sv_edicts_mempool = NULL;
-mempool_t *sv_clients_mempool = NULL;
//============================================================================
sprintf (localmodels[i], "*%i", i);
sv_edicts_mempool = Mem_AllocPool("server edicts");
- sv_clients_mempool = Mem_AllocPool("server clients");
}
/*
MSG_WriteByte (&client->message, svc_serverinfo);
MSG_WriteLong (&client->message, DPPROTOCOL_VERSION4);
- MSG_WriteByte (&client->message, MAX_SCOREBOARD);
+ MSG_WriteByte (&client->message, svs.maxclients);
if (!coop.integer && deathmatch.integer)
MSG_WriteByte (&client->message, GAME_DEATHMATCH);
int i;
float spawn_parms[NUM_SPAWN_PARMS];
- client = svs.connectedclients[clientnum];
+ client = svs.clients + clientnum;
// set up the client_t
if (sv.loadgame)
memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
memset (client, 0, sizeof(*client));
+ client->active = true;
client->netconnection = netconnection;
Con_DPrintf("Client %s connected\n", client->netconnection->address);
// we can omit invisible entities with no effects that are not clients
// LordHavoc: this could kill tags attached to an invisible entity, I
// just hope we never have to support that case
- if (cs.number > MAX_SCOREBOARD && ((cs.effects & EF_NODRAW) || (!cs.modelindex && !cs.specialvisibilityradius)))
+ if (cs.number > svs.maxclients && ((cs.effects & EF_NODRAW) || (!cs.modelindex && !cs.specialvisibilityradius)))
continue;
sendentitiesindex[e] = sendentities + numsendentities;
sendentities[numsendentities++] = cs;
char *s;
// check for changes to be sent over the reliable streams
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- // only update the client fields if they've spawned in
- if ((host_client = svs.connectedclients[i]) && host_client->spawned)
+ // update the host_client fields we care about according to the entity fields
+ sv_player = host_client->edict;
+ s = PR_GetString(sv_player->v->netname);
+ if (s != host_client->name)
{
- // update the host_client fields we care about according to the entity fields
- sv_player = host_client->edict;
- 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
- strncpy(host_client->name, s, sizeof(host_client->name) - 1);
- 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
- if (strcmp(host_client->old_name, host_client->name))
+ if (s == NULL)
+ s = "";
+ // point the string back at host_client->name to keep it safe
+ strncpy(host_client->name, s, sizeof(host_client->name) - 1);
+ 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
+ if (strcmp(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++)
{
- strcpy(host_client->old_name, host_client->name);
- for (j = 0;j < MAX_SCOREBOARD;j++)
- {
- if (!(client = svs.connectedclients[j]) || !client->spawned)
- continue;
- MSG_WriteByte (&client->message, svc_updatename);
- MSG_WriteByte (&client->message, i);
- MSG_WriteString (&client->message, host_client->name);
- }
+ if (!client->spawned || !client->netconnection)
+ continue;
+ MSG_WriteByte (&client->message, svc_updatename);
+ MSG_WriteByte (&client->message, i);
+ MSG_WriteString (&client->message, host_client->name);
}
- if (host_client->old_colors != host_client->colors)
+ }
+ 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++)
{
- host_client->old_colors = host_client->colors;
- for (j = 0;j < MAX_SCOREBOARD;j++)
- {
- if (!(client = svs.connectedclients[j]) || !client->spawned)
- continue;
- MSG_WriteByte (&client->message, svc_updatecolors);
- MSG_WriteByte (&client->message, i);
- MSG_WriteByte (&client->message, host_client->colors);
- }
+ if (!client->spawned || !client->netconnection)
+ continue;
+ MSG_WriteByte (&client->message, svc_updatecolors);
+ MSG_WriteByte (&client->message, i);
+ MSG_WriteByte (&client->message, host_client->colors);
}
- if (host_client->old_frags != host_client->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++)
{
- host_client->old_frags = host_client->frags;
- for (j = 0;j < MAX_SCOREBOARD;j++)
- {
- if (!(client = svs.connectedclients[j]) || !client->spawned)
- continue;
- MSG_WriteByte (&client->message, svc_updatefrags);
- MSG_WriteByte (&client->message, i);
- MSG_WriteShort (&client->message, host_client->frags);
- }
+ if (!client->spawned || !client->netconnection)
+ continue;
+ MSG_WriteByte (&client->message, svc_updatefrags);
+ MSG_WriteByte (&client->message, i);
+ MSG_WriteShort (&client->message, host_client->frags);
}
}
}
- for (j = 0;j < MAX_SCOREBOARD;j++)
- if ((client = svs.connectedclients[j]))
+ for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
+ if (client->netconnection)
SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
SZ_Clear (&sv.reliable_datagram);
SV_UpdateToReliableMessages();
// build individual updates
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if (!(host_client = svs.connectedclients[i]))
+ if (!host_client->active)
continue;
+ if (!host_client->netconnection)
+ {
+ SZ_Clear(&host_client->message);
+ continue;
+ }
- if (host_client->deadsocket || !host_client->netconnection || host_client->message.overflowed)
+ if (host_client->deadsocket || host_client->message.overflowed)
{
SV_DropClient (true); // if the message couldn't send, kick off
continue;
if (svent->e->free)
continue;
- if (entnum > MAX_SCOREBOARD && !svent->v->modelindex)
+ if (entnum > svs.maxclients && !svent->v->modelindex)
continue;
// create entity baseline
VectorCopy (svent->v->angles, svent->e->baseline.angles);
svent->e->baseline.frame = svent->v->frame;
svent->e->baseline.skin = svent->v->skin;
- if (entnum > 0 && entnum <= MAX_SCOREBOARD)
+ if (entnum > 0 && entnum <= svs.maxclients)
{
svent->e->baseline.colormap = entnum;
svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
svs.serverflags = pr_global_struct->serverflags;
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if (!(host_client = svs.connectedclients[i]))
+ if (!host_client->active)
continue;
// call the progs to get default spawn parms for the new client
// allocate server memory
// start out with just enough room for clients and a reasonable estimate of entities
- sv.max_edicts = max(MAX_SCOREBOARD + 1, 512);
+ sv.max_edicts = max(svs.maxclients + 1, 512);
sv.max_edicts = min(sv.max_edicts, MAX_EDICTS);
// clear the edict memory pool
sv.signon.data = sv.signon_buf;
// leave slots at start for clients only
- sv.num_edicts = MAX_SCOREBOARD+1;
+ sv.num_edicts = svs.maxclients+1;
sv.state = ss_loading;
sv.paused = false;
#endif
// send serverinfo to all connected clients
- for (i = 0;i < MAX_SCOREBOARD;i++)
- if ((host_client = svs.connectedclients[i]))
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
+ if (host_client->netconnection)
SV_SendServerinfo(host_client);
Con_DPrintf ("Server spawned.\n");
if (pr_global_struct->force_retouch)
SV_LinkEdict (ent, true); // force retouch even for stationary
- if (i > 0 && i <= MAX_SCOREBOARD)
+ if (i > 0 && i <= svs.maxclients)
{
- if (!svs.connectedclients[i-1] || !svs.connectedclients[i-1]->spawned)
+ if (!svs.clients[i-1].spawned)
continue;
// connected slot
// call standard client pre-think
VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
}
// relink normal entities here, players always get relinked so don't relink twice
- if (!(i > 0 && i <= MAX_SCOREBOARD))
+ if (!(i > 0 && i <= svs.maxclients))
SV_LinkEdict(ent, false);
break;
case MOVETYPE_STEP:
SV_Physics_Toss (ent);
break;
case MOVETYPE_FLY:
- if (i > 0 && i <= MAX_SCOREBOARD)
+ if (i > 0 && i <= svs.maxclients)
{
if (SV_RunThink (ent))
{
break;
}
- if (i > 0 && i <= MAX_SCOREBOARD && !ent->e->free)
+ if (i > 0 && i <= svs.maxclients && !ent->e->free)
{
SV_CheckVelocity (ent);
extern void SV_SendServerinfo(client_t *client);
void SV_ReadClientMessage(void)
{
- int cmd, clientnum = host_client->number;
+ int cmd;
char *s;
//MSG_BeginReading ();
for(;;)
{
- if (!(host_client = svs.connectedclients[clientnum]))
+ if (!host_client->active)
{
// a command caused an error
SV_DropClient (false);
{
int i;
- for (i = 0;i < MAX_SCOREBOARD;i++)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
{
- if (!(host_client = svs.connectedclients[i]))
+ if (!host_client->active)
continue;
- sv_player = host_client->edict;
-
if (!host_client->spawned)
{
// clear client movement until a new packet is received
if (sv.frametime)
{
+ sv_player = host_client->edict;
+
// LordHavoc: QuakeC replacement for SV_ClientThink (player movement)
if (SV_PlayerPhysicsQC)
{
-n darkplaces: make LHNET_Read print out the names of read errors (yummyluv)
-n darkplaces: revert noclip movement to match nq for compatibility with mods that trap movement as input (MauveBib)
-n dpmod: make grapple off-hand (joe hill)
+0 darkplaces: clean up the DrawQ_ blendfunc handling, instead of taking DRAWFLAG_ADDITIVE they should take blendfunc values (Black)
0 darkplaces: ability to disable fopen builtin access to read /, read data/, write data/, or disable fopen builtin entirely
0 darkplaces: add DP_GFX_QUAKE3MODELTAGS, DP_GFX_SKINFILES, and any other new extensions to the wiki
0 darkplaces: add DP_LITSUPPORT extension