From 0706fdfa8e33548670e59234409eac2c51849631 Mon Sep 17 00:00:00 2001 From: Cloudwalk Date: Wed, 21 Jul 2021 21:31:30 -0400 Subject: [PATCH] protocol/dp8: Implement parting messages * Extended CL_Disconnect and SV_DropClient for this purpose. * Add a string parameter to svc_disconnect and clc_disconnect, which shall contain the parting message. --- cl_demo.c | 13 +++++------ cl_input.c | 5 +--- cl_main.c | 67 +++++++++++++++++++++++++++++++++++------------------ cl_parse.c | 6 ++--- client.h | 2 +- common.h | 2 +- csprogs.c | 16 +++---------- fs.c | 4 ++-- host.c | 2 +- host.h | 2 +- libcurl.c | 2 +- netconn.c | 7 ++---- server.h | 2 +- sv_ccmds.c | 10 ++++---- sv_main.c | 51 +++++++++++++++++++++++++++------------- sv_save.c | 2 +- sv_send.c | 2 +- sv_user.c | 10 ++++---- svvm_cmds.c | 2 +- 19 files changed, 118 insertions(+), 89 deletions(-) diff --git a/cl_demo.c b/cl_demo.c index eb4ab55e..4c826c0d 100644 --- a/cl_demo.c +++ b/cl_demo.c @@ -256,9 +256,8 @@ void CL_ReadDemoMessage(void) } if (cl_message.cursize > cl_message.maxsize) { - Con_Printf("Demo message (%i) > cl_message.maxsize (%i)", cl_message.cursize, cl_message.maxsize); + CL_Disconnect(false, "Demo message (%i) > cl_message.maxsize (%i)", cl_message.cursize, cl_message.maxsize); cl_message.cursize = 0; - CL_Disconnect(); return; } VectorCopy(cl.mviewangles[0], cl.mviewangles[1]); @@ -285,7 +284,7 @@ void CL_ReadDemoMessage(void) } else { - CL_Disconnect(); + CL_Disconnect(false, NULL); return; } } @@ -364,7 +363,7 @@ void CL_Record_f(cmd_state_t *cmd) } if (cls.state == ca_connected) - CL_Disconnect(); + CL_Disconnect(false, NULL); // write the forced cd track number, or -1 if (c == 4) @@ -422,7 +421,7 @@ void CL_PlayDemo(const char *demo) cls.demostarting = true; // disconnect from server - CL_Disconnect(); + CL_Disconnect(false, NULL); // update networking ports (this is mainly just needed at startup) NetConn_UpdateSockets(); @@ -680,7 +679,7 @@ static void CL_Demos_f(cmd_state_t *cmd) return; if (cls.demonum == -1) cls.demonum = 1; - CL_Disconnect(); + CL_Disconnect(false, NULL); CL_NextDemo(); } @@ -695,7 +694,7 @@ static void CL_Stopdemo_f(cmd_state_t *cmd) { if (!cls.demoplayback) return; - CL_Disconnect(); + CL_Disconnect(false, NULL); } // LadyHavoc: pausedemo command diff --git a/cl_input.c b/cl_input.c index ebc50867..7c5598ca 100644 --- a/cl_input.c +++ b/cl_input.c @@ -2167,10 +2167,7 @@ void CL_SendMove(void) in_impulse = 0; if (cls.netcon->message.overflowed) - { - Con_Print("CL_SendMove: lost server connection\n"); - CL_Disconnect(); - } + CL_Disconnect(true, "Lost connection to server"); } /* diff --git a/cl_main.c b/cl_main.c index 6d46bc77..e4d56733 100644 --- a/cl_main.c +++ b/cl_main.c @@ -360,11 +360,25 @@ Sends a disconnect message to the server This is also called on Host_Error, so it shouldn't cause any errors ===================== */ -void CL_Disconnect(void) +void CL_Disconnect(qbool kicked, const char *fmt, ... ) { + va_list argptr; + char reason[512]; + if (cls.state == ca_dedicated) return; + if(fmt) + { + va_start(argptr,fmt); + dpvsnprintf(reason,sizeof(reason),fmt,argptr); + va_end(argptr); + } + else + { + dpsnprintf(reason, sizeof(reason), "Disconnect by user"); + } + if (Sys_CheckParm("-profilegameonly")) Sys_AllowProfiling(false); @@ -395,32 +409,41 @@ void CL_Disconnect(void) else if (cls.netcon) { sizebuf_t buf; - unsigned char bufdata[8]; + unsigned char bufdata[520]; if (cls.demorecording) CL_Stop_f(cmd_local); - // send disconnect message 3 times to improve chances of server - // receiving it (but it still fails sometimes) - memset(&buf, 0, sizeof(buf)); - buf.data = bufdata; - buf.maxsize = sizeof(bufdata); - if (cls.protocol == PROTOCOL_QUAKEWORLD) - { - Con_DPrint("Sending drop command\n"); - MSG_WriteByte(&buf, qw_clc_stringcmd); - MSG_WriteString(&buf, "drop"); - } - else + if(!kicked) { - Con_DPrint("Sending clc_disconnect\n"); - MSG_WriteByte(&buf, clc_disconnect); + // send disconnect message 3 times to improve chances of server + // receiving it (but it still fails sometimes) + memset(&buf, 0, sizeof(buf)); + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + Con_DPrint("Sending drop command\n"); + MSG_WriteByte(&buf, qw_clc_stringcmd); + MSG_WriteString(&buf, "drop"); + } + else + { + Con_DPrint("Sending clc_disconnect\n"); + MSG_WriteByte(&buf, clc_disconnect); + if(cls.protocol == PROTOCOL_DARKPLACES8) + MSG_WriteString(&buf, reason); + } + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false); } - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false); - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false); - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false); + NetConn_Close(cls.netcon); cls.netcon = NULL; - Con_Printf("Disconnected\n"); + if(fmt) + Con_Printf("Disconnect: %s\n", reason); + else + Con_Printf("Disconnected\n"); } cls.state = ca_disconnected; cl.islocalgame = false; @@ -515,7 +538,7 @@ static void CL_Connect_f(cmd_state_t *cmd) void CL_Disconnect_f(cmd_state_t *cmd) { - CL_Disconnect(); + CL_Disconnect(false, Cmd_Argc(cmd) > 1 ? Cmd_Argv(cmd, 1) : NULL); } @@ -2909,7 +2932,7 @@ void CL_Shutdown (void) S_StopAllSounds(); // disconnect client from server if active - CL_Disconnect(); + CL_Disconnect(false, NULL); CL_Video_Shutdown(); diff --git a/cl_parse.c b/cl_parse.c index 7dfd3a95..5cbcb8b2 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -35,7 +35,7 @@ const char *svc_strings[128] = { "svc_bad", "svc_nop", - "svc_disconnect", + "svc_disconnect", // (DP8) [string] null terminated parting message "svc_updatestat", "svc_version", // [int] server version "svc_setview", // [short] entity number @@ -3531,7 +3531,7 @@ void CL_ParseServerMessage(void) if (cls.demonum != -1) CL_NextDemo(); else - CL_Disconnect(); + CL_Disconnect(true, NULL); break; case qw_svc_print: @@ -3911,7 +3911,7 @@ void CL_ParseServerMessage(void) if (cls.demonum != -1) CL_NextDemo(); else - CL_Disconnect(); + CL_Disconnect(true, cls.protocol == PROTOCOL_DARKPLACES8 ? MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)) : NULL); break; case svc_print: diff --git a/client.h b/client.h index 8e6d0f50..3e007c70 100644 --- a/client.h +++ b/client.h @@ -1223,7 +1223,7 @@ void CL_StartVideo(void); void CL_EstablishConnection(const char *host, int firstarg); -void CL_Disconnect (void); +void CL_Disconnect (qbool kicked, const char *reason, ... ); void CL_Disconnect_f(cmd_state_t *cmd); void CL_UpdateRenderEntity(entity_render_t *ent); diff --git a/common.h b/common.h index 95a12ab3..169d989b 100644 --- a/common.h +++ b/common.h @@ -131,7 +131,7 @@ void StoreLittleShort (unsigned char *buffer, unsigned short i); typedef enum protocolversion_e { PROTOCOL_UNKNOWN, - PROTOCOL_DARKPLACES8, ///< wip + PROTOCOL_DARKPLACES8, ///< added parting messages. WIP PROTOCOL_DARKPLACES7, ///< added QuakeWorld-style movement protocol to allow more consistent prediction PROTOCOL_DARKPLACES6, ///< various changes PROTOCOL_DARKPLACES5, ///< uses EntityFrame5 entity snapshot encoder/decoder which is based on a Tribes networking article at http://www.garagegames.com/articles/networking1/ diff --git a/csprogs.c b/csprogs.c index 9800fe0a..47ac1ef2 100644 --- a/csprogs.c +++ b/csprogs.c @@ -1043,8 +1043,7 @@ void CL_VM_Init (void) else { Mem_Free(csprogsdata); - Con_Printf(CON_ERROR "Your %s is not the same version as the server (CRC is %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); - CL_Disconnect(); + CL_Disconnect(false, "Your %s is not the same version as the server (CRC is %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); return; } } @@ -1052,13 +1051,7 @@ void CL_VM_Init (void) else { if (requiredcrc >= 0) - { - if (cls.demoplayback) - Con_Printf(CON_ERROR "CL_VM_Init: demo requires CSQC, but \"%s\" wasn't found\n", csqc_progname.string); - else - Con_Printf(CON_ERROR "CL_VM_Init: server requires CSQC, but \"%s\" wasn't found\n", csqc_progname.string); - CL_Disconnect(); - } + CL_Disconnect(false, CON_ERROR "CL_VM_Init: %s requires CSQC, but \"%s\" wasn't found\n", cls.demoplayback ? "demo" : "server", csqc_progname.string); return; } @@ -1094,11 +1087,8 @@ void CL_VM_Init (void) if (!prog->loaded) { - Host_Error("CSQC %s failed to load\n", csprogsfn); - if(!sv.active) - CL_Disconnect(); Mem_Free(csprogsdata); - return; + Host_Error("CSQC %s failed to load\n", csprogsfn); } if(cls.demorecording) diff --git a/fs.c b/fs.c index f5e67b36..97259f72 100644 --- a/fs.c +++ b/fs.c @@ -1577,7 +1577,7 @@ qbool FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qbool compl if (cls.demoplayback) { - CL_Disconnect(); + CL_Disconnect(false, NULL); cls.demonum = 0; } @@ -1628,7 +1628,7 @@ static void FS_GameDir_f(cmd_state_t *cmd) } // halt demo playback to close the file - CL_Disconnect(); + CL_Disconnect(false, NULL); FS_ChangeGameDirs(numgamedirs, gamedirs, true, true); } diff --git a/host.c b/host.c index e196fe79..21650a24 100644 --- a/host.c +++ b/host.c @@ -134,7 +134,7 @@ void Host_Error (const char *error, ...) if (cls.state == ca_dedicated) Sys_Error ("Host_Error: %s",hosterrorstring2); // dedicated servers exit - CL_Disconnect (); + CL_Disconnect (false, NULL); cls.demonum = -1; hosterror = false; diff --git a/host.h b/host.h index 4521f72b..26465423 100644 --- a/host.h +++ b/host.h @@ -31,7 +31,7 @@ typedef struct host_static_s struct { void (*ConnectLocal)(void); - void (*Disconnect)(void); + void (*Disconnect)(qbool, const char *, ... ); void (*ToggleMenu)(void); qbool (*CL_Intermission)(void); // Quake compatibility void (*CL_SendCvar)(struct cmd_state_s *); diff --git a/libcurl.c b/libcurl.c index c29a1894..f71dfaaf 100644 --- a/libcurl.c +++ b/libcurl.c @@ -1494,7 +1494,7 @@ static void Curl_Curl_f(cmd_state_t *cmd) dpsnprintf(donecommand, sizeof(donecommand), "connect %s", cls.netcon->address); Curl_CommandWhenDone(donecommand); noclear = true; - CL_Disconnect(); + CL_Disconnect(false, NULL); noclear = false; Curl_CheckCommandWhenDone(); } diff --git a/netconn.c b/netconn.c index 1ec19fcd..ac481ca6 100755 --- a/netconn.c +++ b/netconn.c @@ -1529,7 +1529,7 @@ static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_ #endif // Disconnect from the current server or stop demo playback if(cls.state == ca_connected || cls.demoplayback) - CL_Disconnect(); + CL_Disconnect(false, NULL); // allocate a net connection to keep track of things cls.netcon = NetConn_Open(mysocket, peeraddress); crypto = &cls.netcon->crypto; @@ -2488,10 +2488,7 @@ void NetConn_ClientFrame(void) NetConn_QueryQueueFrame(); #endif if (cls.netcon && host.realtime > cls.netcon->timeout && !sv.active) - { - Con_Print("Connection timed out\n"); - CL_Disconnect(); - } + CL_Disconnect(true, "Connection timed out"); } static void NetConn_BuildChallengeString(char *buffer, int bufferlength) diff --git a/server.h b/server.h index 07639e4b..02d3786b 100644 --- a/server.h +++ b/server.h @@ -515,7 +515,7 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation, float speed); void SV_ConnectClient (int clientnum, netconn_t *netconnection); -void SV_DropClient (qbool crash); +void SV_DropClient (qbool leaving, const char *reason, ... ); void SV_ClientCommands(const char *fmt, ...) DP_FUNC_PRINTF(1); diff --git a/sv_ccmds.c b/sv_ccmds.c index 639a3253..036f4c63 100644 --- a/sv_ccmds.c +++ b/sv_ccmds.c @@ -62,7 +62,7 @@ static void SV_Map_f(cmd_state_t *cmd) Cvar_Set(&cvars_all, "warpmark", ""); if(host.hook.Disconnect) - host.hook.Disconnect(); + host.hook.Disconnect(false, NULL); SV_Shutdown(); @@ -1026,6 +1026,7 @@ static void SV_Kick_f(cmd_state_t *cmd) { const char *who; const char *message = NULL; + char reason[512]; client_t *save; int i; qbool byNumber = false; @@ -1084,10 +1085,11 @@ static void SV_Kick_f(cmd_state_t *cmd) message++; } if (message) - SV_ClientPrintf("Kicked by %s: %s\n", who, message); + SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s: %s", who, message)); // kicked + //SV_ClientPrintf("Kicked by %s: %s\n", who, message); else - SV_ClientPrintf("Kicked by %s\n", who); - SV_DropClient (false); // kicked + //SV_ClientPrintf("Kicked by %s\n", who); + SV_DropClient (false, va(reason, sizeof(reason), "Kicked by %s", who)); // kicked } host_client = save; diff --git a/sv_main.c b/sv_main.c index 956b22ac..777d3e57 100644 --- a/sv_main.c +++ b/sv_main.c @@ -984,14 +984,31 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) SV_DropClient Called when the player is getting totally kicked off the host -if (crash = true), don't bother sending signofs +if (leaving = true), don't bother sending signofs ===================== */ -void SV_DropClient(qbool crash) +void SV_DropClient(qbool leaving, const char *fmt, ... ) { prvm_prog_t *prog = SVVM_prog; int i; - Con_Printf("Client \"%s\" dropped\n", host_client->name); + + va_list argptr; + char reason[512] = ""; + + Con_Printf("Client \"%s\" dropped", host_client->name); + + if(fmt) + { + va_start(argptr, fmt); + dpvsnprintf(reason, sizeof(reason), fmt, argptr); + va_end(argptr); + + Con_Printf(" (%s)\n", reason); + } + else + { + Con_Printf(" \n"); + } SV_StopDemoRecording(host_client); @@ -1001,15 +1018,22 @@ void SV_DropClient(qbool crash) if (host_client->netconnection) { // tell the client to be gone - if (!crash) + if (!leaving) { // LadyHavoc: no opportunity for resending, so use unreliable 3 times - unsigned char bufdata[8]; + unsigned char bufdata[520]; // Disconnect reason string can be 512 characters sizebuf_t buf; memset(&buf, 0, sizeof(buf)); buf.data = bufdata; buf.maxsize = sizeof(bufdata); MSG_WriteByte(&buf, svc_disconnect); + if(fmt) + { + if(sv.protocol == PROTOCOL_DARKPLACES8) + MSG_WriteString(&buf, reason); + else + SV_ClientPrintf("%s\n", reason); + } NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false); NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false); NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false); @@ -1037,6 +1061,10 @@ void SV_DropClient(qbool crash) NetConn_Close(host_client->netconnection); host_client->netconnection = NULL; } + if(fmt) + SV_BroadcastPrintf("\003^3%s left the game (%s)\n", host_client->name, reason); + else + SV_BroadcastPrintf("\003^3%s left the game\n", host_client->name); // if a download is active, close it if (host_client->download_file) @@ -2083,7 +2111,7 @@ void SV_Shutdown(void) } for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) if (host_client->active) - SV_DropClient(false); // server shutdown + SV_DropClient(false, "Server shutting down"); // server shutdown NetConn_CloseServerPorts(); @@ -2446,17 +2474,8 @@ static void SV_CheckTimeouts(void) // never timeout loopback connections for (i = (host_isclient.integer ? 1 : 0), host_client = &svs.clients[i]; i < svs.maxclients; i++, host_client++) - { if (host_client->netconnection && host.realtime > host_client->netconnection->timeout) - { - if (host_client->begun) - SV_BroadcastPrintf("Client \"%s\" connection timed out\n", host_client->name); - else - Con_Printf("Client \"%s\" connection timed out\n", host_client->name); - - SV_DropClient(false); - } - } + SV_DropClient(false, "Timed out"); } /* diff --git a/sv_save.c b/sv_save.c index 926c90c9..814e2db1 100644 --- a/sv_save.c +++ b/sv_save.c @@ -272,7 +272,7 @@ void SV_Loadgame_f(cmd_state_t *cmd) // stop playing demos if (cls.demoplayback) - CL_Disconnect (); + CL_Disconnect (false, NULL); #ifdef CONFIG_MENU // remove menu diff --git a/sv_send.c b/sv_send.c index c42cbc69..a1ee1050 100644 --- a/sv_send.c +++ b/sv_send.c @@ -1712,7 +1712,7 @@ void SV_SendClientMessages(void) if (host_client->netconnection->message.overflowed) { - SV_DropClient (true); // if the message couldn't send, kick off + SV_DropClient (true, "Buffer overflow in net message"); // if the message couldn't send, kick off continue; } diff --git a/sv_user.c b/sv_user.c index ff1bdbc3..6a621bac 100644 --- a/sv_user.c +++ b/sv_user.c @@ -999,14 +999,14 @@ void SV_ReadClientMessage(void) if (!host_client->active) { // a command caused an error - SV_DropClient (false); + SV_DropClient (false, "Connection closing"); return; } if (sv_message.badread) { Con_Print("SV_ReadClientMessage: badread\n"); - SV_DropClient (false); + SV_DropClient (false, "An internal server error occurred"); return; } @@ -1025,7 +1025,7 @@ void SV_ReadClientMessage(void) Con_Printf("SV_ReadClientMessage: unknown command char %i (at offset 0x%x)\n", netcmd, sv_message.readcount); if (developer_networking.integer) Com_HexDumpToConsole(sv_message.data, sv_message.cursize); - SV_DropClient (false); + SV_DropClient (false, "Unknown message sent to the server"); return; case clc_nop: @@ -1076,7 +1076,9 @@ clc_stringcmd_invalid: break; case clc_disconnect: - SV_DropClient (false); // client wants to disconnect + SV_DropClient (true, sv.protocol == PROTOCOL_DARKPLACES8 + ? MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)) + : "Disconnect by user"); // client wants to disconnect return; case clc_move: diff --git a/svvm_cmds.c b/svvm_cmds.c index 249e186d..672ff70d 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -2657,7 +2657,7 @@ static void VM_SV_dropclient(prvm_prog_t *prog) } oldhostclient = host_client; host_client = svs.clients + clientnum; - SV_DropClient(false); + SV_DropClient(false, "Client dropped"); host_client = oldhostclient; } -- 2.39.2