From 94173a5fe04e87602d27bd1c6cce8715192cea4c Mon Sep 17 00:00:00 2001 From: divverent Date: Wed, 2 Jan 2013 08:27:19 +0000 Subject: [PATCH] server: ignore out of order prespawn/spawn/begin commands This fixes disconnection issues for clients joining during map change. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11870 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=6037bd95e06be7ae06198464b5871fb567077092 --- host.c | 2 +- host_cmd.c | 27 ++++++++++++++++++++++----- netconn.c | 6 +++--- server.h | 6 +++++- sv_main.c | 22 +++++++++++++--------- sv_phys.c | 6 +++--- sv_user.c | 4 ++-- 7 files changed, 49 insertions(+), 24 deletions(-) diff --git a/host.c b/host.c index 4b106a69..a8c8bf2e 100644 --- a/host.c +++ b/host.c @@ -709,7 +709,7 @@ void Host_Main(void) // Look for clients who have spawned playing = false; for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) - if(host_client->spawned) + if(host_client->begun) if(host_client->netconnection) playing = true; if(sv.time < 10) diff --git a/host_cmd.c b/host_cmd.c index eb02215f..6a56f78c 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -1198,7 +1198,7 @@ static void Host_Name_f (void) PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name); if (strcmp(host_client->old_name, host_client->name)) { - if (host_client->spawned) + if (host_client->begun) SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name); strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name)); // send notification to all clients @@ -1316,7 +1316,7 @@ static void Host_Playerskin_f (void) PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin); if (strcmp(host_client->old_skin, host_client->playerskin)) { - //if (host_client->spawned) + //if (host_client->begun) // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin); strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin)); /*// send notification to all clients @@ -1774,11 +1774,12 @@ Host_PreSpawn_f */ static void Host_PreSpawn_f (void) { - if (host_client->spawned) + if (host_client->prespawned) { - Con_Print("prespawn not valid -- already spawned\n"); + Con_Print("prespawn not valid -- already prespawned\n"); return; } + host_client->prespawned = true; if (host_client->netconnection) { @@ -1804,11 +1805,17 @@ static void Host_Spawn_f (void) client_t *client; int stats[MAX_CL_STATS]; + if (!host_client->prespawned) + { + Con_Print("Spawn not valid -- not yet prespawned\n"); + return; + } if (host_client->spawned) { Con_Print("Spawn not valid -- already spawned\n"); return; } + host_client->spawned = true; // reset name change timer again because they might want to change name // again in the first 5 seconds after connecting @@ -1936,7 +1943,17 @@ Host_Begin_f */ static void Host_Begin_f (void) { - host_client->spawned = true; + if (!host_client->spawned) + { + Con_Print("Begin not valid -- not yet spawned\n"); + return; + } + if (host_client->begun) + { + Con_Print("Begin not valid -- already begun\n"); + return; + } + host_client->begun = true; // LordHavoc: note: this code also exists in SV_DropClient if (sv.loadgame) diff --git a/netconn.c b/netconn.c index 395f6d33..80dd9a77 100755 --- a/netconn.c +++ b/netconn.c @@ -2950,7 +2950,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat return true; } } - if (client->spawned) + if (client->begun) { // client crashed and is coming back, // keep their stuff intact @@ -3213,7 +3213,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat // if client is already spawned, re-send the // serverinfo message as they'll need it to play - if (client->spawned) + if (client->begun) SV_SendServerinfo(client); return true; } @@ -3398,7 +3398,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat } if (host_client) { - if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->spawned ? net_messagetimeout.value : net_connecttimeout.value)) == 2) + if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->begun ? net_messagetimeout.value : net_connecttimeout.value)) == 2) { SV_ReadClientMessage(); return ret; diff --git a/server.h b/server.h index 761321d7..08881cab 100644 --- a/server.h +++ b/server.h @@ -191,8 +191,12 @@ typedef struct client_s qboolean active; /// false = don't do ClientDisconnect on drop qboolean clientconnectcalled; - /// false = don't send datagrams + /// false = don't allow spawn + qboolean prespawned; + /// false = don't allow begin qboolean spawned; + /// false = don't send datagrams + qboolean begun; /// 1 = send svc_serverinfo and advance to 2, 2 doesn't send, then advances to 0 (allowing unlimited sending) when prespawn is received int sendsignon; diff --git a/sv_main.c b/sv_main.c index 64a29138..755c51c6 100644 --- a/sv_main.c +++ b/sv_main.c @@ -1030,7 +1030,9 @@ void SV_SendServerinfo (client_t *client) MSG_WriteByte (&client->netconnection->message, svc_signonnum); MSG_WriteByte (&client->netconnection->message, 1); + client->prespawned = false; // need prespawn, spawn, etc client->spawned = false; // need prespawn, spawn, etc + client->begun = false; // need prespawn, spawn, etc client->sendsignon = 1; // send this message, and increment to 2, 2 will be set to 0 by the prespawn command // clear movement info until client enters the new level properly @@ -1094,7 +1096,9 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) strlcpy(client->name, "unconnected", sizeof(client->name)); strlcpy(client->old_name, "unconnected", sizeof(client->old_name)); + client->prespawned = false; client->spawned = false; + client->begun = false; client->edict = PRVM_EDICT_NUM(clientnum+1); if (client->netconnection) client->netconnection->message.allowoverflow = true; // we can catch it @@ -1127,7 +1131,7 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) if (client->netconnection) SV_SendServerinfo (client); else - client->spawned = true; + client->prespawned = client->spawned = client->begun = true; } @@ -2237,7 +2241,7 @@ void SV_FlushBroadcastMessages(void) return; for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) { - if (!client->spawned || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0]))) + if (!client->begun || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0]))) continue; SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize); client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize; @@ -2365,7 +2369,7 @@ static void SV_SendClientDatagram (client_t *client) msg.cursize = 0; msg.allowoverflow = false; - if (host_client->spawned) + if (host_client->begun) { // the player is in the game MSG_WriteByte (&msg, svc_time); @@ -2460,7 +2464,7 @@ static void SV_UpdateToReliableMessages (void) PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name); if (strcmp(host_client->old_name, host_client->name)) { - if (host_client->spawned) + if (host_client->begun) SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name); strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name)); // send notification to all clients @@ -2516,7 +2520,7 @@ static void SV_UpdateToReliableMessages (void) // frags host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags); if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) - if(!host_client->spawned && host_client->netconnection) + if(!host_client->begun && host_client->netconnection) host_client->frags = -666; if (host_client->old_frags != host_client->frags) { @@ -2529,7 +2533,7 @@ static void SV_UpdateToReliableMessages (void) } for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) - if (client->netconnection && (client->spawned || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet + if (client->netconnection && (client->begun || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); SZ_Clear (&sv.reliable_datagram); @@ -3436,7 +3440,7 @@ void SV_SpawnServer (const char *server) // and we need to set the ->edict pointers to point into the progs edicts for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) { - host_client->spawned = false; + host_client->begun = false; host_client->edict = PRVM_EDICT_NUM(i + 1); PRVM_ED_ClearEdict(prog, host_client->edict); } @@ -3500,7 +3504,7 @@ void SV_SpawnServer (const char *server) PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing"); prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing"); - host_client->spawned = true; + host_client->begun = true; } } @@ -3896,7 +3900,7 @@ static int SV_ThreadFunc(void *voiddata) playing = false; if (sv.active) for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) - if(host_client->spawned) + if(host_client->begun) if(host_client->netconnection) playing = true; if(sv.time < 10) diff --git a/sv_phys.c b/sv_phys.c index 4e7d2765..727c28d0 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -2984,7 +2984,7 @@ static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent) { prvm_prog_t *prog = SVVM_prog; // don't do physics on disconnected clients, FrikBot relies on this - if (!host_client->spawned) + if (!host_client->begun) return; // make sure the velocity is sane (not a NaN) @@ -3013,7 +3013,7 @@ static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent) { prvm_prog_t *prog = SVVM_prog; // don't do physics on disconnected clients, FrikBot relies on this - if (!host_client->spawned) + if (!host_client->begun) return; // make sure the velocity is sane (not a NaN) @@ -3050,7 +3050,7 @@ static void SV_Physics_ClientEntity(prvm_edict_t *ent) { prvm_prog_t *prog = SVVM_prog; // don't do physics on disconnected clients, FrikBot relies on this - if (!host_client->spawned) + if (!host_client->begun) { memset(&host_client->cmd, 0, sizeof(host_client->cmd)); return; diff --git a/sv_user.c b/sv_user.c index 83a0e86a..a65705f4 100644 --- a/sv_user.c +++ b/sv_user.c @@ -586,7 +586,7 @@ static void SV_ExecuteClientMoves(void) if (sv_numreadmoves < 1) return; // only start accepting input once the player is spawned - if (!host_client->spawned) + if (!host_client->begun) return; #if DEBUGMOVES Con_Printf("SV_ExecuteClientMoves: read %i moves at sv.time %f\n", sv_numreadmoves, (float)sv.time); @@ -950,7 +950,7 @@ clc_stringcmd_invalid: // if the client hasn't progressed through signons yet, // ignore any clc_ackframes we get (they're probably from the // previous level) - if (host_client->spawned && host_client->latestframenum < num) + if (host_client->begun && host_client->latestframenum < num) { int i; for (i = host_client->latestframenum + 1;i < num;i++) -- 2.39.2