From f6a18e05a6fb46a808a2342780df2cb89b9ec39d Mon Sep 17 00:00:00 2001 From: zico Date: Tue, 24 Jun 2014 14:49:18 +0200 Subject: [PATCH] Reworked packet loss prevention system to send and receive protected packets in correct order --- common/main/multi.h | 2 +- common/main/net_udp.h | 29 +++--- similar/main/net_udp.cpp | 219 ++++++++++++++++++++++----------------- 3 files changed, 141 insertions(+), 109 deletions(-) diff --git a/common/main/multi.h b/common/main/multi.h index e6f46c61e..435821843 100644 --- a/common/main/multi.h +++ b/common/main/multi.h @@ -69,7 +69,7 @@ extern int multi_protocol; // set and determinate used protocol #define MULTI_PROTO_UDP 1 // UDP protocol // What version of the multiplayer protocol is this? Increment each time something drastic changes in Multiplayer without the version number changes. Reset to 0 each time the version of the game changes -#define MULTI_PROTO_VERSION 13 +#define MULTI_PROTO_VERSION 14 // PROTOCOL VARIABLES AND DEFINES - END // limits for Packets (i.e. positional updates) per sec diff --git a/common/main/net_udp.h b/common/main/net_udp.h index 6c1df1499..1f52e9db9 100644 --- a/common/main/net_udp.h +++ b/common/main/net_udp.h @@ -53,7 +53,10 @@ void net_udp_send_netgame_update(); #define UDP_NETGAMES_PPAGE 12 // Netgames on one page of Netlist #define UDP_NETGAMES_PAGES 75 // Pages available on Netlist (UDP_MAX_NETGAMES/UDP_NETGAMES_PPAGE) #define UDP_TIMEOUT (5*F1_0) // 5 seconds disconnect timeout -#define UDP_MDATA_STOR_QUEUE_SIZE 500 // Store up to 500 MDATA packets +#define UDP_MDATA_STOR_QUEUE_SIZE 1024 // Store up to 1024 MDATA packets +#define UDP_MDATA_STOR_MIN_FREE_2JOIN 384 // have at least this many free packet slots before we let someone join the game +#define UDP_MDATA_PKT_NUM_MIN 1 // start from pkt_num 1 (0 is used to initialize the trace list) +#define UDP_MDATA_PKT_NUM_MAX (UDP_MDATA_STOR_QUEUE_SIZE*100) // the max value for pkt_num. roll over when we go any higher. this should be smaller than INT_MAX // UDP-Packet identificators (ubyte) and their (max. sizes). #define UPID_VERSION_DENY 1 // Netgame join or info has been denied due to version difference. @@ -144,21 +147,23 @@ struct UDP_mdata_info // structure to store MDATA to maybe resend struct UDP_mdata_store { - int used; - fix64 pkt_initial_timestamp; // initial timestamp to see if packet is outdated - fix64 pkt_timestamp[MAX_PLAYERS]; // Packet timestamp - int pkt_num; // Packet number - ubyte Player_num; // sender of this packet - ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected - ubyte data[UPID_MDATA_BUF_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose + sbyte used; + fix64 pkt_initial_timestamp; // initial timestamp to see if packet is outdated + fix64 pkt_timestamp[MAX_PLAYERS]; // Packet timestamp + uint32_t pkt_num[MAX_PLAYERS]; // Packet number + ubyte Player_num; // sender of this packet + ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected + ubyte data[UPID_MDATA_BUF_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose ushort data_size; } __pack__; -// structure to keep track of MDATA packets we've already got -struct UDP_mdata_recv : public prohibit_void_ptr +// structure to keep track of MDATA packets we already got, which we expect from another player and the pkt_num for the next packet we want to send to another player +struct UDP_mdata_check : public prohibit_void_ptr { - int pkt_num[UDP_MDATA_STOR_QUEUE_SIZE]; - int cur_slot; // index we can use for a new pkt_num + uint32_t pkt_num[UDP_MDATA_STOR_QUEUE_SIZE]; // all those we got just recently, so we can ignore them if we get them again + int cur_slot; // index we can use for a new pkt_num + uint32_t pkt_num_torecv; // the next pkt_num we await for this player + uint32_t pkt_num_tosend; // the next pkt_num we want to send to another player }; #endif diff --git a/similar/main/net_udp.cpp b/similar/main/net_udp.cpp index 45fd7017a..c6569a1e9 100644 --- a/similar/main/net_udp.cpp +++ b/similar/main/net_udp.cpp @@ -87,7 +87,7 @@ static void net_udp_timeout_check(fix64 time); static int net_udp_get_new_player_num (UDP_sequence_packet *their); static void net_udp_noloss_got_ack(ubyte *data, int data_len); static void net_udp_noloss_init_mdata_queue(void); -static void net_udp_noloss_clear_mdata_got(ubyte player_num); +static void net_udp_noloss_clear_mdata_trace(ubyte player_num); static void net_udp_noloss_process_queue(fix64 time); static void net_udp_send_extras (); static void net_udp_broadcast_game_info(ubyte info_upid); @@ -99,8 +99,9 @@ static int net_udp_start_game(void); int UDP_num_sendto = 0, UDP_len_sendto = 0, UDP_num_recvfrom = 0, UDP_len_recvfrom = 0; UDP_mdata_info UDP_MData; UDP_sequence_packet UDP_Seq; +int UDP_mdata_queue_highest = 0; UDP_mdata_store UDP_mdata_queue[UDP_MDATA_STOR_QUEUE_SIZE]; -UDP_mdata_recv UDP_mdata_got[MAX_PLAYERS]; +UDP_mdata_check UDP_mdata_trace[MAX_PLAYERS]; UDP_sequence_packet UDP_sync_player; // For rejoin object syncing UDP_netgame_info_lite Active_udp_games[UDP_MAX_NETGAMES]; int num_active_udp_games = 0; @@ -157,7 +158,7 @@ static void udp_traffic_stat() if (timer_query() >= last_traf_time + F1_0) { last_traf_time = timer_query(); - con_printf(CON_VERBOSE, "P#%i TRAFFIC - OUT: %fKB/s %iPPS IN: %fKB/s %iPPS",Player_num, (float)UDP_len_sendto/1024, UDP_num_sendto, (float)UDP_len_recvfrom/1024, UDP_num_recvfrom); + con_printf(CON_DEBUG, "P#%i TRAFFIC - OUT: %fKB/s %iPPS IN: %fKB/s %iPPS",Player_num, (float)UDP_len_sendto/1024, UDP_num_sendto, (float)UDP_len_recvfrom/1024, UDP_num_recvfrom); UDP_num_sendto = UDP_len_sendto = UDP_num_recvfrom = UDP_len_recvfrom = 0; } } @@ -1237,7 +1238,7 @@ void net_udp_disconnect_player(int playernum) if (VerifyPlayerJoined==playernum) VerifyPlayerJoined=-1; - net_udp_noloss_clear_mdata_got(playernum); + net_udp_noloss_clear_mdata_trace(playernum); } void @@ -1297,7 +1298,7 @@ static net_udp_new_player(UDP_sequence_packet *their) multi_sort_kill_list(); #endif - net_udp_noloss_clear_mdata_got(pnum); + net_udp_noloss_clear_mdata_trace(pnum); } static void net_udp_welcome_player(UDP_sequence_packet *their) @@ -1325,6 +1326,11 @@ static void net_udp_welcome_player(UDP_sequence_packet *their) return; } + // Joining a running game will need quite a few packets on the mdata-queue, so let players only join if we have enough space. + if (Netgame.PacketLossPrevention) + if ((UDP_MDATA_STOR_QUEUE_SIZE - UDP_mdata_queue_highest) < UDP_MDATA_STOR_MIN_FREE_2JOIN) + return; + if (their->player.connected != Current_level_num) { net_udp_dump_player(their->player.protocol.udp.addr, DUMP_LEVEL); @@ -1430,7 +1436,7 @@ static void net_udp_welcome_player(UDP_sequence_packet *their) multi_send_score(); - net_udp_noloss_clear_mdata_got(player_num); + net_udp_noloss_clear_mdata_trace(player_num); } Players[player_num].KillGoalCount=0; @@ -4266,13 +4272,14 @@ void net_udp_do_frame(int force, int listen) } /* CODE FOR PACKET LOSS PREVENTION - START */ +/* This code tries to make sure that packets with opcode UPID_MDATA_PNEEDACK aren't lost and sent and received in order. */ /* * Adds a packet to our queue. Should be called when an IMPORTANT mdata packet is created. * player_ack is an array which should contain 0 for each player that needs to send an ACK signal. */ -static void net_udp_noloss_add_queue_pkt(uint32_t pkt_num, fix64 time, ubyte *data, ushort data_size, ubyte pnum, ubyte player_ack[MAX_PLAYERS]) +static void net_udp_noloss_add_queue_pkt(fix64 time, ubyte *data, ushort data_size, ubyte pnum, ubyte player_ack[MAX_PLAYERS]) { - int i, found = 0; + int i; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; @@ -4280,30 +4287,19 @@ static void net_udp_noloss_add_queue_pkt(uint32_t pkt_num, fix64 time, ubyte *da if (!Netgame.PacketLossPrevention) return; - for (i = 0; i < UDP_MDATA_STOR_QUEUE_SIZE; i++) // look for unused or oldest slot - { - if (UDP_mdata_queue[i].used) - { - if (UDP_mdata_queue[i].pkt_initial_timestamp > UDP_mdata_queue[found].pkt_initial_timestamp) - found = i; - } - else - { - found = i; - break; - } - } - - if (UDP_mdata_queue[found].used) // seems the slot we found is used (list is full) so screw those who still need ack's. + if (UDP_mdata_queue_highest == UDP_MDATA_STOR_QUEUE_SIZE) // The list is full. That should not happen. But if it does, we must do something. { con_printf(CON_VERBOSE, "P#%i: MData store list is full!", Player_num); - if (multi_i_am_master()) + if (multi_i_am_master()) // I am host. I will kick everyone who did not ACK the first packet and then remove it. { for ( i=1; i UDP_MDATA_PKT_NUM_MAX) + UDP_mdata_trace[i].pkt_num_tosend = UDP_MDATA_PKT_NUM_MIN; + } + UDP_mdata_queue[UDP_mdata_queue_highest].Player_num = pnum; + memcpy( &UDP_mdata_queue[UDP_mdata_queue_highest].player_ack, player_ack, sizeof(ubyte)*MAX_PLAYERS); + memcpy( &UDP_mdata_queue[UDP_mdata_queue_highest].data, data, sizeof(char)*data_size ); + UDP_mdata_queue[UDP_mdata_queue_highest].data_size = data_size; + UDP_mdata_queue_highest++; } /* * We have received a MDATA packet. Send ACK response to sender! - * Also check in our UDP_mdata_got list, if we got this packet already. If yes, return 0 so do not process it! + * Make sure this packet has the expected packet number so we get them all in order. If not, reject it and await further packets. + * Also check in our UDP_mdata_trace list, if we got this packet already. If yes, return 0 so do not process it! */ static int net_udp_noloss_validate_mdata(uint32_t pkt_num, ubyte sender_pnum, struct _sockaddr sender_addr) { - ubyte buf[7]; + ubyte buf[7], pkt_sender_pnum = sender_pnum; int i = 0, len = 0; + // If we are a client, we get all our packets from the host. + if (!multi_i_am_master()) + sender_pnum = 0; + // Check if this comes from a valid IP - if (multi_i_am_master()) + if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[sender_pnum].protocol.udp.addr, sizeof(struct _sockaddr))) + return 0; + // Make sure this is the packet we are expecting! + if (UDP_mdata_trace[sender_pnum].pkt_num_torecv != pkt_num) { - if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[sender_pnum].protocol.udp.addr, sizeof(struct _sockaddr))) - return 0; - } - else - { - if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, sizeof(struct _sockaddr))) - return 0; + con_printf(CON_VERBOSE, "P#%i: Rejecting MData pkt %i - expected %i - pnum %i",Player_num, pkt_num, UDP_mdata_trace[sender_pnum].pkt_num_torecv, sender_pnum); + return 0; } con_printf(CON_VERBOSE, "P#%i: Sending MData ACK for pkt %i - pnum %i",Player_num, pkt_num, sender_pnum); memset(&buf,0,sizeof(buf)); buf[len] = UPID_MDATA_ACK; len++; buf[len] = Player_num; len++; - buf[len] = sender_pnum; len++; - PUT_INTEL_INT(buf + len, pkt_num); len += 4; + buf[len] = pkt_sender_pnum; len++; + PUT_INTEL_INT(buf + len, pkt_num); len += 4; dxx_sendto (UDP_Socket[0], buf, len, 0, sender_addr); - for (i = 0; i < UDP_MDATA_STOR_QUEUE_SIZE; i++) + for (i = 0; i < UDP_mdata_queue_highest; i++) { - if (pkt_num == UDP_mdata_got[sender_pnum].pkt_num[i]) + if (pkt_num == UDP_mdata_trace[sender_pnum].pkt_num[i]) return 0; // we got this packet already } - UDP_mdata_got[sender_pnum].cur_slot++; - if (UDP_mdata_got[sender_pnum].cur_slot >= UDP_MDATA_STOR_QUEUE_SIZE) - UDP_mdata_got[sender_pnum].cur_slot = 0; - UDP_mdata_got[sender_pnum].pkt_num[UDP_mdata_got[sender_pnum].cur_slot] = pkt_num; + UDP_mdata_trace[sender_pnum].cur_slot++; + if (UDP_mdata_trace[sender_pnum].cur_slot >= UDP_MDATA_STOR_QUEUE_SIZE) + UDP_mdata_trace[sender_pnum].cur_slot = 0; + UDP_mdata_trace[sender_pnum].pkt_num[UDP_mdata_trace[sender_pnum].cur_slot] = pkt_num; + UDP_mdata_trace[sender_pnum].pkt_num_torecv++; + if (UDP_mdata_trace[sender_pnum].pkt_num_torecv > UDP_MDATA_PKT_NUM_MAX) + UDP_mdata_trace[sender_pnum].pkt_num_torecv = UDP_MDATA_PKT_NUM_MIN; return 1; } @@ -4382,14 +4394,14 @@ void net_udp_noloss_got_ack(ubyte *data, int data_len) if (data_len != 7) return; - len++; - sender_pnum = data[len]; len++; - dest_pnum = data[len]; len++; + len++; + sender_pnum = data[len]; len++; + dest_pnum = data[len]; len++; pkt_num = GET_INTEL_INT(&data[len]); len += 4; - for (i = 0; i < UDP_MDATA_STOR_QUEUE_SIZE; i++) + for (i = 0; i < UDP_mdata_queue_highest; i++) { - if ((pkt_num == UDP_mdata_queue[i].pkt_num) && (dest_pnum == UDP_mdata_queue[i].Player_num)) + if ((pkt_num == UDP_mdata_queue[i].pkt_num[sender_pnum]) && (dest_pnum == UDP_mdata_queue[i].Player_num)) { con_printf(CON_VERBOSE, "P#%i: Got MData ACK for pkt_num %i from pnum %i for pnum %i",Player_num, pkt_num, sender_pnum, dest_pnum); UDP_mdata_queue[i].player_ack[sender_pnum] = 1; @@ -4401,17 +4413,22 @@ void net_udp_noloss_got_ack(ubyte *data, int data_len) /* Init/Free the queue. Call at start and end of a game or level. */ void net_udp_noloss_init_mdata_queue(void) { - con_printf(CON_VERBOSE, "P#%i: Clearing MData store/GOT list",Player_num); + int i = 0; + UDP_mdata_queue_highest=0; + con_printf(CON_VERBOSE, "P#%i: Clearing MData store/trace list",Player_num); memset(&UDP_mdata_queue,0,sizeof(UDP_mdata_store)*UDP_MDATA_STOR_QUEUE_SIZE); - memset(&UDP_mdata_got,0,sizeof(UDP_mdata_recv)*MAX_PLAYERS); + for (i = 0; i < MAX_PLAYERS; i++) + net_udp_noloss_clear_mdata_trace(i); } /* Reset the trace list for given player when (dis)connect happens */ -void net_udp_noloss_clear_mdata_got(ubyte player_num) +void net_udp_noloss_clear_mdata_trace(ubyte player_num) { - con_printf(CON_VERBOSE, "P#%i: Clearing GOT list for %i",Player_num, player_num); - memset(&UDP_mdata_got[player_num].pkt_num,0,sizeof(uint32_t)*UDP_MDATA_STOR_QUEUE_SIZE); - UDP_mdata_got[player_num].cur_slot = 0; + con_printf(CON_VERBOSE, "P#%i: Clearing trace list for %i",Player_num, player_num); + memset(&UDP_mdata_trace[player_num].pkt_num,0,sizeof(uint32_t)*UDP_MDATA_STOR_QUEUE_SIZE); + UDP_mdata_trace[player_num].cur_slot = 0; + UDP_mdata_trace[player_num].pkt_num_torecv = UDP_MDATA_PKT_NUM_MIN; + UDP_mdata_trace[player_num].pkt_num_tosend = UDP_MDATA_PKT_NUM_MIN; } /* @@ -4428,10 +4445,11 @@ void net_udp_noloss_process_queue(fix64 time) if (!Netgame.PacketLossPrevention) return; - for (queuec = 0; queuec < UDP_MDATA_STOR_QUEUE_SIZE; queuec++) + for (queuec = 0; queuec < UDP_mdata_queue_highest; queuec++) { int needack = 0; - + + // This might happen if we get out ACK's in the wrong order. So ignore that packet for now. It'll resolve itself. if (!UDP_mdata_queue[queuec].used) continue; @@ -4445,12 +4463,12 @@ void net_udp_noloss_process_queue(fix64 time) if (!UDP_mdata_queue[queuec].player_ack[plc]) { // Resend if enough time has passed. - if (UDP_mdata_queue[queuec].pkt_timestamp[plc] + (F1_0/3) <= time) + if (UDP_mdata_queue[queuec].pkt_timestamp[plc] + (F1_0/4) <= time) { ubyte buf[sizeof(UDP_mdata_info)]; int len = 0; - con_printf(CON_VERBOSE, "P#%i: Resending pkt_num %i from pnum %i to pnum %i",Player_num, UDP_mdata_queue[queuec].pkt_num, UDP_mdata_queue[queuec].Player_num, plc); + con_printf(CON_VERBOSE, "P#%i: Resending pkt_num %i from pnum %i to pnum %i",Player_num, UDP_mdata_queue[queuec].pkt_num[plc], UDP_mdata_queue[queuec].Player_num, plc); UDP_mdata_queue[queuec].pkt_timestamp[plc] = time; memset(&buf, 0, sizeof(UDP_mdata_info)); @@ -4458,7 +4476,7 @@ void net_udp_noloss_process_queue(fix64 time) // Prepare the packet and send it buf[len] = UPID_MDATA_PNEEDACK; len++; buf[len] = UDP_mdata_queue[queuec].Player_num; len++; - PUT_INTEL_INT(buf + len, UDP_mdata_queue[queuec].pkt_num); len += 4; + PUT_INTEL_INT(buf + len, UDP_mdata_queue[queuec].pkt_num[plc]); len += 4; memcpy(&buf[len], UDP_mdata_queue[queuec].data, sizeof(char)*UDP_mdata_queue[queuec].data_size); len += UDP_mdata_queue[queuec].data_size; dxx_sendto (UDP_Socket[0], buf, len, 0, Netgame.players[plc].protocol.udp.addr); @@ -4471,15 +4489,15 @@ void net_udp_noloss_process_queue(fix64 time) // Check if we can remove that packet due to to it had no resend's or Timeout if (needack==0 || (UDP_mdata_queue[queuec].pkt_initial_timestamp + UDP_TIMEOUT <= time)) { - if (needack) // packet timed out but still not all have ack'd. SCREW THEM NOW! + if (needack) // packet timed out but still not all have ack'd. { - if (multi_i_am_master()) + if (multi_i_am_master()) // We are host, so we kick the remaining players. { for ( plc=1; plc= (UPID_MAX_SIZE/2)) break; } + + // Now that we are done processing the queue, actually remove all unused packets from the top of the list. + while (!UDP_mdata_queue[0].used && UDP_mdata_queue_highest > 0) + { + memcpy(&UDP_mdata_queue[0], &UDP_mdata_queue[1], sizeof(UDP_mdata_store) * (UDP_MDATA_STOR_QUEUE_SIZE - 1)); + memset(&UDP_mdata_queue[UDP_MDATA_STOR_QUEUE_SIZE - 1], 0, sizeof(UDP_mdata_store)); + UDP_mdata_queue_highest--; + } } /* CODE FOR PACKET LOSS PREVENTION - END */ @@ -4532,22 +4558,18 @@ void net_udp_send_mdata_direct(ubyte *data, int data_len, int pnum, int needack) buf[len] = UPID_MDATA_PNEEDACK; else buf[len] = UPID_MDATA_PNORM; - len++; - buf[len] = Player_num; len++; + len++; + buf[len] = Player_num; len++; if (needack) { - UDP_MData.pkt_num++; - Assert(UDP_MDATA_STOR_QUEUE_SIZE*100 < INT_MAX); - if (UDP_MData.pkt_num > UDP_MDATA_STOR_QUEUE_SIZE*100) // roll over at some point - UDP_MData.pkt_num = 0; - PUT_INTEL_INT(buf + len, UDP_MData.pkt_num); len += 4; + PUT_INTEL_INT(buf + len, UDP_mdata_trace[pnum].pkt_num_tosend); len += 4; } memcpy(&buf[len], data, sizeof(char)*data_len); len += data_len; dxx_sendto (UDP_Socket[0], buf, len, 0, Netgame.players[pnum].protocol.udp.addr); if (needack) - net_udp_noloss_add_queue_pkt(UDP_MData.pkt_num, timer_query(), data, data_len, Player_num, pack); + net_udp_noloss_add_queue_pkt(timer_query(), data, data_len, Player_num, pack); } void net_udp_send_mdata(int needack, fix64 time) @@ -4572,14 +4594,10 @@ void net_udp_send_mdata(int needack, fix64 time) buf[len] = UPID_MDATA_PNEEDACK; else buf[len] = UPID_MDATA_PNORM; - len++; - buf[len] = Player_num; len++; - if (needack) - { - UDP_MData.pkt_num++; - PUT_INTEL_INT(buf + len, UDP_MData.pkt_num); len += 4; - } - memcpy(&buf[len], UDP_MData.mbuf, sizeof(char)*UDP_MData.mbuf_size); len += UDP_MData.mbuf_size; + len++; + buf[len] = Player_num; len++; + if (needack) len += 4; // we place the pkt_num later since it changes per player + memcpy(&buf[len], UDP_MData.mbuf, sizeof(char)*UDP_MData.mbuf_size); len += UDP_MData.mbuf_size; if (multi_i_am_master()) { @@ -4587,6 +4605,8 @@ void net_udp_send_mdata(int needack, fix64 time) { if (Players[i].connected == CONNECT_PLAYING) { + if (needack) // assign pkt_num + PUT_INTEL_INT(buf + 2, UDP_mdata_trace[i].pkt_num_tosend); dxx_sendto (UDP_Socket[0], buf, len, 0, Netgame.players[i].protocol.udp.addr); pack[i] = 0; } @@ -4594,12 +4614,14 @@ void net_udp_send_mdata(int needack, fix64 time) } else { + if (needack) // assign pkt_num + PUT_INTEL_INT(buf + 2, UDP_mdata_trace[0].pkt_num_tosend); dxx_sendto (UDP_Socket[0], buf, len, 0, Netgame.players[0].protocol.udp.addr); pack[0] = 0; } if (needack) - net_udp_noloss_add_queue_pkt(UDP_MData.pkt_num, time, UDP_MData.mbuf, UDP_MData.mbuf_size, Player_num, pack); + net_udp_noloss_add_queue_pkt(time, UDP_MData.mbuf, UDP_MData.mbuf_size, Player_num, pack); // Clear UDP_MData except pkt_num. That one must not be deleted so we can clearly keep track of important packets. UDP_MData.type = 0; @@ -4635,7 +4657,7 @@ void net_udp_process_mdata (ubyte *data, int data_len, struct _sockaddr sender_a // Add needack packet and check for possible redundancy if (needack) { - if (!net_udp_noloss_validate_mdata(GET_INTEL_SHORT(&data[2]), pnum, sender_addr)) + if (!net_udp_noloss_validate_mdata(GET_INTEL_INT(&data[2]), pnum, sender_addr)) return; } @@ -4651,14 +4673,19 @@ void net_udp_process_mdata (ubyte *data, int data_len, struct _sockaddr sender_a { if ((i != pnum) && Players[i].connected == CONNECT_PLAYING) { + if (needack) + { + pack[i] = 0; + PUT_INTEL_INT(data + 2, UDP_mdata_trace[i].pkt_num_tosend); + } dxx_sendto (UDP_Socket[0], data, data_len, 0, Netgame.players[i].protocol.udp.addr); - pack[i] = 0; + } } - if (needack && N_players > 2) + if (needack) { - net_udp_noloss_add_queue_pkt(GET_INTEL_SHORT(&data[2]), timer_query(), data+dataoffset, data_len-dataoffset, pnum, pack); + net_udp_noloss_add_queue_pkt(timer_query(), data+dataoffset, data_len-dataoffset, pnum, pack); } } @@ -4816,7 +4843,7 @@ void net_udp_read_pdata_packet(UDP_frame_info *pd) multi_send_score(); - net_udp_noloss_clear_mdata_got(TheirPlayernum); + net_udp_noloss_clear_mdata_trace(TheirPlayernum); } }