summaryrefslogtreecommitdiff
path: root/src/server/sv_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/sv_client.c')
-rw-r--r--src/server/sv_client.c93
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)