* 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.
}
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]);
}
else
{
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
return;
}
}
}
if (cls.state == ca_connected)
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
// write the forced cd track number, or -1
if (c == 4)
cls.demostarting = true;
// disconnect from server
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
// update networking ports (this is mainly just needed at startup)
NetConn_UpdateSockets();
return;
if (cls.demonum == -1)
cls.demonum = 1;
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
CL_NextDemo();
}
{
if (!cls.demoplayback)
return;
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
}
// LadyHavoc: pausedemo command
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");
}
/*
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);
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;
void CL_Disconnect_f(cmd_state_t *cmd)
{
- CL_Disconnect();
+ CL_Disconnect(false, Cmd_Argc(cmd) > 1 ? Cmd_Argv(cmd, 1) : NULL);
}
S_StopAllSounds();
// disconnect client from server if active
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
CL_Video_Shutdown();
{
"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
if (cls.demonum != -1)
CL_NextDemo();
else
- CL_Disconnect();
+ CL_Disconnect(true, NULL);
break;
case qw_svc_print:
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:
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);
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/
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;
}
}
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;
}
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)
if (cls.demoplayback)
{
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
cls.demonum = 0;
}
}
// halt demo playback to close the file
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
FS_ChangeGameDirs(numgamedirs, gamedirs, true, true);
}
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;
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 *);
dpsnprintf(donecommand, sizeof(donecommand), "connect %s", cls.netcon->address);
Curl_CommandWhenDone(donecommand);
noclear = true;
- CL_Disconnect();
+ CL_Disconnect(false, NULL);
noclear = false;
Curl_CheckCommandWhenDone();
}
#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;
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)
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);
Cvar_Set(&cvars_all, "warpmark", "");
if(host.hook.Disconnect)
- host.hook.Disconnect();
+ host.hook.Disconnect(false, NULL);
SV_Shutdown();
{
const char *who;
const char *message = NULL;
+ char reason[512];
client_t *save;
int i;
qbool byNumber = false;
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;
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);
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);
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)
}
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();
// 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");
}
/*
// stop playing demos
if (cls.demoplayback)
- CL_Disconnect ();
+ CL_Disconnect (false, NULL);
#ifdef CONFIG_MENU
// remove menu
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;
}
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;
}
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:
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:
}
oldhostclient = host_client;
host_client = svs.clients + clientnum;
- SV_DropClient(false);
+ SV_DropClient(false, "Client dropped");
host_client = oldhostclient;
}