diff options
Diffstat (limited to 'src/server/sv_client.c')
-rw-r--r-- | src/server/sv_client.c | 93 |
1 files changed, 86 insertions, 7 deletions
diff --git a/src/server/sv_client.c b/src/server/sv_client.c index f3a0494f..9c0f842d 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -167,6 +167,8 @@ void SV_DirectConnect( netadr_t from ) { if ( cl->state == CS_FREE ) { continue; } + if (cl->isPlaceholder) + continue; if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { @@ -250,6 +252,8 @@ void SV_DirectConnect( netadr_t from ) { if ( cl->state == CS_FREE ) { continue; } + if (cl->isPlaceholder) + continue; if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { @@ -333,7 +337,7 @@ gotnewcl: Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) ); // get the game a chance to reject this connection or modify the userinfo - denied = VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue ); // firstTime = qtrue + denied = VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue if ( denied ) { // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call char *str = VM_ExplicitArgPtr( gvm, denied ); @@ -373,6 +377,57 @@ gotnewcl: } } +int sv_install_placeholder_client(const char *const ui) +{ + for (int n = (sv_privateClients->integer > 0 && strcmp(Info_ValueForKey(ui, "password"), sv_privatePassword->string) + ? sv_privateClients->integer : 0); + n < sv_maxclients->integer; ++n) + { + client_t *cl = &svs.clients[n]; + if (cl->state != CS_FREE) + continue; + + memset(cl, 0, sizeof(*cl)); + + cl->state = CS_ACTIVE; + cl->isPlaceholder = qtrue; + + cl->gentity = SV_GentityNum(n); + cl->gentity->s.number = n; + + Q_strncpyz(cl->userinfo, ui, sizeof(cl->userinfo)); + Q_strncpyz(cl->name, Info_ValueForKey(ui, "name"), sizeof(cl->name)); + cl->ping = atoi(Info_ValueForKey(ui, "ping")); + + cl->gotCP = qtrue; + cl->pureAuthentic = qtrue; + + Cvar_Set(va("sv_clAltProto%i", n), "0"); + + int count = 0; + for (int i = 0; i < sv_maxclients->integer; ++i) + { + if (svs.clients[i].state >= CS_CONNECTED) + ++count; + } + if (count == 1 || count == sv_maxclients->integer) + SV_Heartbeat_f(); + + return n; + } + + return -1; +} + +void sv_set_client_view_entity(client_t *const c, client_t *const e) +{ + if (e == c) + c->view = NULL; + else + c->view = e; +} + + /* ===================== SV_FreeClient @@ -382,6 +437,9 @@ Destructor for data allocated in a client structure */ void SV_FreeClient(client_t *client) { + if (client->isPlaceholder) + return; + #ifdef USE_VOIP int index; @@ -416,13 +474,16 @@ void SV_DropClient( client_t *drop, const char *reason ) { return; // already dropped } - // see if we already have a challenge for this ip - challenge = &svs.challenges[0]; + if (!drop->isPlaceholder) + { + // see if we already have a challenge for this ip + challenge = &svs.challenges[0]; - for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { - if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { - Com_Memset(challenge, 0, sizeof(*challenge)); - break; + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { + if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { + Com_Memset(challenge, 0, sizeof(*challenge)); + break; + } } } @@ -444,6 +505,18 @@ void SV_DropClient( client_t *drop, const char *reason ) { Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); drop->state = CS_ZOMBIE; // become free in a few seconds + if (drop->isPlaceholder) + drop->state = CS_FREE; + + for (int i = 0; i < sv_maxclients->integer; ++i) + { + client_t *cl = &svs.clients[i]; + if (cl->state == CS_FREE) + continue; + + if (cl->view == drop) + cl->view = NULL; + } // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty @@ -886,6 +959,8 @@ int SV_SendQueuedMessages(void) { cl = &svs.clients[i]; + if (cl->isPlaceholder) + continue; if(cl->state) { nextFragT = SV_RateMsec(cl); @@ -921,6 +996,8 @@ int SV_SendDownloadMessages(void) { cl = &svs.clients[i]; + if (cl->isPlaceholder) + continue; if(cl->state && *cl->downloadName) { MSG_Init(&msg, msgBuffer, sizeof(msgBuffer)); @@ -1594,6 +1671,8 @@ void SV_UserVoip(client_t *cl, msg_t *msg, qboolean ignoreData) for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) { if (client->state != CS_ACTIVE) continue; // not in the game yet, don't send to this guy. + if (client->isPlaceholder) + continue; else if (i == sender) continue; // don't send voice packet back to original author. else if (!client->hasVoip) |