/** * netplay_post_frame: * @netplay : pointer to netplay object * * Post-frame for Netplay. * We check if we have new input and replay from recorded input. * Call this after running retro_run(). **/ void netplay_post_frame(netplay_t *netplay) { size_t i; retro_assert(netplay); netplay_update_unread_ptr(netplay); netplay_sync_post_frame(netplay, false); for (i = 0; i < netplay->connections_size; i++) { struct netplay_connection *connection = &netplay->connections[i]; if (connection->active && !netplay_send_flush(&connection->send_packet_buffer, connection->fd, false)) netplay_hangup(netplay, connection); } /* If we're disconnected, deinitialize */ if (!netplay->is_server && !netplay->connections[0].active) netplay_disconnect(netplay); }
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) { bool ret = true; if (in_netplay) return true; in_netplay = true; if (!netplay_data) { switch (state) { case RARCH_NETPLAY_CTL_ENABLE_SERVER: netplay_enabled = true; netplay_is_client = false; goto done; case RARCH_NETPLAY_CTL_ENABLE_CLIENT: netplay_enabled = true; netplay_is_client = true; break; case RARCH_NETPLAY_CTL_DISABLE: netplay_enabled = false; goto done; case RARCH_NETPLAY_CTL_IS_ENABLED: ret = netplay_enabled; goto done; case RARCH_NETPLAY_CTL_IS_DATA_INITED: ret = false; goto done; default: goto done; } } switch (state) { case RARCH_NETPLAY_CTL_ENABLE_SERVER: case RARCH_NETPLAY_CTL_ENABLE_CLIENT: case RARCH_NETPLAY_CTL_IS_DATA_INITED: goto done; case RARCH_NETPLAY_CTL_DISABLE: ret = false; goto done; case RARCH_NETPLAY_CTL_IS_ENABLED: goto done; case RARCH_NETPLAY_CTL_POST_FRAME: netplay_post_frame(netplay_data); break; case RARCH_NETPLAY_CTL_PRE_FRAME: ret = netplay_pre_frame(netplay_data); goto done; case RARCH_NETPLAY_CTL_FLIP_PLAYERS: { bool *state = (bool*)data; if (*state) netplay_flip_users(netplay_data); } break; case RARCH_NETPLAY_CTL_FULLSCREEN_TOGGLE: { bool *state = (bool*)data; if (*state) command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); } break; case RARCH_NETPLAY_CTL_PAUSE: netplay_frontend_paused(netplay_data, true); break; case RARCH_NETPLAY_CTL_UNPAUSE: netplay_frontend_paused(netplay_data, false); break; case RARCH_NETPLAY_CTL_LOAD_SAVESTATE: netplay_load_savestate(netplay_data, (retro_ctx_serialize_info_t*)data, true); break; case RARCH_NETPLAY_CTL_DISCONNECT: ret = netplay_disconnect(netplay_data); goto done; default: case RARCH_NETPLAY_CTL_NONE: ret = false; } done: in_netplay = false; return ret; }
/** * netplay_pre_frame: * @netplay : pointer to netplay object * * Pre-frame for Netplay. * Call this before running retro_run(). * * Returns: true (1) if the frontend is cleared to emulate the frame, false (0) * if we're stalled or paused **/ bool netplay_pre_frame(netplay_t *netplay) { bool sync_stalled; settings_t *settings = config_get_ptr(); retro_assert(netplay); if (settings->bools.netplay_public_announce) { reannounce++; if ((netplay->is_server || is_mitm) && (reannounce % 600 == 0)) netplay_announce(); } else { /* Make sure that if announcement is turned on mid-game, it gets announced */ reannounce = -1; } /* FIXME: This is an ugly way to learn we're not paused anymore */ if (netplay->local_paused) netplay_frontend_paused(netplay, false); if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) { /* Are we ready now? */ netplay_try_init_serialization(netplay); } if (netplay->is_server && !settings->bools.netplay_use_mitm_server) { /* Advertise our server */ netplay_lan_ad_server(netplay); /* NAT traversal if applicable */ if (netplay->nat_traversal && !netplay->nat_traversal_task_oustanding && netplay->nat_traversal_state.request_outstanding && !netplay->nat_traversal_state.have_inet4) { struct timeval tmptv = {0}; fd_set fds = netplay->nat_traversal_state.fds; if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0) natt_read(&netplay->nat_traversal_state); #ifndef HAVE_SOCKET_LEGACY if (!netplay->nat_traversal_state.request_outstanding || netplay->nat_traversal_state.have_inet4) netplay_announce_nat_traversal(netplay); #endif } } sync_stalled = !netplay_sync_pre_frame(netplay); /* If we're disconnected, deinitialize */ if (!netplay->is_server && !netplay->connections[0].active) { netplay_disconnect(netplay); return true; } if (sync_stalled || ((!netplay->is_server || (netplay->connected_players>1)) && (netplay->stall || netplay->remote_paused))) { /* We may have received data even if we're stalled, so run post-frame * sync */ netplay_sync_post_frame(netplay, true); return false; } return true; }
/** * netplay_driver_ctl * * Frontend access to Netplay functionality */ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) { bool ret = true; if (in_netplay) return true; in_netplay = true; if (!netplay_data) { switch (state) { case RARCH_NETPLAY_CTL_ENABLE_SERVER: netplay_enabled = true; netplay_is_client = false; goto done; case RARCH_NETPLAY_CTL_ENABLE_CLIENT: netplay_enabled = true; netplay_is_client = true; break; case RARCH_NETPLAY_CTL_DISABLE: netplay_enabled = false; goto done; case RARCH_NETPLAY_CTL_IS_ENABLED: ret = netplay_enabled; goto done; case RARCH_NETPLAY_CTL_IS_DATA_INITED: ret = false; goto done; case RARCH_NETPLAY_CTL_IS_SERVER: ret = netplay_enabled && !netplay_is_client; goto done; case RARCH_NETPLAY_CTL_IS_CONNECTED: ret = false; goto done; default: goto done; } } switch (state) { case RARCH_NETPLAY_CTL_ENABLE_SERVER: case RARCH_NETPLAY_CTL_ENABLE_CLIENT: case RARCH_NETPLAY_CTL_IS_DATA_INITED: goto done; case RARCH_NETPLAY_CTL_DISABLE: ret = false; goto done; case RARCH_NETPLAY_CTL_IS_ENABLED: goto done; case RARCH_NETPLAY_CTL_IS_SERVER: ret = netplay_enabled && !netplay_is_client; goto done; case RARCH_NETPLAY_CTL_IS_CONNECTED: ret = netplay_data->is_connected; goto done; case RARCH_NETPLAY_CTL_POST_FRAME: netplay_post_frame(netplay_data); break; case RARCH_NETPLAY_CTL_PRE_FRAME: ret = netplay_pre_frame(netplay_data); goto done; case RARCH_NETPLAY_CTL_GAME_WATCH: netplay_toggle_play_spectate(netplay_data); break; case RARCH_NETPLAY_CTL_PAUSE: netplay_frontend_paused(netplay_data, true); break; case RARCH_NETPLAY_CTL_UNPAUSE: netplay_frontend_paused(netplay_data, false); break; case RARCH_NETPLAY_CTL_LOAD_SAVESTATE: netplay_load_savestate(netplay_data, (retro_ctx_serialize_info_t*)data, true); break; case RARCH_NETPLAY_CTL_RESET: netplay_core_reset(netplay_data); break; case RARCH_NETPLAY_CTL_DISCONNECT: ret = netplay_disconnect(netplay_data); goto done; case RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL: netplay_data->nat_traversal_task_oustanding = false; #ifndef HAVE_SOCKET_LEGACY netplay_announce_nat_traversal(netplay_data); #endif goto done; case RARCH_NETPLAY_CTL_DESYNC_PUSH: netplay_data->desync++; break; case RARCH_NETPLAY_CTL_DESYNC_POP: if (netplay_data->desync) { netplay_data->desync--; if (!netplay_data->desync) netplay_load_savestate(netplay_data, NULL, true); } break; default: case RARCH_NETPLAY_CTL_NONE: ret = false; } done: in_netplay = false; return ret; }