From ae1534f3ea57ed5165d1103ad4bba9bc2fa9272f Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 30 Aug 2003 01:54:31 +0000 Subject: [PATCH] reverted the massive svs.connectedclients change, now back to svs.clients and svs.maxclients like quake this fixes mods detecting singleplayer as multiplayer this fixes frikbot frags updates on the scoreboard added most of the capability necessary for botclient extension git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3428 d7cf8633-e32d-0410-b094-e92efae38249 --- host.c | 61 +++++++---------------- host_cmd.c | 77 ++++++++++++++++++++--------- menu.c | 2 +- netconn.c | 113 ++++++++++++++++-------------------------- pr_cmds.c | 78 ++++++++++++++--------------- pr_edict.c | 8 +-- server.h | 11 +++-- sv_main.c | 140 ++++++++++++++++++++++++++--------------------------- sv_phys.c | 10 ++-- sv_user.c | 12 ++--- todo | 1 + 11 files changed, 247 insertions(+), 266 deletions(-) diff --git a/host.c b/host.c index 69e38368..e6401a03 100644 --- a/host.c +++ b/host.c @@ -96,8 +96,6 @@ cvar_t temp1 = {0, "temp1","0"}; 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 @@ -182,6 +180,8 @@ void Host_Error (const char *error, ...) longjmp (host_abortserver, 1); } +mempool_t *sv_clients_mempool = NULL; + void Host_ServerOptions (void) { int i, numplayers; @@ -241,7 +241,9 @@ void Host_ServerOptions (void) 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); } /* @@ -283,8 +285,6 @@ void Host_InitLocal (void) Cvar_RegisterVariable (×tamps); Cvar_RegisterVariable (&timeformat); - Cvar_RegisterVariable(&sv_maxplayers); - Host_ServerOptions (); } @@ -358,9 +358,9 @@ void SV_BroadcastPrintf(const char *fmt, ...) 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); @@ -436,9 +436,9 @@ void SV_DropClient(qboolean crash) } // 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); @@ -456,9 +456,8 @@ void SV_DropClient(qboolean crash) // 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)); } /* @@ -473,7 +472,6 @@ void Host_ShutdownServer(qboolean crash) int i, count; sizebuf_t buf; char message[4]; - double start; if (!sv.active) return; @@ -489,32 +487,6 @@ void Host_ShutdownServer(qboolean crash) 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; @@ -524,8 +496,8 @@ void Host_ShutdownServer(qboolean crash) 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(); @@ -534,6 +506,7 @@ void Host_ShutdownServer(qboolean crash) // clear structures // memset(&sv, 0, sizeof(sv)); + memset(svs.clients, 0, svs.maxclients*sizeof(client_t)); } @@ -835,9 +808,11 @@ void Host_Frame (float time) timecount = 0; timetotal = 0; c = 0; - for (i = 0;i < MAX_SCOREBOARD;i++) - if (svs.connectedclients[i]) + for (i=0 ; iactive) continue; seconds = (int)(realtime - client->netconnection->connecttime); minutes = seconds / 60; @@ -241,9 +241,9 @@ void Host_Ping_f (void) } 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 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; @@ -468,7 +468,7 @@ void Host_Savegame_f (void) Host_SavegameComment (comment); FS_Printf (f, "%s\n", comment); for (i=0 ; ispawn_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); @@ -649,7 +649,7 @@ void Host_PerformLoadGame(char *name) 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)) @@ -768,8 +768,8 @@ void Host_Say(qboolean teamonly) 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; @@ -845,8 +845,8 @@ void Host_Tell_f(void) 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; } @@ -1115,9 +1115,9 @@ void Host_Spawn_f (void) 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); @@ -1214,22 +1214,22 @@ void Host_Kick_f (void) 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) { @@ -1659,6 +1659,36 @@ void Host_PerformSpawnServerAndLoadGame(void) 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"); +} + //============================================================================= /* @@ -1723,6 +1753,7 @@ void Host_InitCommands (void) 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); } diff --git a/menu.c b/menu.c index f01dda9a..1ad5cf06 100644 --- a/menu.c +++ b/menu.c @@ -2970,7 +2970,7 @@ void M_Menu_GameOptions_f (void) 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); } diff --git a/netconn.c b/netconn.c index 08ab2a0c..90d6d40d 100755 --- a/netconn.c +++ b/netconn.c @@ -621,15 +621,8 @@ void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peer 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; } @@ -987,7 +980,7 @@ static void NetConn_BuildChallengeString(char *buffer, int bufferlength) 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; @@ -1057,10 +1050,10 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, 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) @@ -1081,39 +1074,27 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, 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 @@ -1135,13 +1116,13 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, // 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)) @@ -1201,10 +1182,10 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, 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) @@ -1233,11 +1214,10 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, 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 @@ -1292,7 +1272,7 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, 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); @@ -1367,25 +1347,14 @@ int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length, } } #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; } } } @@ -1401,9 +1370,9 @@ void NetConn_ServerFrame(void) 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; @@ -1478,7 +1447,7 @@ void NetConn_Heartbeat(int priority) // 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++) @@ -1505,9 +1474,9 @@ int NetConn_SendToAll(sizebuf_t *data, double blocktime) 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)) { diff --git a/pr_cmds.c b/pr_cmds.c index b45bdccc..3ee8a180 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -372,13 +372,15 @@ void PF_sprint (void) 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 ); } @@ -402,13 +404,15 @@ void PF_centerprint (void) 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 ); } @@ -829,8 +833,8 @@ int PF_newcheckclient (int check) // 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; @@ -840,7 +844,7 @@ int PF_newcheckclient (int check) // 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); @@ -930,12 +934,15 @@ void PF_stuffcmd (void) 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; } @@ -951,10 +958,7 @@ localcmd (string) */ void PF_localcmd (void) { - char *str; - - str = G_STRING(OFS_PARM0); - Cbuf_AddText (str); + Cbuf_AddText(G_STRING(OFS_PARM0)); } /* @@ -966,11 +970,7 @@ float cvar (string) */ 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)); } /* @@ -982,12 +982,7 @@ float cvar (string) */ 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)); } /* @@ -1116,7 +1111,7 @@ void PF_Remove (void) 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); } @@ -1440,9 +1435,9 @@ void PF_lightstyle (void) 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); @@ -1729,9 +1724,9 @@ sizebuf_t *WriteDest (void) 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; @@ -1841,11 +1836,14 @@ void PF_setspawnparms (void) 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]; } @@ -2084,12 +2082,13 @@ void PF_setcolor (void) 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; @@ -2887,11 +2886,14 @@ void PF_clientcommand (void) //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; } diff --git a/pr_edict.c b/pr_edict.c index 3c3b31e6..445e0449 100644 --- a/pr_edict.c +++ b/pr_edict.c @@ -199,11 +199,11 @@ void ED_ClearEdict (edict_t *e) 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); } } @@ -223,7 +223,7 @@ edict_t *ED_Alloc (void) 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 diff --git a/server.h b/server.h index 490dd52c..fdc94cd2 100644 --- a/server.h +++ b/server.h @@ -24,8 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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 @@ -99,6 +101,8 @@ typedef struct 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 @@ -107,7 +111,7 @@ typedef struct client_s 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 @@ -247,7 +251,6 @@ extern cvar_t sv_idealpitchscale; 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; diff --git a/sv_main.c b/sv_main.c index ada5adbc..8810480e 100644 --- a/sv_main.c +++ b/sv_main.c @@ -32,7 +32,6 @@ server_static_t svs; static char localmodels[MAX_MODELS][5]; // inline model names for precache mempool_t *sv_edicts_mempool = NULL; -mempool_t *sv_clients_mempool = NULL; //============================================================================ @@ -71,7 +70,6 @@ void SV_Init (void) sprintf (localmodels[i], "*%i", i); sv_edicts_mempool = Mem_AllocPool("server edicts"); - sv_clients_mempool = Mem_AllocPool("server clients"); } /* @@ -261,7 +259,7 @@ void SV_SendServerinfo (client_t *client) 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); @@ -308,12 +306,13 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) 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); @@ -822,7 +821,7 @@ void SV_PrepareEntitiesForSending(void) // 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; @@ -1345,71 +1344,67 @@ void SV_UpdateToReliableMessages (void) 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); @@ -1453,12 +1448,17 @@ void SV_SendClientMessages (void) 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; @@ -1565,7 +1565,7 @@ void SV_CreateBaseline (void) if (svent->e->free) continue; - if (entnum > MAX_SCOREBOARD && !svent->v->modelindex) + if (entnum > svs.maxclients && !svent->v->modelindex) continue; // create entity baseline @@ -1573,7 +1573,7 @@ void SV_CreateBaseline (void) 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"); @@ -1656,9 +1656,9 @@ void SV_SaveSpawnparms (void) 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 @@ -1766,7 +1766,7 @@ void SV_SpawnServer (const char *server) // 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 @@ -1799,7 +1799,7 @@ void SV_SpawnServer (const char *server) 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; @@ -1892,8 +1892,8 @@ void SV_SpawnServer (const char *server) #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"); diff --git a/sv_phys.c b/sv_phys.c index 6cfa187e..83ba3545 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -1314,9 +1314,9 @@ void SV_Physics (void) 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 @@ -1349,7 +1349,7 @@ void SV_Physics (void) 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: @@ -1372,7 +1372,7 @@ void SV_Physics (void) SV_Physics_Toss (ent); break; case MOVETYPE_FLY: - if (i > 0 && i <= MAX_SCOREBOARD) + if (i > 0 && i <= svs.maxclients) { if (SV_RunThink (ent)) { @@ -1388,7 +1388,7 @@ void SV_Physics (void) break; } - if (i > 0 && i <= MAX_SCOREBOARD && !ent->e->free) + if (i > 0 && i <= svs.maxclients && !ent->e->free) { SV_CheckVelocity (ent); diff --git a/sv_user.c b/sv_user.c index 05624d81..a0be1080 100644 --- a/sv_user.c +++ b/sv_user.c @@ -665,14 +665,14 @@ SV_ReadClientMessage 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); @@ -761,13 +761,11 @@ void SV_RunClients (void) { 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 @@ -777,6 +775,8 @@ void SV_RunClients (void) if (sv.frametime) { + sv_player = host_client->edict; + // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) if (SV_PlayerPhysicsQC) { diff --git a/todo b/todo index fcbb4a46..df45c3f5 100644 --- a/todo +++ b/todo @@ -4,6 +4,7 @@ -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 -- 2.39.2