From 3762a6633d1179e5dd4e9b0ab4dd37cca9920354 Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 8 Jul 2006 09:24:58 +0000 Subject: [PATCH] added ping and packet loss display to scoreboard, and pings/pingplreport commands to make it work without changing protocol and without breaking demo compatibility either, this can work on any server that supports the pings command and replies with pingplreport revised scoreboard layout and added column titles above it git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6504 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_input.c | 7 +++--- host_cmd.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ netconn.c | 34 +++++++++++++++++++-------- netconn.h | 4 ++++ sbar.c | 42 +++++++++++++-------------------- sv_user.c | 1 + 6 files changed, 118 insertions(+), 38 deletions(-) diff --git a/cl_input.c b/cl_input.c index ae0ba2f6..2824743c 100644 --- a/cl_input.c +++ b/cl_input.c @@ -1187,7 +1187,7 @@ CL_SendMove extern cvar_t cl_netinputpacketspersecond; void CL_SendMove(void) { - int i; + int i, j, packetloss; int bits; int impulse; sizebuf_t buf; @@ -1334,8 +1334,9 @@ void CL_SendMove(void) checksumindex = buf.cursize; MSG_WriteByte(&buf, 0); // packet loss percentage - // FIXME: netgraph stuff - MSG_WriteByte(&buf, 0); + for (j = 0, packetloss = 0;j < 100;j++) + packetloss += cls.netcon->packetlost[j]; + MSG_WriteByte(&buf, packetloss); // write most recent 3 moves i = (cls.netcon->qw.outgoing_sequence-2) & QW_UPDATE_MASK; cmd = &cl.qw_moves[i]; diff --git a/host_cmd.c b/host_cmd.c index ebfd6d49..8e6930d3 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -2324,6 +2324,71 @@ void Host_Packet_f (void) // credit: taken from QuakeWorld NetConn_Write(mysocket, send, out - send, &address); } +/* +==================== +Host_Pings_f + +Send back ping and packet loss update for all current players to this player +==================== +*/ +void Host_Pings_f (void) +{ + int i, j, ping, packetloss; + char temp[128]; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + if (!host_client->netconnection) + return; + + if (sv.protocol != PROTOCOL_QUAKEWORLD) + { + MSG_WriteByte(&host_client->netconnection->message, svc_stufftext); + MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport"); + } + for (i = 0;i < svs.maxclients;i++) + { + packetloss = 0; + if (svs.clients[i].netconnection) + for (j = 0;j < 100;j++) + packetloss += svs.clients[i].netconnection->packetlost[j]; + ping = (int)floor(svs.clients[i].ping*1000+0.5); + ping = bound(0, ping, 9999); + if (sv.protocol == PROTOCOL_QUAKEWORLD) + { + // send qw_svc_updateping and qw_svc_updatepl messages + MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping); + MSG_WriteShort(&host_client->netconnection->message, ping); + MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl); + MSG_WriteByte(&host_client->netconnection->message, packetloss); + } + else + { + // write the string into the packet as multiple unterminated strings to avoid needing a local buffer + dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss); + MSG_WriteUnterminatedString(&host_client->netconnection->message, temp); + } + } + if (sv.protocol != PROTOCOL_QUAKEWORLD) + MSG_WriteString(&host_client->netconnection->message, "\n"); +} + +void Host_PingPLReport_f(void) +{ + int i; + int l = Cmd_Argc(); + if (l > cl.maxclients) + l = cl.maxclients; + for (i = 0;i < l;i++) + { + cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2)); + cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1)); + } +} + //============================================================================= /* @@ -2415,6 +2480,9 @@ void Host_InitCommands (void) Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color"); Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color"); + Cmd_AddCommand ("pings", Host_Pings_f, "command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)"); + Cmd_AddCommand ("pingplreport", Host_PingPLReport_f, "command sent by server containing client ping and packet loss values for scoreboard, triggered by pings command from client (not used by QW servers)"); + Cvar_RegisterVariable (&team); Cvar_RegisterVariable (&skin); Cvar_RegisterVariable (&noaim); diff --git a/netconn.c b/netconn.c index a37505ca..79448a9c 100755 --- a/netconn.c +++ b/netconn.c @@ -846,6 +846,8 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len if (length < 8) return 0; + // TODO: add netgraph stuff rather than just packetloss counting... + if (protocol == PROTOCOL_QUAKEWORLD) { int sequence, sequence_ack; @@ -876,15 +878,22 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len sequence_ack &= ~(1<<31); if (sequence <= conn->qw.incoming_sequence) { - Con_DPrint("Got a stale datagram\n"); + //Con_DPrint("Got a stale datagram\n"); return 0; } count = sequence - (conn->qw.incoming_sequence + 1); if (count > 0) { droppedDatagrams += count; - Con_DPrintf("Dropped %u datagram(s)\n", count); + //Con_DPrintf("Dropped %u datagram(s)\n", count); + while (count--) + { + conn->packetlost[conn->packetlostcounter] = true; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + } } + conn->packetlost[conn->packetlostcounter] = false; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; if (reliable_ack == conn->qw.reliable_sequence) { // received, now we will be able to send another reliable message @@ -931,8 +940,15 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len { count = sequence - conn->nq.unreliableReceiveSequence; droppedDatagrams += count; - Con_DPrintf("Dropped %u datagram(s)\n", count); + //Con_DPrintf("Dropped %u datagram(s)\n", count); + while (count--) + { + conn->packetlost[conn->packetlostcounter] = true; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + } } + conn->packetlost[conn->packetlostcounter] = false; + conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; conn->nq.unreliableReceiveSequence = sequence + 1; conn->lastMessageTime = realtime; conn->timeout = realtime + net_messagetimeout.value; @@ -945,8 +961,8 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len return 2; } } - else - Con_DPrint("Got a stale datagram\n"); + //else + // Con_DPrint("Got a stale datagram\n"); return 1; } else if (flags & NETFLAG_ACK) @@ -999,11 +1015,11 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len else conn->sendMessageLength = 0; } - else - Con_DPrint("Duplicate ACK received\n"); + //else + // Con_DPrint("Duplicate ACK received\n"); } - else - Con_DPrint("Stale ACK received\n"); + //else + // Con_DPrint("Stale ACK received\n"); return 1; } else if (flags & NETFLAG_DATA) diff --git a/netconn.h b/netconn.h index ddbce415..bbd1b88e 100755 --- a/netconn.h +++ b/netconn.h @@ -185,6 +185,10 @@ typedef struct netconn_s } qw; + // this tracks which of the last 100 received packet sequence numbers were lost + int packetlostcounter; + unsigned char packetlost[100]; + char address[128]; } netconn_t; diff --git a/sbar.c b/sbar.c index 95a79f36..01df2be4 100644 --- a/sbar.c +++ b/sbar.c @@ -1370,33 +1370,19 @@ float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y) { int minutes; unsigned char *c; - if (cls.protocol == PROTOCOL_QUAKEWORLD) - { - minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : realtime - s->qw_entertime) / 60.0); - if (s->qw_spectator) - DrawQ_ColoredString(x, y, va("%c%4i %2i %4i spec %-4s %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, cl.qw_teamplay ? s->qw_team : "", s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL ); - else - { - // draw colors behind score - c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8]; - DrawQ_Pic(x + 14*8, y+1, NULL, 32, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0); - c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8]; - DrawQ_Pic(x + 14*8, y+4, NULL, 32, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0); - // print the text - //DrawQ_String(x, y, va("%c%4i %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); - DrawQ_ColoredString(x, y, va("%c%4i %2i %4i %4i %-4s %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL ); - } - } + minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : realtime - s->qw_entertime) / 60.0); + if (s->qw_spectator) + DrawQ_ColoredString(x, y, va("%4i %3i %4i spect %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL ); else { // draw colors behind score c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8]; - DrawQ_Pic(x + 1*8, y+1, NULL, 32, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0); + DrawQ_Pic(x + 14*8, y+1, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0); c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8]; - DrawQ_Pic(x + 1*8, y+4, NULL, 32, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0); + DrawQ_Pic(x + 14*8, y+4, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0); // print the text //DrawQ_String(x, y, va("%c%4i %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); - DrawQ_ColoredString(x, y, va("%c%4i %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL ); + DrawQ_ColoredString(x, y, va("%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL ); } return 8; } @@ -1406,14 +1392,19 @@ void Sbar_DeathmatchOverlay (void) int i, x, y; // request new ping times every two second - if (cl.last_ping_request < realtime - 2) + if (cl.last_ping_request < realtime - 2 && cls.netcon) { cl.last_ping_request = realtime; - if (cls.protocol == PROTOCOL_QUAKEWORLD && cls.netcon) + if (cls.protocol == PROTOCOL_QUAKEWORLD) { MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); MSG_WriteString(&cls.netcon->message, "pings"); } + else + { + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "pings"); + } } DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); @@ -1421,11 +1412,10 @@ void Sbar_DeathmatchOverlay (void) // scores Sbar_SortFrags (); // draw the text - if (cls.protocol == PROTOCOL_QUAKEWORLD) - x = (vid_conwidth.integer - (6 + 17 + 15) * 8) / 2; - else - x = (vid_conwidth.integer - (6 + 15) * 8) / 2; + x = (vid_conwidth.integer - (6 + 18 + 15) * 8) / 2; y = 40; + DrawQ_ColoredString(x, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL ); + y += 8; if (Sbar_IsTeammatch ()) { diff --git a/sv_user.c b/sv_user.c index 9ef6b380..e8998013 100644 --- a/sv_user.c +++ b/sv_user.c @@ -706,6 +706,7 @@ void SV_ReadClientMessage(void) || strncasecmp(s, "pause", 5) == 0 || strncasecmp(s, "kick", 4) == 0 || strncasecmp(s, "ping", 4) == 0 + || strncasecmp(s, "pings", 5) == 0 || strncasecmp(s, "ban", 3) == 0 || strncasecmp(s, "pmodel", 6) == 0 || strncasecmp(s, "rate", 4) == 0 -- 2.39.2