diff --git a/autosave.c b/autosave.c index 6e0fdd79ec..1b2d37db04 100644 --- a/autosave.c +++ b/autosave.c @@ -122,3 +122,23 @@ void autosave_free(autosave_t *handle) free(handle->buffer); free(handle); } + +void lock_autosave(void) +{ + for (unsigned i = 0; i < sizeof(g_extern.autosave)/sizeof(g_extern.autosave[0]); i++) + { + if (g_extern.autosave[i]) + autosave_lock(g_extern.autosave[i]); + } +} + +void unlock_autosave(void) +{ + for (unsigned i = 0; i < sizeof(g_extern.autosave)/sizeof(g_extern.autosave[0]); i++) + { + if (g_extern.autosave[i]) + autosave_unlock(g_extern.autosave[i]); + } +} + + diff --git a/autosave.h b/autosave.h index 59f420184b..4815e4610f 100644 --- a/autosave.h +++ b/autosave.h @@ -27,5 +27,7 @@ void autosave_lock(autosave_t *handle); void autosave_unlock(autosave_t *handle); void autosave_free(autosave_t *handle); +void lock_autosave(void); +void unlock_autosave(void); #endif diff --git a/general.h b/general.h index fe6abd0822..8ced5222f2 100644 --- a/general.h +++ b/general.h @@ -43,6 +43,8 @@ #define MAX_PLAYERS 5 #define MAX_BINDS 25 // Needs to be increased every time there are new binds added. #define SSNES_NO_JOYPAD 0xFFFF + +// All config related settings go here. struct settings { struct @@ -108,6 +110,7 @@ enum ssnes_game_type SSNES_CART_SUFAMI, }; +// All run-time- / command line flag-related globals go here. struct global { bool verbose; @@ -166,19 +169,24 @@ struct global msg_queue_t *msg_queue; + // Rewind support. state_manager_t *state_manager; void *state_buf; bool frame_is_reverse; + // Movie record support bsv_movie_t *bsv_movie; char bsv_movie_path[256]; bool bsv_movie_end; bool bsv_movie_playback; + // Pausing support bool is_paused; + // Autosave support. autosave_t *autosave[2]; + // Netplay. netplay_t *netplay; char netplay_server[256]; bool netplay_enable; @@ -186,6 +194,7 @@ struct global unsigned netplay_sync_frames; uint16_t netplay_port; + // FFmpeg record. #ifdef HAVE_FFMPEG ffemu_t *rec; char record_path[256]; diff --git a/netplay.c b/netplay.c index 1237a5c4ca..9ae554d27d 100644 --- a/netplay.c +++ b/netplay.c @@ -18,6 +18,7 @@ #include "netplay.h" #include "general.h" #include "dynamic.h" +#include "autosave.h" #include #include #include @@ -387,6 +388,27 @@ bool netplay_is_alive(netplay_t *handle) return handle->has_connection; } +static bool send_chunk(netplay_t *handle) +{ + const struct sockaddr *addr = NULL; + if (handle->addr) + addr = handle->addr->ai_addr; + else if (handle->has_client_addr) + addr = (const struct sockaddr*)&handle->their_addr; + + if (addr) + { + if (sendto(handle->udp_fd, CONST_CAST handle->packet_buffer, sizeof(handle->packet_buffer), 0, addr, sizeof(struct sockaddr)) != sizeof(handle->packet_buffer)) + { + SSNES_WARN("Netplay connection hung up. Will continue without netplay.\n"); + handle->has_connection = false; + return false; + } + } + return true; +} + +#define MAX_RETRIES 16 static int poll_input(netplay_t *handle, bool block) { @@ -395,19 +417,30 @@ static int poll_input(netplay_t *handle, bool block) FD_SET(handle->udp_fd, &fds); struct timeval tv = { - .tv_sec = block ? 5 : 0, - .tv_usec = 0 + .tv_sec = 0, + .tv_usec = block ? 500000 : 0 }; - if (select(handle->udp_fd + 1, &fds, NULL, NULL, &tv) < 0) + int i = 0; + do + { + if (select(handle->udp_fd + 1, &fds, NULL, NULL, &tv) < 0) + return -1; + + if (FD_ISSET(handle->udp_fd, &fds)) + return 1; + + if (block && !send_chunk(handle)) + { + SSNES_WARN("Netplay connection hung up. Will continue without netplay.\n"); + handle->has_connection = false; + return false; + } + + } while (i++ < MAX_RETRIES && block); + + if (block) return -1; - - if (block && !FD_ISSET(handle->udp_fd, &fds)) - return -1; - - if (FD_ISSET(handle->udp_fd, &fds)) - return 1; - return 0; } @@ -431,20 +464,11 @@ static bool get_self_input_state(netplay_t *handle) handle->packet_buffer[(UDP_FRAME_PACKETS - 1) * 2] = htonl(handle->frame_count); handle->packet_buffer[(UDP_FRAME_PACKETS - 1) * 2 + 1] = htonl(state); - const struct sockaddr *addr = NULL; - if (handle->addr) - addr = handle->addr->ai_addr; - else if (handle->has_client_addr) - addr = (const struct sockaddr*)&handle->their_addr; - - if (addr) + if (!send_chunk(handle)) { - if (sendto(handle->udp_fd, CONST_CAST handle->packet_buffer, sizeof(handle->packet_buffer), 0, addr, sizeof(struct sockaddr)) != sizeof(handle->packet_buffer)) - { - SSNES_WARN("Netplay connection hung up. Will continue without netplay.\n"); - handle->has_connection = false; - return false; - } + SSNES_WARN("Netplay connection hung up. Will continue without netplay.\n"); + handle->has_connection = false; + return false; } ptr->self_state = state; @@ -647,7 +671,9 @@ void netplay_post_frame(netplay_t *handle) while (handle->tmp_ptr != handle->self_ptr) { psnes_serialize(handle->buffer[handle->tmp_ptr].state, handle->state_size); + lock_autosave(); psnes_run(); + unlock_autosave(); handle->tmp_ptr = NEXT_PTR(handle->tmp_ptr); } handle->other_ptr = handle->read_ptr; diff --git a/ssnes.c b/ssnes.c index 35d61d959b..0f6248f764 100644 --- a/ssnes.c +++ b/ssnes.c @@ -871,24 +871,6 @@ static void deinit_autosave(void) } } -static void lock_autosave(void) -{ - for (unsigned i = 0; i < sizeof(g_extern.autosave)/sizeof(g_extern.autosave[0]); i++) - { - if (g_extern.autosave[i]) - autosave_lock(g_extern.autosave[i]); - } -} - -static void unlock_autosave(void) -{ - for (unsigned i = 0; i < sizeof(g_extern.autosave)/sizeof(g_extern.autosave[0]); i++) - { - if (g_extern.autosave[i]) - autosave_unlock(g_extern.autosave[i]); - } -} - static void fill_pathnames(void) { switch (g_extern.game_type)