diff --git a/CHANGELOG.txt b/CHANGELOG.txt index d40486738..168ce499e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,9 @@ D1X-Rebirth Changelog +20101223 +-------- +main/net_udp.c, main/net_udp.h: Reworked object sending/receiving to work without unnecessary type casting and a bit less error prone; Also increased UDP max packet size to 2048 so we can send 7 objects per frame + 20101222 -------- arch/sdl/window.c: In window_close() prev window did not get EVENT_WINDOW_ACTIVATED but the recent closed window got it causing previous window not being activated anymore and a bunch of memory errors diff --git a/main/net_udp.c b/main/net_udp.c index 7c8e36049..5248dfd86 100644 --- a/main/net_udp.c +++ b/main/net_udp.c @@ -1323,15 +1323,9 @@ ubyte object_buffer[UPKT_MAX_SIZE]; void net_udp_send_objects(void) { - short remote_objnum; - sbyte owner; - int loc, i, h; - + sbyte owner, player_num = UDP_sync_player.player.connected; static int obj_count = 0; - static int frame_num = 0; - - int obj_count_frame = 0; - int player_num = UDP_sync_player.player.connected; + int loc = 0, i = 0, remote_objnum = 0, obj_count_frame = 0; // Send clear objects array trigger and send player num @@ -1343,107 +1337,204 @@ void net_udp_send_objects(void) { // Endlevel started before we finished sending the goods, we'll // have to stop and try again after the level. - net_udp_dump_player(UDP_sync_player.player.protocol.udp.addr, DUMP_ENDLEVEL); Network_send_objects = 0; return; } - for (h = 0; h < UDP_OBJ_PACKETS_PER_FRAME; h++) // Do more than 1 per frame, try to speed it up without - // over-stressing the receiver. + memset(object_buffer, 0, UPKT_MAX_SIZE); + object_buffer[0] = UPID_OBJECT_DATA; + loc = 5; + + if (Network_send_objnum == -1) { - obj_count_frame = 0; - memset(object_buffer, 0, UPKT_MAX_SIZE); - object_buffer[0] = UPID_OBJECT_DATA; - loc = 3; + obj_count = 0; + Network_send_object_mode = 0; + PUT_INTEL_INT(object_buffer+loc, -1); loc += 4; + object_buffer[loc] = player_num; loc += 1; + /* Placeholder for remote_objnum, not used here */ loc += 4; + Network_send_objnum = 0; + obj_count_frame = 1; + } - if (Network_send_objnum == -1) - { - obj_count = 0; - Network_send_object_mode = 0; - *(short *)(object_buffer+loc) = INTEL_SHORT(-1); loc += 2; - object_buffer[loc] = player_num; loc += 1; - loc += 2; // Placeholder for remote_objnum, not used here - Network_send_objnum = 0; - obj_count_frame = 1; - frame_num = 0; - } - - for (i = Network_send_objnum; i <= Highest_object_index; i++) - { - if ((Objects[i].type != OBJ_POWERUP) && (Objects[i].type != OBJ_PLAYER) && - (Objects[i].type != OBJ_CNTRLCEN) && (Objects[i].type != OBJ_GHOST) && - (Objects[i].type != OBJ_ROBOT) && (Objects[i].type != OBJ_HOSTAGE)) - continue; - if ((Network_send_object_mode == 0) && ((object_owner[i] != -1) && (object_owner[i] != player_num))) - continue; - if ((Network_send_object_mode == 1) && ((object_owner[i] == -1) || (object_owner[i] == player_num))) - continue; - - if ( loc + sizeof(object_rw) + 5 > UPKT_MAX_SIZE-1 ) - break; // Not enough room for another object + for (i = Network_send_objnum; i <= Highest_object_index; i++) + { + if ((Objects[i].type != OBJ_POWERUP) && (Objects[i].type != OBJ_PLAYER) && + (Objects[i].type != OBJ_CNTRLCEN) && (Objects[i].type != OBJ_GHOST) && + (Objects[i].type != OBJ_ROBOT) && (Objects[i].type != OBJ_HOSTAGE)) + continue; + if ((Network_send_object_mode == 0) && ((object_owner[i] != -1) && (object_owner[i] != player_num))) + continue; + if ((Network_send_object_mode == 1) && ((object_owner[i] == -1) || (object_owner[i] == player_num))) + continue; - obj_count_frame++; - obj_count++; - - remote_objnum = objnum_local_to_remote((short)i, &owner); - Assert(owner == object_owner[i]); + if ( loc + sizeof(object_rw) + 9 > UPKT_MAX_SIZE-1 ) + break; // Not enough room for another object - *(short *)(object_buffer+loc) = INTEL_SHORT(i); loc += 2; - object_buffer[loc] = owner; loc += 1; - *(short *)(object_buffer+loc) = INTEL_SHORT(remote_objnum); loc += 2; - // use object_rw to send objects for now. if object sometime contains some day contains something useful the client should know about, we should use it. but by now it's also easier to use object_rw because then we also do not need fix64 timer values. - multi_object_to_object_rw(&Objects[i], (object_rw *)&object_buffer[loc]); + obj_count_frame++; + obj_count++; + + remote_objnum = objnum_local_to_remote(i, &owner); + Assert(owner == object_owner[i]); + + PUT_INTEL_INT(object_buffer+loc, i); loc += 4; + object_buffer[loc] = owner; loc += 1; + PUT_INTEL_INT(object_buffer+loc, remote_objnum); loc += 4; + // use object_rw to send objects for now. if object sometime contains some day contains something useful the client should know about, we should use it. but by now it's also easier to use object_rw because then we also do not need fix64 timer values. + multi_object_to_object_rw(&Objects[i], (object_rw *)&object_buffer[loc]); #ifdef WORDS_BIGENDIAN - object_rw_swap((object_rw *)&object_buffer[loc], 1); + object_rw_swap((object_rw *)&object_buffer[loc], 1); #endif - loc += sizeof(object_rw); - } + loc += sizeof(object_rw); + } - if (obj_count_frame) // Send any objects we've buffered + if (obj_count_frame) // Send any objects we've buffered + { + Network_send_objnum = i; + PUT_INTEL_INT(object_buffer+1, obj_count_frame); + + Assert(loc <= UPKT_MAX_SIZE); + + sendto (UDP_Socket[0], object_buffer, loc, 0, (struct sockaddr *)&UDP_sync_player.player.protocol.udp.addr, sizeof(struct _sockaddr)); + } + + if (i > Highest_object_index) + { + if (Network_send_object_mode == 0) { - frame_num++; + Network_send_objnum = 0; + Network_send_object_mode = 1; // go to next mode + } + else + { + Assert(Network_send_object_mode == 1); + + // Send count so other side can make sure he got them all + object_buffer[0] = UPID_OBJECT_DATA; + PUT_INTEL_INT(object_buffer+1, 1); + PUT_INTEL_INT(object_buffer+5, -2); + PUT_INTEL_INT(object_buffer+9, obj_count); + sendto (UDP_Socket[0], object_buffer, 13, 0, (struct sockaddr *)&UDP_sync_player.player.protocol.udp.addr, sizeof(struct _sockaddr)); + + // Send sync packet which tells the player who he is and to start! + net_udp_send_rejoin_sync(player_num); + + // Turn off send object mode + Network_send_objnum = -1; + Network_send_objects = 0; + obj_count = 0; + + return; + } // mode == 1; + } // i > Highest_object_index +} + +int net_udp_verify_objects(int remote, int local) +{ + int i, nplayers = 0; + + if ((remote-local) > 10) + return(2); + + for (i = 0; i <= Highest_object_index; i++) + { + if ((Objects[i].type == OBJ_PLAYER) || (Objects[i].type == OBJ_GHOST)) + nplayers++; + } + + if (MaxNumNetPlayers<=nplayers) + return(0); + + return(1); +} + +void net_udp_read_object_packet( ubyte *data ) +{ + // Object from another net player we need to sync with + object *obj; + sbyte obj_owner, my_pnum = 0; + static int mode = 0, object_count = 0; + int i = 0, segnum = 0, objnum = 0, remote_objnum = 0, nobj = 0, loc = 5; - Network_send_objnum = i; - object_buffer[1] = obj_count_frame; - object_buffer[2] = frame_num; + nobj = GET_INTEL_INT(data + 1); - Assert(loc <= UPKT_MAX_SIZE); + for (i = 0; i < nobj; i++) + { + objnum = GET_INTEL_INT(data + loc); loc += 4; + obj_owner = data[loc]; loc += 1; + remote_objnum = GET_INTEL_INT(data + loc); loc += 4; - sendto (UDP_Socket[0], object_buffer, loc, 0, (struct sockaddr *)&UDP_sync_player.player.protocol.udp.addr, sizeof(struct _sockaddr)); - } - - if (i > Highest_object_index) + if (objnum == -1) { - if (Network_send_object_mode == 0) + // Clear object array + init_objects(); + Network_rejoined = 1; + my_pnum = obj_owner; + change_playernum_to(my_pnum); + mode = 1; + object_count = 0; + } + else if (objnum == -2) + { + // Special debug checksum marker for entire send + if (mode == 1) { - Network_send_objnum = 0; - Network_send_object_mode = 1; // go to next mode + special_reset_objects(); + mode = 0; } - else + if (remote_objnum != object_count) { + Int3(); + } + if (net_udp_verify_objects(remote_objnum, object_count)) { - Assert(Network_send_object_mode == 1); - - frame_num++; - // Send count so other side can make sure he got them all - object_buffer[0] = UPID_OBJECT_DATA; - object_buffer[1] = 1; - object_buffer[2] = frame_num; - *(short *)(object_buffer+3) = INTEL_SHORT(-2); - *(short *)(object_buffer+6) = INTEL_SHORT(obj_count); - sendto (UDP_Socket[0], object_buffer, 8, 0, (struct sockaddr *)&UDP_sync_player.player.protocol.udp.addr, sizeof(struct _sockaddr)); - - // Send sync packet which tells the player who he is and to start! - net_udp_send_rejoin_sync(player_num); - - // Turn off send object mode - Network_send_objnum = -1; - Network_send_objects = 0; - obj_count = 0; + // Failed to sync up + nm_messagebox(NULL, 1, TXT_OK, TXT_NET_SYNC_FAILED); + Network_status = NETSTAT_MENU; return; - } // mode == 1; - } // i > Highest_object_index - } // For PACKETS_PER_FRAME + } + } + else + { + object_count++; + if ((obj_owner == my_pnum) || (obj_owner == -1)) + { + if (mode != 1) + Int3(); // SEE ROB + objnum = remote_objnum; + } + else { + if (mode == 1) + { + special_reset_objects(); + mode = 0; + } + objnum = obj_allocate(); + } + if (objnum != -1) { + obj = &Objects[objnum]; + if (obj->segnum != -1) + obj_unlink(objnum); + Assert(obj->segnum == -1); + Assert(objnum < MAX_OBJECTS); +#ifdef WORDS_BIGENDIAN + object_rw_swap((object_rw *)&data[loc], 1); +#endif + multi_object_rw_to_object((object_rw *)&data[loc], obj); + loc += sizeof(object_rw); + segnum = obj->segnum; + obj->next = obj->prev = obj->segnum = -1; + obj->attached_obj = -1; + if (segnum > -1) + obj_link(obj-Objects,segnum); + if (obj_owner == my_pnum) + map_objnum_local_to_local(objnum); + else if (obj_owner != -1) + map_objnum_local_to_remote(objnum, remote_objnum, obj_owner); + else + object_owner[objnum] = -1; + } + } // For a standard onbject + } // For each object in packet } void net_udp_send_rejoin_sync(int player_num) @@ -2279,143 +2370,6 @@ void net_udp_read_endlevel_packet( ubyte *data, int data_len, struct _sockaddr s } } -void -net_udp_pack_objects(void) -{ - // Switching modes, pack the object array - - special_reset_objects(); -} - -int -net_udp_verify_objects(int remote, int local) -{ - int i, nplayers = 0; - - if ((remote-local) > 10) - return(2); - - for (i = 0; i <= Highest_object_index; i++) - { - if ((Objects[i].type == OBJ_PLAYER) || (Objects[i].type == OBJ_GHOST)) - nplayers++; - } - - if (MaxNumNetPlayers<=nplayers) - return(0); - - return(1); -} - -void -net_udp_read_object_packet( ubyte *data ) -{ - // Object from another net player we need to sync with - - short objnum, remote_objnum; - sbyte obj_owner; - int segnum, i; - object *obj; - - static int my_pnum = 0; - static int mode = 0; - static int object_count = 0; - static int frame_num = 0; - int nobj = data[1]; - int loc = 3; - int remote_frame_num = data[2]; - - frame_num++; - - for (i = 0; i < nobj; i++) - { - objnum = INTEL_SHORT(*(short *)(data+loc)); loc += 2; - obj_owner = data[loc]; loc += 1; - remote_objnum = INTEL_SHORT(*(short *)(data+loc)); loc += 2; - - if (objnum == -1) - { - // Clear object array - init_objects(); - Network_rejoined = 1; - my_pnum = obj_owner; - change_playernum_to(my_pnum); - mode = 1; - object_count = 0; - frame_num = 1; - } - else if (objnum == -2) - { - // Special debug checksum marker for entire send - if (mode == 1) - { - net_udp_pack_objects(); - mode = 0; - } - if (remote_objnum != object_count) { - Int3(); - } - if (net_udp_verify_objects(remote_objnum, object_count)) - { - // Failed to sync up - nm_messagebox(NULL, 1, TXT_OK, TXT_NET_SYNC_FAILED); - Network_status = NETSTAT_MENU; - return; - } - frame_num = 0; - } - else - { - if (frame_num != remote_frame_num) - Int3(); - - object_count++; - if ((obj_owner == my_pnum) || (obj_owner == -1)) - { - if (mode != 1) - Int3(); // SEE ROB - objnum = remote_objnum; - //if (objnum > Highest_object_index) - //{ - // Highest_object_index = objnum; - // num_objects = Highest_object_index+1; - //} - } - else { - if (mode == 1) - { - net_udp_pack_objects(); - mode = 0; - } - objnum = obj_allocate(); - } - if (objnum != -1) { - obj = &Objects[objnum]; - if (obj->segnum != -1) - obj_unlink(objnum); - Assert(obj->segnum == -1); - Assert(objnum < MAX_OBJECTS); -#ifdef WORDS_BIGENDIAN - object_rw_swap((object_rw *)&data[loc], 1); -#endif - multi_object_rw_to_object((object_rw *)&data[loc], obj); - loc += sizeof(object_rw); - segnum = obj->segnum; - obj->next = obj->prev = obj->segnum = -1; - obj->attached_obj = -1; - if (segnum > -1) - obj_link(obj-Objects,segnum); - if (obj_owner == my_pnum) - map_objnum_local_to_local(objnum); - else if (obj_owner != -1) - map_objnum_local_to_remote(objnum, remote_objnum, obj_owner); - else - object_owner[objnum] = -1; - } - } // For a standard onbject - } // For each object in packet -} - /* * Polling loop waiting for sync packet to start game after having sent request */ diff --git a/main/net_udp.h b/main/net_udp.h index 5f967c8ec..7e73d5dbb 100644 --- a/main/net_udp.h +++ b/main/net_udp.h @@ -34,10 +34,9 @@ int net_udp_level_sync(); #define UDP_NETGAMES_PAGES 50 // Pages available on Netlist (UDP_MAX_NETGAMES/UDP_NETGAMES_PPAGE) #define UDP_TIMEOUT (10*F1_0) // 10 seconds disconnect timeout #define UDP_MDATA_STOR_QUEUE_SIZE 500 // Store up to 500 MDATA packets -#define UDP_OBJ_PACKETS_PER_FRAME 1 // Following are static defines for the buffer size of various packets. IF you change the packets, you must change the size, too. -#define UPKT_MAX_SIZE 1024 // Max size for a packet - just for the buffers +#define UPKT_MAX_SIZE 2048 // Max size for a packet #define UPKT_GAME_INFO_REQ_SIZE 11 #define UPKT_SEQUENCE_SIZE 14 #define UPKT_PING_SIZE 37