diff --git a/PROJECTS/ROLLER/3d.c b/PROJECTS/ROLLER/3d.c index d685654..0f6de69 100644 --- a/PROJECTS/ROLLER/3d.c +++ b/PROJECTS/ROLLER/3d.c @@ -656,8 +656,8 @@ void doexit() if (network_on) { tick_on = -1; frontend_on = -1; - broadcast_mode = -666; - while (broadcast_mode == -666) { + network_broadcast_wait_start(-666, 1); + while (!network_broadcast_wait_update()) { UpdateSDL(); } } diff --git a/PROJECTS/ROLLER/frontend_lobby.c b/PROJECTS/ROLLER/frontend_lobby.c index c74b4da..d5cdeff 100644 --- a/PROJECTS/ROLLER/frontend_lobby.c +++ b/PROJECTS/ROLLER/frontend_lobby.c @@ -29,6 +29,31 @@ static int iLobbyActive; // nonzero while waiting for players; 0 when lobby should exit static int iLobbySavedScrSize; +typedef enum { + eLOBBY_BROADCAST_NONE = 0, + eLOBBY_BROADCAST_FADE_IN, + eLOBBY_BROADCAST_START_RACE, + eLOBBY_BROADCAST_LEAVE, + eLOBBY_BROADCAST_SAME_CAR_DROP +} eLobbyBroadcastAction; + +typedef enum { + eLOBBY_POST_SYNC_NONE = 0, + eLOBBY_POST_SYNC_DELAY, + eLOBBY_POST_SYNC_INIT, + eLOBBY_POST_SYNC_MASTER_RECORDS, + eLOBBY_POST_SYNC_MASTER_SEED, + eLOBBY_POST_SYNC_SLAVE_SEED +} eLobbyPostSyncPhase; + +static eLobbyBroadcastAction eLobbyBroadcastActionCurrent; +static eLobbyPostSyncPhase eLobbyPostSyncCurrentPhase; +static int iLobbyPostSyncDelayTarget; +static int iLobbyLastRecordWaitLog; +static int iLobbyLastStartResend; +static int iLobbyLastRecordResend; +static int iLobbyRacePrepared; + //------------------------------------------------------------------------------------------------- void frontend_lobby_enter(void) @@ -63,6 +88,147 @@ void frontend_lobby_enter(void) } } iLobbyActive = -1; + eLobbyBroadcastActionCurrent = eLOBBY_BROADCAST_NONE; + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_NONE; + iLobbyPostSyncDelayTarget = 0; + iLobbyLastRecordWaitLog = -1000; + iLobbyLastStartResend = -1000; + iLobbyLastRecordResend = -1000; + iLobbyRacePrepared = 0; +} + +//------------------------------------------------------------------------------------------------- + +static void lobby_begin_broadcast_wait(eLobbyBroadcastAction eAction, + int iBroadcastMode, + int iRepeatCount) +{ + eLobbyBroadcastActionCurrent = eAction; + network_broadcast_wait_start(iBroadcastMode, iRepeatCount); +} + +//------------------------------------------------------------------------------------------------- + +static int lobby_update_broadcast_wait(void) +{ + if (eLobbyBroadcastActionCurrent == eLOBBY_BROADCAST_NONE) + return 0; + + if (!network_broadcast_wait_update()) + return -1; + + switch (eLobbyBroadcastActionCurrent) { + case eLOBBY_BROADCAST_FADE_IN: + frames = 0; + break; + case eLOBBY_BROADCAST_START_RACE: + iLobbyActive = 0; + time_to_start = -1; + break; + case eLOBBY_BROADCAST_LEAVE: + iLobbyActive = 0; + --players_waiting; + no_clear = -1; + break; + case eLOBBY_BROADCAST_SAME_CAR_DROP: + iLobbyActive = 0; + --players_waiting; + break; + default: + break; + } + + eLobbyBroadcastActionCurrent = eLOBBY_BROADCAST_NONE; + return -1; +} + +//------------------------------------------------------------------------------------------------- + +static void lobby_begin_post_sync(void) +{ + iLobbyPostSyncDelayTarget = ticks + 18; + iLobbyLastRecordWaitLog = -1000; + iLobbyLastStartResend = -1000; + iLobbyLastRecordResend = -1000; + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_DELAY; +} + +//------------------------------------------------------------------------------------------------- + +static void lobby_finish_post_sync(void) +{ + check_cars(); + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_NONE; + eFrontendNextState = quit_game ? eFRONTEND_STATE_QUIT : eFRONTEND_STATE_LOADING; +} + +//------------------------------------------------------------------------------------------------- + +static int lobby_update_post_sync(void) +{ + if (eLobbyPostSyncCurrentPhase == eLOBBY_POST_SYNC_NONE) + return 0; + + switch (eLobbyPostSyncCurrentPhase) { + case eLOBBY_POST_SYNC_DELAY: + if (iLobbyPostSyncDelayTarget > ticks) + return -1; + network_broadcast_wait_start(-314, 1); + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_INIT; + return -1; + + case eLOBBY_POST_SYNC_INIT: + if (!network_broadcast_wait_update()) + return -1; + if (wConsoleNode == master) + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_MASTER_RECORDS; + else + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_SLAVE_SEED; + return -1; + + case eLOBBY_POST_SYNC_MASTER_RECORDS: + if (received_records >= network_on) { + network_broadcast_wait_start(-2718, 1); + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_MASTER_SEED; + return -1; + } + if (frames - iLobbyLastRecordWaitLog >= 36) { + iLobbyLastRecordWaitLog = frames; + SDL_Log("[NET-START] master waiting for records received=%d expected=%d", + received_records, network_on); + } + if (frames - iLobbyLastStartResend >= 36) { + iLobbyLastStartResend = frames; + TransmitInit(); + } + CheckNewNodes(); + ROLLERCommsPumpSendQueue(); + return -1; + + case eLOBBY_POST_SYNC_MASTER_SEED: + if (!network_broadcast_wait_update()) + return -1; + lobby_finish_post_sync(); + return -1; + + case eLOBBY_POST_SYNC_SLAVE_SEED: + if (received_seed) { + lobby_finish_post_sync(); + return -1; + } + if (frames - iLobbyLastRecordResend >= 36) { + iLobbyLastRecordResend = frames; + SDL_Log("[NET-START] slave waiting for seed; resending record to master=%d", master); + send_record_to_master(TrackLoad); + } + CheckNewNodes(); + ROLLERCommsPumpSendQueue(); + return -1; + + default: + eLobbyPostSyncCurrentPhase = eLOBBY_POST_SYNC_NONE; + return 0; + } } //------------------------------------------------------------------------------------------------- @@ -154,13 +320,7 @@ static void lobby_draw_frame(void) if (!front_fade) { front_fade = -1; menu_render_begin_fade(mr, 1, 32); - broadcast_mode = -668; - while (broadcast_mode) - UpdateSDL(); - broadcast_mode = -668; - while (broadcast_mode) - UpdateSDL(); - frames = 0; + lobby_begin_broadcast_wait(eLOBBY_BROADCAST_FADE_IN, -668, 2); } } } @@ -179,27 +339,14 @@ static void lobby_handle_input(void) fatgetch(); } else if (uiKeyPressed <= 0xD) { if (players_waiting == network_on && !time_to_start) { - iLobbyActive = 0; - broadcast_mode = -671; - while (broadcast_mode) - UpdateSDL(); - broadcast_mode = -671; - while (broadcast_mode) - UpdateSDL(); - broadcast_mode = -671; - while (broadcast_mode) - UpdateSDL(); - time_to_start = -1; + lobby_begin_broadcast_wait(eLOBBY_BROADCAST_START_RACE, -671, 3); + return; } } else if (uiKeyPressed == 27 && !time_to_start && !restart_net) { StartPressed = 0; time_to_start = 0; - broadcast_mode = -670; - while (broadcast_mode) - UpdateSDL(); - iLobbyActive = 0; - --players_waiting; - no_clear = -1; + lobby_begin_broadcast_wait(eLOBBY_BROADCAST_LEAVE, -670, 1); + return; } } } @@ -208,6 +355,12 @@ static void lobby_handle_input(void) void frontend_lobby_update(void) { + if (lobby_update_broadcast_wait()) + return; + + if (lobby_update_post_sync()) + return; + // Handle game type switching from master if (switch_types) { game_type = switch_types - 1; @@ -228,11 +381,8 @@ void frontend_lobby_update(void) if (Players_Cars[player1_car] < 0) { StartPressed = 0; time_to_start = 0; - broadcast_mode = -670; - while (broadcast_mode) - ; - iLobbyActive = 0; - --players_waiting; + lobby_begin_broadcast_wait(eLOBBY_BROADCAST_SAME_CAR_DROP, -670, 1); + return; } } else if (switch_same < 0) { for (int i = 0; i < players; i++) @@ -241,11 +391,8 @@ void frontend_lobby_update(void) switch_same = 0; StartPressed = 0; time_to_start = 0; - broadcast_mode = -670; - while (broadcast_mode) - ; - iLobbyActive = 0; - --players_waiting; + lobby_begin_broadcast_wait(eLOBBY_BROADCAST_SAME_CAR_DROP, -670, 1); + return; } check_cars(); @@ -254,8 +401,11 @@ void frontend_lobby_update(void) if (!iLobbyActive) { if (time_to_start) { - frontend_main_menu_prepare_race_start(); - eFrontendNextState = quit_game ? eFRONTEND_STATE_QUIT : eFRONTEND_STATE_LOADING; + if (!iLobbyRacePrepared) { + frontend_main_menu_prepare_race_start(); + iLobbyRacePrepared = -1; + } + lobby_begin_post_sync(); } else { eFrontendNextState = eFRONTEND_STATE_MAIN_MENU; } @@ -266,55 +416,6 @@ void frontend_lobby_update(void) void frontend_lobby_exit(void) { - // Post-lobby sync: brief timing gap then network handshake before race starts. - // Only runs when time_to_start is set; skipped on escape or disconnect. - int iTimer = ticks + 18; - while (iTimer > ticks) - ; - - if (time_to_start) { - broadcast_mode = -314; - while (broadcast_mode) { - CheckNewNodes(); - BroadcastNews(); - UpdateSDL(); - } - if (wConsoleNode == master) { - int iLastRecordWaitLog = -1000; - int iLastStartResend = -1000; - while (received_records < network_on) { - if (frames - iLastRecordWaitLog >= 36) { - iLastRecordWaitLog = frames; - SDL_Log("[NET-START] master waiting for records received=%d expected=%d", - received_records, network_on); - } - if (frames - iLastStartResend >= 36) { - iLastStartResend = frames; - TransmitInit(); - } - CheckNewNodes(); - UpdateSDL(); - } - broadcast_mode = -2718; - while (broadcast_mode) { - CheckNewNodes(); - BroadcastNews(); - UpdateSDL(); - } - } else { - int iLastRecordResend = -1000; - while (!received_seed) { - if (frames - iLastRecordResend >= 36) { - iLastRecordResend = frames; - SDL_Log("[NET-START] slave waiting for seed; resending record to master=%d", master); - send_record_to_master(TrackLoad); - } - CheckNewNodes(); - UpdateSDL(); - } - } - } - check_cars(); { diff --git a/PROJECTS/ROLLER/frontend_screens.c b/PROJECTS/ROLLER/frontend_screens.c index 41fcf48..43405e0 100644 --- a/PROJECTS/ROLLER/frontend_screens.c +++ b/PROJECTS/ROLLER/frontend_screens.c @@ -294,6 +294,19 @@ static int iFrontendMainMenuBlockIdx = 0; static int iFrontendMainMenuPtexSize = 0; static int iFrontendMainMenuStartDelayTarget = 0; +typedef enum { + eMAIN_MENU_NET_WAIT_NONE = 0, + eMAIN_MENU_NET_WAIT_SETUP_SYNC, + eMAIN_MENU_NET_WAIT_FADE_EXISTING, + eMAIN_MENU_NET_WAIT_FADE_DISCOVERY, + eMAIN_MENU_NET_WAIT_QUIT_BROADCAST, + eMAIN_MENU_NET_WAIT_QUIT_TICKS, + eMAIN_MENU_NET_WAIT_RESTART_SYNC +} eMainMenuNetworkWait; + +static eMainMenuNetworkWait eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; +static int iFrontendMainMenuQuitTickTarget = 0; + static void frontend_main_menu_load_renderer_blocks(void) { MenuRenderer *mr = GetMenuRenderer(); @@ -307,6 +320,85 @@ static void frontend_main_menu_load_renderer_blocks(void) } } +static int frontend_main_menu_update_network_wait(void); +static void frontend_main_menu_finish_prepare_to_start(void); + +//------------------------------------------------------------------------------------------------- + +static void frontend_main_menu_begin_network_wait(eMainMenuNetworkWait eWait, + int iBroadcastMode, + int iRepeatCount) +{ + eFrontendMainMenuNetworkWait = eWait; + network_broadcast_wait_start(iBroadcastMode, iRepeatCount); +} + +//------------------------------------------------------------------------------------------------- + +static int frontend_main_menu_update_network_wait(void) +{ + if (eFrontendMainMenuNetworkWait == eMAIN_MENU_NET_WAIT_NONE) + return 0; + + switch (eFrontendMainMenuNetworkWait) { + case eMAIN_MENU_NET_WAIT_SETUP_SYNC: + if (!network_broadcast_wait_update()) + return -1; + name_copy(player_names[player1_car], my_name); + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; + return -1; + + case eMAIN_MENU_NET_WAIT_FADE_EXISTING: + if (!network_broadcast_wait_update()) + return -1; + frontend_main_menu_begin_network_wait(eMAIN_MENU_NET_WAIT_FADE_DISCOVERY, -1, 1); + return -1; + + case eMAIN_MENU_NET_WAIT_FADE_DISCOVERY: + if (!network_broadcast_wait_update()) + return -1; + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; + return -1; + + case eMAIN_MENU_NET_WAIT_QUIT_BROADCAST: + if (!network_broadcast_wait_update()) + return -1; + tick_on = 0; + ticks = 0; + iFrontendMainMenuQuitTickTarget = 3; + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_QUIT_TICKS; + return -1; + + case eMAIN_MENU_NET_WAIT_QUIT_TICKS: + if (ticks < iFrontendMainMenuQuitTickTarget) + return -1; + close_network(); + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; + frontend_main_menu_finish_prepare_to_start(); + return -1; + + case eMAIN_MENU_NET_WAIT_RESTART_SYNC: + if (!network_broadcast_wait_update()) + return -1; + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; + restart_net = 0; + no_clear = 0; + if (!quit_game && !intro) { + check_cars(); + eFrontendNextState = eFRONTEND_STATE_LOBBY; + } else { + eFrontendNextState = quit_game ? eFRONTEND_STATE_QUIT : eFRONTEND_STATE_LOADING; + } + return -1; + + default: + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; + return 0; + } +} + +//------------------------------------------------------------------------------------------------- + static void frontend_main_menu_black_palette(void) { palette_brightness = 0; @@ -379,6 +471,26 @@ static void frontend_main_menu_free_preview_title_assets(void) fre((void **)&front_vga[14]); } +static void frontend_main_menu_begin_restart_net(void) +{ + SVGA_ON = -1; + init_screen(); + winx = 0; + winy = 0; + winw = XMAX; + mirror = 0; + winh = YMAX; + frontend_on = -1; + time_to_start = 0; + StartPressed = 0; + tick_on = -1; + load_language_file(szSelectEng, 0); + load_language_file(szConfigEng, 1); + remove_messages(-1); + reset_network(0); + frontend_main_menu_begin_network_wait(eMAIN_MENU_NET_WAIT_RESTART_SYNC, -667, 1); +} + static void frontend_main_menu_resume_after_child(void) { frontend_main_menu_free_preview_title_assets(); @@ -404,6 +516,8 @@ static void frontend_main_menu_setup(void) loadfatalsample(); iFrontendMainMenuContinue = 0; iFrontendMainMenuRotation = 0; + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_NONE; + iFrontendMainMenuQuitTickTarget = 0; player1_car = 0; player2_car = 1; if (!network_on) { @@ -515,10 +629,7 @@ static void frontend_main_menu_setup(void) ticks = 0; frames = 0; if (network_on) { - broadcast_mode = -667; - while (broadcast_mode) - UpdateSDL(); - name_copy(player_names[player1_car], my_name); + frontend_main_menu_begin_network_wait(eMAIN_MENU_NET_WAIT_SETUP_SYNC, -667, 1); } iFrontendMainMenuStartDelayTarget = 0; @@ -895,23 +1006,8 @@ void frontend_main_menu_prepare_race_start(void) stopmusic(); } -static void frontend_main_menu_prepare_to_start(void) +static void frontend_main_menu_finish_prepare_to_start(void) { - my_car = Players_Cars[player1_car]; - name_copy(my_name, player_names[player1_car]); - my_invul = player_invul[player1_car]; - my_control = manual_control[player1_car]; - last_replay = replaytype; - if (quit_game && network_on) { - broadcast_mode = -666; - while (broadcast_mode) - UpdateSDL(); - tick_on = 0; - ticks = 0; - while (ticks < 3) - ; - close_network(); - } releasesamples(); if (game_type != 4 && game_type != 3) holdmusic = 0; @@ -932,8 +1028,8 @@ static void frontend_main_menu_prepare_to_start(void) if (network_on && iFrontendMainMenuSelection == 8 && !intro) { // Hand off to the LOBBY dispatcher state; it calls // frontend_main_menu_prepare_race_start() and sets the next state - // when the lobby resolves. restart_net_game() still calls - // NetworkWait() directly (Phase 5 will convert that path). + // when the lobby resolves. restart_net re-entry uses the same + // dispatcher lobby path. iFrontendMainMenuInitialized = 0; iFrontendMainMenuStartDelayTarget = 0; eFrontendNextState = eFRONTEND_STATE_LOBBY; @@ -954,6 +1050,21 @@ static void frontend_main_menu_prepare_to_start(void) eFrontendNextState = quit_game ? eFRONTEND_STATE_QUIT : eFRONTEND_STATE_LOADING; } +static void frontend_main_menu_prepare_to_start(void) +{ + my_car = Players_Cars[player1_car]; + name_copy(my_name, player_names[player1_car]); + my_invul = player_invul[player1_car]; + my_control = manual_control[player1_car]; + last_replay = replaytype; + if (quit_game && network_on) { + frontend_main_menu_begin_network_wait(eMAIN_MENU_NET_WAIT_QUIT_BROADCAST, -666, 1); + return; + } + + frontend_main_menu_finish_prepare_to_start(); +} + static void frontend_main_menu_begin_child(eFrontendState eState) { frontend_main_menu_free_selected_car_textures(); @@ -1111,16 +1222,20 @@ void frontend_menu_update(void) int nFrames; MenuRenderer *mr; + if (frontend_main_menu_update_network_wait()) + return; + if (restart_net) { - restart_net_game(); - restart_net = 0; - eFrontendNextState = quit_game ? eFRONTEND_STATE_QUIT : eFRONTEND_STATE_LOADING; + frontend_main_menu_begin_restart_net(); return; } if (!iFrontendMainMenuInitialized) frontend_main_menu_setup(); + if (frontend_main_menu_update_network_wait()) + return; + if (iFrontendMainMenuStartDelayTarget) { if (ticks >= iFrontendMainMenuStartDelayTarget) { while (fatkbhit()) @@ -1151,11 +1266,12 @@ void frontend_menu_update(void) palette_brightness = 32; frames = 0; if (network_on) { - while (broadcast_mode) - UpdateSDL(); - broadcast_mode = -1; - while (broadcast_mode) - UpdateSDL(); + if (broadcast_mode) { + eFrontendMainMenuNetworkWait = eMAIN_MENU_NET_WAIT_FADE_EXISTING; + } else { + frontend_main_menu_begin_network_wait(eMAIN_MENU_NET_WAIT_FADE_DISCOVERY, -1, 1); + } + return; } } diff --git a/PROJECTS/ROLLER/network.c b/PROJECTS/ROLLER/network.c index a2d7de8..3fcd023 100644 --- a/PROJECTS/ROLLER/network.c +++ b/PROJECTS/ROLLER/network.c @@ -66,6 +66,8 @@ int16 wConsoleNode; //0017C9DA //------------------------------------------------------------------------------------------------- static int s_iLastDiscoveryBroadcastFrame = -1000; +static int s_iBroadcastWaitMode = 0; +static int s_iBroadcastWaitRepeatsLeft = 0; //------------------------------------------------------------------------------------------------- @@ -262,7 +264,8 @@ void Initialise_Network(int iSelectNetSlot) else broadcast_mode = -1; tick_on = -1; - while (broadcast_mode) + network_broadcast_wait_start((int)broadcast_mode, 1); + while (!network_broadcast_wait_update()) UpdateSDL(); //added by ROLLER ROLLERCommsSortNodes(); received_records = 1; @@ -450,14 +453,12 @@ void send_quit() if (wConsoleNode == master) { for (i = 0; i < network_on; ++i) { if (i != wConsoleNode) { - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), p_data, 0, i)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), p_data, 0, i); } } net_quit = -1; } else { - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), p_data, 0, master)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), p_data, 0, master); } } } @@ -466,8 +467,6 @@ void send_quit() //0004F290 void send_ready() { - int iDataSent; // eax - if (network_on) { p_header.byConsoleNode = (uint8)wConsoleNode; if (localCD) @@ -475,12 +474,9 @@ void send_ready() else p_header.uiId = PACKET_ID_NOCD; if (wConsoleNode != master || player_ready[master]) { - do { - //_disable(); - iDataSent = ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), p_data, 0, master); - //_enable(); - UpdateSDL(); //added by ROLLER - } while (!iDataSent); + if (ROLLERCommsSendQueueDepth(master) > 0) + return; + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), p_data, 0, master); } else { player_ready[master] = -1; active_nodes++; @@ -501,8 +497,7 @@ void send_record_to_master(int iRecordIdx) SDL_Log("[NET-START] send record to master=%d from node=%d track=%d", master, (int)wConsoleNode, iRecordIdx); - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), &p_record, sizeof(tRecordPacket), master)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), &p_record, sizeof(tRecordPacket), master); } } @@ -520,9 +515,7 @@ void send_record_to_slaves(int iRecordIdx) for (int i = 0; i < network_on; ++i) { iRecordIdx = wConsoleNode; if (wConsoleNode != i) { - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), &p_record, sizeof(tRecordPacket), i)) { - UpdateSDL(); //added by ROLLER - } + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), &p_record, sizeof(tRecordPacket), i); } } } @@ -552,16 +545,14 @@ void send_mes(int iNetworkMessageIdx, int iNode) iNetPlayers = 0; do { if (iNodeIdx != wConsoleNode && net_players[iNetPlayers]) { - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), p_data, sizeof(p_data), iNodeIdx)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), p_data, sizeof(p_data), iNodeIdx); } ++iNetPlayers; ++iNodeIdx; } while (iNodeIdx < network_on); } } else { - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), p_data, sizeof(p_data), iNode)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), p_data, sizeof(p_data), iNode); } } else { message_sent = 4; @@ -581,8 +572,7 @@ void send_seed(int iRandomSeed) iRandomSeed, (int)wConsoleNode, network_on); for (int i = 0; i < network_on; ++i) { if (i != wConsoleNode) { - while (!ROLLERCommsSendData(&p_header, 12, &test_seed, 4, i)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, 12, &test_seed, 4, i); } } @@ -645,8 +635,7 @@ void send_pause() syncHeader.byConsoleNode = (uint8)wConsoleNode; syncHeader.uiId = PACKET_ID_PAUSE; bPaused = paused == 0; - while (!ROLLERCommsSendData(&syncHeader, sizeof(tSyncHeader), &bPaused, sizeof(bool), master)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&syncHeader, sizeof(tSyncHeader), &bPaused, sizeof(bool), master); } } @@ -660,8 +649,7 @@ void send_slot() if (network_on) { syncHeader.byConsoleNode = (uint8)network_slot; syncHeader.uiId = PACKET_ID_SLOT; - while (!ROLLERCommsSendData(&syncHeader, sizeof(tSyncHeader), &iSlot, sizeof(int), 21)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&syncHeader, sizeof(tSyncHeader), &iSlot, sizeof(int), 21); } } @@ -683,8 +671,7 @@ void transmitpausetoslaves() iNetPlayerIdx = 0; do { if (iNode != master && net_players[iNetPlayerIdx]) { - while (!ROLLERCommsSendData(&syncHeader, sizeof(tSyncHeader), &bPaused, sizeof(bool), iNode)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&syncHeader, sizeof(tSyncHeader), &bPaused, sizeof(bool), iNode); } ++iNetPlayerIdx; ++iNode; @@ -1145,19 +1132,15 @@ void do_sync_stuff() int iCarIdx; // eax int *pTestMultiple; // edx uint32 uiSyncData2; // ebx - int iSendDataSuccess2; // eax uint8 byConsoleNode; // al int *pTestMini; // edx int i; // eax uint32 uiSyncData; // ebx - int iSendDataSuccess; // eax + int iSyncBudget = 16; iSyncPtr = syncptr; if (net_type) { - do { - if (!syncleft) - break; - + while (syncleft && iSyncBudget-- > 0) { // Prepare sync header byConsoleNode = (uint8)wConsoleNode; in_header.uiId = 0x686C6366; // fclh @@ -1173,16 +1156,18 @@ void do_sync_stuff() } syncptr = iSyncPtr; - // Send data - iSendDataSuccess = ROLLERCommsSendData(&in_header, 12, test_mini, 8, syncnode); + // Queue data; if the destination queue is full, resume on the next tick. + if (!ROLLERCommsQueueSend(&in_header, 12, test_mini, 8, syncnode)) + break; // Advance state iSyncPtr = ((uint16)syncptr + 1) & 0x1FF; // ensure this index doesn't go beyond 511 --syncleft; ++syncframe; - } while (iSendDataSuccess); + syncptr = iSyncPtr; + } } else { - while (syncleft) { + while (syncleft && iSyncBudget-- > 0) { // Prepare sync header byConsoleNode2 = (uint8)wConsoleNode; in_header.uiId = 0x686C6366; // fclh @@ -1201,17 +1186,15 @@ void do_sync_stuff() } syncptr = iSyncPtr; - // Send data - iSendDataSuccess2 = ROLLERCommsSendData(&in_header, 12, test_multiple, 64, syncnode); + // Queue data; if the destination queue is full, resume on the next tick. + if (!ROLLERCommsQueueSend(&in_header, 12, test_multiple, 64, syncnode)) + break; // Advance state iSyncPtr = ((uint16)syncptr + 1) & 0x1FF; --syncleft; ++syncframe; - if (!iSendDataSuccess2) { - syncptr = ((uint16)syncptr + 1) & 0x1FF; // ensure this index doesn't go beyond 511 - return; - } + syncptr = iSyncPtr; } } syncptr = iSyncPtr; @@ -2045,8 +2028,7 @@ void SendPlayerInfo() //send to all nodes for (int i = 0; i < network_on; ++i) { if (wConsoleNode != i) { - while (!ROLLERCommsSendData(&p_header, sizeof(tSyncHeader), &playerInfo, sizeof(tPlayerInfoPacket), i)) - UpdateSDL(); //added by ROLLER + ROLLERCommsQueueSend(&p_header, sizeof(tSyncHeader), &playerInfo, sizeof(tPlayerInfoPacket), i); } } } @@ -2262,6 +2244,51 @@ void BroadcastNews() } } +//------------------------------------------------------------------------------------------------- + +void network_broadcast_wait_start(int iBroadcastMode, int iRepeatCount) +{ + if (iRepeatCount <= 0) + iRepeatCount = 1; + + s_iBroadcastWaitMode = iBroadcastMode; + s_iBroadcastWaitRepeatsLeft = iRepeatCount; + broadcast_mode = iBroadcastMode; +} + +//------------------------------------------------------------------------------------------------- + +int network_broadcast_wait_active(void) +{ + return s_iBroadcastWaitRepeatsLeft > 0 || broadcast_mode != 0; +} + +//------------------------------------------------------------------------------------------------- + +int network_broadcast_wait_update(void) +{ + if (!network_broadcast_wait_active()) + return -1; + + CheckNewNodes(); + BroadcastNews(); + ROLLERCommsPumpSendQueue(); + + if (broadcast_mode) + return 0; + + if (s_iBroadcastWaitRepeatsLeft > 0) + --s_iBroadcastWaitRepeatsLeft; + + if (s_iBroadcastWaitRepeatsLeft > 0) { + broadcast_mode = s_iBroadcastWaitMode; + return 0; + } + + s_iBroadcastWaitMode = 0; + return -1; +} + //------------------------------------------------------------------------------------------------- //00051E20 void remove_messages(int iClear) @@ -2390,28 +2417,16 @@ unsigned int send_broadcast(unsigned int uiBroadcastMode) if (uiBroadcastMode == 0xFFFFFE37) { uiOldTimeToStart = time_to_start; time_to_start = 0xFFFFFE37; - do { - uiBroadcastMode = -1; - if (network_on) - uiBroadcastMode = TransmitInit(); - } while (!uiBroadcastMode); + uiBroadcastMode = network_on ? (unsigned int)TransmitInit() : (unsigned int)-1; time_to_start = uiOldTimeToStart; } } else if (uiBroadcastMode <= 0xFFFFFE38) { uiOldTimeToStart = time_to_start; time_to_start = 0xFFFFFE38; - do { - uiBroadcastMode = -1; - if (network_on) - uiBroadcastMode = TransmitInit(); - } while (!uiBroadcastMode); + uiBroadcastMode = network_on ? (unsigned int)TransmitInit() : (unsigned int)-1; time_to_start = uiOldTimeToStart; } else if (uiBroadcastMode == -1) { - do { - uiBroadcastMode = -1; - if (network_on) - uiBroadcastMode = TransmitInit(); - } while (!uiBroadcastMode); + uiBroadcastMode = network_on ? (unsigned int)TransmitInit() : (unsigned int)-1; } return uiBroadcastMode; } diff --git a/PROJECTS/ROLLER/network.h b/PROJECTS/ROLLER/network.h index 64418da..7fb7fde 100644 --- a/PROJECTS/ROLLER/network.h +++ b/PROJECTS/ROLLER/network.h @@ -219,6 +219,9 @@ void SendPlayerInfo(); void prepare_net_message(int iMessageMode, int iMessageNumber); void SendAMessage(); void BroadcastNews(); +void network_broadcast_wait_start(int iBroadcastMode, int iRepeatCount); +int network_broadcast_wait_update(void); +int network_broadcast_wait_active(void); void remove_messages(int iClear); void reset_network(int iResetBroadcastMode); void clear_network_game(); diff --git a/PROJECTS/ROLLER/rollercomms.c b/PROJECTS/ROLLER/rollercomms.c index 32c5325..652de78 100644 --- a/PROJECTS/ROLLER/rollercomms.c +++ b/PROJECTS/ROLLER/rollercomms.c @@ -26,6 +26,10 @@ //------------------------------------------------------------------------------------------------- +#define SEND_QUEUE_PUMP_BUDGET_PER_NODE 16 + +//------------------------------------------------------------------------------------------------- + typedef struct { tROLLERNetAddr address; @@ -40,6 +44,20 @@ typedef struct tROLLERNetAddr transportAddress; } tPendingTransport; +typedef struct +{ + tSendQueueEntry entry; + tROLLERNetAddr destAddress; +} tQueuedSend; + +typedef struct +{ + int iReadIdx; + int iWriteIdx; + int iCount; + tQueuedSend aEntries[SEND_QUEUE_DEPTH]; +} tSendQueue; + static struct { bool bInitialized; @@ -65,6 +83,8 @@ static tROLLERNetAddr s_peerAddr; static uint32_t s_uiLocalIPOverride = 0; // 0 = auto-detect static tPendingTransport s_pendingTransports[ROLLER_MAX_NODES]; static int s_iPendingTransports = 0; +static tSendQueue s_aSendQueues[ROLLER_MAX_NODES]; +static SDL_Mutex *s_pSendQueueMutex = NULL; //------------------------------------------------------------------------------------------------- @@ -288,6 +308,58 @@ static int SendPacketToIPv4(uint32_t uiIPAddress, uint16_t unPort, const uint8_t //------------------------------------------------------------------------------------------------- +static int EnsureSendQueueMutex(void) +{ + if (s_pSendQueueMutex) + return 1; + + s_pSendQueueMutex = SDL_CreateMutex(); + if (!s_pSendQueueMutex) { + SDL_Log("[NET-QUEUE] failed to create send queue mutex: %s", SDL_GetError()); + return 0; + } + return 1; +} + +static void ClearSendQueuesLocked(void) +{ + memset(s_aSendQueues, 0, sizeof(s_aSendQueues)); +} + +static void ClearSendQueues(void) +{ + if (!EnsureSendQueueMutex()) + return; + + SDL_LockMutex(s_pSendQueueMutex); + ClearSendQueuesLocked(); + SDL_UnlockMutex(s_pSendQueueMutex); +} + +static int QueueSendPacketLocked(const tSendQueueEntry *pEntry, + const tROLLERNetAddr *pDestAddress, + int iDestNode) +{ + if (!pEntry || !pDestAddress || iDestNode < 0 || iDestNode >= ROLLER_MAX_NODES) + return 0; + + tSendQueue *pQueue = &s_aSendQueues[iDestNode]; + if (pQueue->iCount >= SEND_QUEUE_DEPTH) { + SDL_Log("[NET-QUEUE] send queue overflow for node=%d depth=%d", + iDestNode, pQueue->iCount); + return 0; + } + + tQueuedSend *pQueuedSend = &pQueue->aEntries[pQueue->iWriteIdx]; + pQueuedSend->entry = *pEntry; + pQueuedSend->destAddress = *pDestAddress; + pQueue->iWriteIdx = (pQueue->iWriteIdx + 1) % SEND_QUEUE_DEPTH; + pQueue->iCount++; + return 1; +} + +//------------------------------------------------------------------------------------------------- + static int IsLoopbackIPv4(uint32_t uiIPAddress); static int BroadcastPacketToIPv4(uint32_t uiIPAddress, uint16_t unPort, const uint8_t *pPacket, int iPacketSize) @@ -473,6 +545,7 @@ int ROLLERCommsInitSystem(unsigned int uiMaxPackets) memset(&g_commsState, 0, sizeof(g_commsState)); s_iPendingTransports = 0; g_commsState.listenSocket = INVALID_SOCKET; + ClearSendQueues(); g_commsState.listenSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (g_commsState.listenSocket == INVALID_SOCKET) { @@ -586,6 +659,7 @@ void ROLLERCommsUnInitSystem() CleanupSockets(); memset(&g_commsState, 0, sizeof(g_commsState)); s_iPendingTransports = 0; + ClearSendQueues(); } //------------------------------------------------------------------------------------------------- @@ -637,6 +711,106 @@ int ROLLERCommsSendData( //------------------------------------------------------------------------------------------------- +int ROLLERCommsQueueSend( + const void *pHeader, + int iHeaderSize, + const void *pData, + int iDataSize, + int iDestNode) +{ + if (!g_commsState.bInitialized) { + return 0; + } + + tSendQueueEntry entry; + int iTotalSize = 0; + memset(&entry, 0, sizeof(entry)); + if (!BuildPacket(entry.abPacket, &iTotalSize, pHeader, iHeaderSize, pData, iDataSize)) { + return 0; + } + entry.unHeaderSize = (uint16)iHeaderSize; + entry.unDataSize = (uint16)iDataSize; + + if (!EnsureSendQueueMutex()) + return 0; + + SDL_LockMutex(s_pSendQueueMutex); + + int iQueued = 1; + if (iDestNode == 21) { + for (int i = 0; i < g_commsState.iActiveNodes; i++) { + if (i != g_commsState.iConsoleNode && g_commsState.nodes[i].bActive) { + if (!QueueSendPacketLocked(&entry, &g_commsState.nodes[i].transportAddress, i)) + iQueued = 0; + } + } + } else if (iDestNode < 0 || iDestNode >= ROLLER_MAX_NODES || + !g_commsState.nodes[iDestNode].bActive) { + iQueued = 0; + } else if (iDestNode != g_commsState.iConsoleNode) { + iQueued = QueueSendPacketLocked(&entry, + &g_commsState.nodes[iDestNode].transportAddress, + iDestNode); + } + + SDL_UnlockMutex(s_pSendQueueMutex); + return iQueued; +} + +//------------------------------------------------------------------------------------------------- + +void ROLLERCommsPumpSendQueue(void) +{ + if (!g_commsState.bInitialized || !s_pSendQueueMutex) + return; + + SDL_LockMutex(s_pSendQueueMutex); + + for (int iNode = 0; iNode < ROLLER_MAX_NODES; iNode++) { + tSendQueue *pQueue = &s_aSendQueues[iNode]; + int iBudget = SEND_QUEUE_PUMP_BUDGET_PER_NODE; + + while (pQueue->iCount > 0 && iBudget-- > 0) { + tQueuedSend *pQueuedSend = &pQueue->aEntries[pQueue->iReadIdx]; + int iPacketSize = pQueuedSend->entry.unHeaderSize + pQueuedSend->entry.unDataSize; + if (!SendPacketToIPv4(pQueuedSend->destAddress.uiIPAddress, + pQueuedSend->destAddress.unPort, + pQueuedSend->entry.abPacket, + iPacketSize)) { + break; + } + + pQueue->iReadIdx = (pQueue->iReadIdx + 1) % SEND_QUEUE_DEPTH; + pQueue->iCount--; + } + } + + SDL_UnlockMutex(s_pSendQueueMutex); +} + +//------------------------------------------------------------------------------------------------- + +int ROLLERCommsSendQueueDepth(int iDestNode) +{ + int iDepth = 0; + + if (!EnsureSendQueueMutex()) + return 0; + + SDL_LockMutex(s_pSendQueueMutex); + if (iDestNode == 21) { + for (int i = 0; i < ROLLER_MAX_NODES; i++) + iDepth += s_aSendQueues[i].iCount; + } else if (iDestNode >= 0 && iDestNode < ROLLER_MAX_NODES) { + iDepth = s_aSendQueues[iDestNode].iCount; + } + SDL_UnlockMutex(s_pSendQueueMutex); + + return iDepth; +} + +//------------------------------------------------------------------------------------------------- + int ROLLERCommsBroadcastData( const void *pHeader, int iHeaderSize, @@ -1101,7 +1275,7 @@ void ROLLERclrrx(void) void ROLLERclrtx(void) { -// Clear transmit buffer - could implement if needed + ClearSendQueues(); } //------------------------------------------------------------------------------------------------- diff --git a/PROJECTS/ROLLER/rollercomms.h b/PROJECTS/ROLLER/rollercomms.h index b411964..525347f 100644 --- a/PROJECTS/ROLLER/rollercomms.h +++ b/PROJECTS/ROLLER/rollercomms.h @@ -9,6 +9,7 @@ #define ROLLER_DEFAULT_PORT 7777 #define ROLLER_MAX_PACKET_SIZE 1024 #define ROLLER_MAX_IFACES 8 +#define SEND_QUEUE_DEPTH 64 typedef struct { @@ -25,6 +26,14 @@ typedef struct uint64 ullReserved; // Must be zero — pads to 16 bytes to match _NETNOW_NODE_ADDR } tROLLERNetAddr; +//------------------------------------------------------------------------------------------------- + +typedef struct { + uint16 unHeaderSize; + uint16 unDataSize; + uint8 abPacket[ROLLER_MAX_PACKET_SIZE]; +} tSendQueueEntry; + //------------------------------------------------------------------------------------------------- // Pre-init configuration (call before InitSystem) void ROLLERCommsSetLocalPort(uint16_t unPort); @@ -62,6 +71,14 @@ int ROLLERCommsSendData( const void *pData, int iDataSize, int iDestNode); +int ROLLERCommsQueueSend( + const void *pHeader, + int iHeaderSize, + const void *pData, + int iDataSize, + int iDestNode); +void ROLLERCommsPumpSendQueue(void); +int ROLLERCommsSendQueueDepth(int iDestNode); int ROLLERCommsBroadcastData( const void *pHeader, int iHeaderSize, diff --git a/PROJECTS/ROLLER/sound.c b/PROJECTS/ROLLER/sound.c index 56250da..691d29c 100644 --- a/PROJECTS/ROLLER/sound.c +++ b/PROJECTS/ROLLER/sound.c @@ -10,6 +10,7 @@ #include "roller.h" #include "control.h" #include "network.h" +#include "rollercomms.h" #include "replay.h" #include "function.h" #include "tower.h" @@ -1168,7 +1169,9 @@ void tick_clock_step(void) int iTickAdvance = 1; if (network_on && syncleft) { + ROLLERCommsPumpSendQueue(); do_sync_stuff(); + ROLLERCommsPumpSendQueue(); return; } @@ -1252,6 +1255,9 @@ void tick_clock_step(void) } } + if (network_on) + ROLLERCommsPumpSendQueue(); + if (!frontend_on && iTickAdvance != 0) SDL_AddAtomicInt(&iTicksPending, iTickAdvance); }