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));
+ }
+}
+
//=============================================================================
/*
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);
if (length < 8)
return 0;
+ // TODO: add netgraph stuff rather than just packetloss counting...
+
if (protocol == PROTOCOL_QUAKEWORLD)
{
int sequence, sequence_ack;
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
{
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;
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)
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)
{
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;
}
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);
// 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 ())
{