diff --git a/core/deps/ggpo/include/ggponet.h b/core/deps/ggpo/include/ggponet.h index bd82894ce..39ed8fe9c 100644 --- a/core/deps/ggpo/include/ggponet.h +++ b/core/deps/ggpo/include/ggponet.h @@ -112,7 +112,8 @@ typedef struct GGPOLocalEndpoint { GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_DROPPED, 8) \ GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_PLAYER_DISCONNECTED, 9) \ GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_TOO_MANY_SPECTATORS, 10) \ - GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INVALID_REQUEST, 11) + GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INVALID_REQUEST, 11) \ + GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_SIZE_DIFF, 12) #define GGPO_ERRORLIST_ENTRY(name, value) name = value, typedef enum { diff --git a/core/deps/ggpo/lib/ggpo/ggpo_types.h b/core/deps/ggpo/lib/ggpo/ggpo_types.h index 3352da7b2..e74d19e70 100644 --- a/core/deps/ggpo/lib/ggpo/ggpo_types.h +++ b/core/deps/ggpo/lib/ggpo/ggpo_types.h @@ -35,6 +35,17 @@ typedef char int8; typedef short int16; typedef int int32; +#include "ggponet.h" +#include + +class GGPOException : public std::runtime_error { +public: + GGPOException(const std::string& what, GGPOErrorCode ggpoError) + : std::runtime_error(what), ggpoError(ggpoError) {} + + GGPOErrorCode ggpoError; +}; + /* * Additional headers */ @@ -48,8 +59,6 @@ typedef int int32; #include "log.h" - - /* * Macros */ diff --git a/core/deps/ggpo/lib/ggpo/input_queue.cpp b/core/deps/ggpo/lib/ggpo/input_queue.cpp index 65cb26463..3441ef70c 100644 --- a/core/deps/ggpo/lib/ggpo/input_queue.cpp +++ b/core/deps/ggpo/lib/ggpo/input_queue.cpp @@ -218,7 +218,8 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number) { Log("adding delayed input frame number %d to queue.\n", frame_number); - ASSERT(input.size == _prediction.size); + if (input.size != _prediction.size) + throw GGPOException("Input size differs from peer", GGPO_ERRORCODE_INPUT_SIZE_DIFF); ASSERT(_last_added_frame == GameInput::NullFrame || frame_number == _last_added_frame + 1); diff --git a/core/deps/ggpo/lib/ggpo/main.cpp b/core/deps/ggpo/lib/ggpo/main.cpp index 88dd4fa7e..6b4f435e5 100644 --- a/core/deps/ggpo/lib/ggpo/main.cpp +++ b/core/deps/ggpo/lib/ggpo/main.cpp @@ -35,9 +35,8 @@ ggpo_log(GGPOSession *ggpo, const char *fmt, ...) void ggpo_logv(GGPOSession *ggpo, const char *fmt, va_list args) { - if (ggpo) { + if (ggpo) ggpo->Logv(fmt, args); - } } GGPOErrorCode @@ -48,12 +47,17 @@ ggpo_start_session(GGPOSession **session, int input_size, unsigned short localport) { - *session= (GGPOSession *)new Peer2PeerBackend(cb, - game, - localport, - num_players, - input_size); - return GGPO_OK; + try { + *session= (GGPOSession *)new Peer2PeerBackend(cb, + game, + localport, + num_players, + input_size); + return GGPO_OK; + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_start_session: %s", e.what()); + return e.ggpoError; + } } GGPOErrorCode @@ -61,10 +65,14 @@ ggpo_add_player(GGPOSession *ggpo, GGPOPlayer *player, GGPOPlayerHandle *handle) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->AddPlayer(player, handle); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_add_player: %s", e.what()); + return e.ggpoError; } - return ggpo->AddPlayer(player, handle); } @@ -77,8 +85,13 @@ ggpo_start_synctest(GGPOSession **ggpo, int input_size, int frames) { - *ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players); - return GGPO_OK; + try { + *ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players); + return GGPO_OK; + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_start_synctest: %s", e.what()); + return e.ggpoError; + } } GGPOErrorCode @@ -86,19 +99,27 @@ ggpo_set_frame_delay(GGPOSession *ggpo, GGPOPlayerHandle player, int frame_delay) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->SetFrameDelay(player, frame_delay); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_set_frame_delay: %s", e.what()); + return e.ggpoError; } - return ggpo->SetFrameDelay(player, frame_delay); } GGPOErrorCode ggpo_idle(GGPOSession *ggpo, int timeout) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->DoPoll(timeout); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_idle: %s", e.what()); + return e.ggpoError; } - return ggpo->DoPoll(timeout); } GGPOErrorCode @@ -107,10 +128,14 @@ ggpo_add_local_input(GGPOSession *ggpo, void *values, int size) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->AddLocalInput(player, values, size); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_add_local_input: %s", e.what()); + return e.ggpoError; } - return ggpo->AddLocalInput(player, values, size); } GGPOErrorCode @@ -119,37 +144,53 @@ ggpo_synchronize_input(GGPOSession *ggpo, int size, int *disconnect_flags) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->SyncInput(values, size, disconnect_flags); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_synchronize_input: %s", e.what()); + return e.ggpoError; } - return ggpo->SyncInput(values, size, disconnect_flags); } GGPOErrorCode ggpo_disconnect_player(GGPOSession *ggpo, GGPOPlayerHandle player) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->DisconnectPlayer(player); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_disconnect_player: %s", e.what()); + return e.ggpoError; } - return ggpo->DisconnectPlayer(player); } GGPOErrorCode ggpo_advance_frame(GGPOSession *ggpo) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->IncrementFrame(); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_advance_frame: %s", e.what()); + return e.ggpoError; } - return ggpo->IncrementFrame(); } GGPOErrorCode ggpo_client_chat(GGPOSession *ggpo, char *text) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->Chat(text); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_client_chat: %s", e.what()); + return e.ggpoError; } - return ggpo->Chat(text); } GGPOErrorCode @@ -157,10 +198,14 @@ ggpo_get_network_stats(GGPOSession *ggpo, GGPOPlayerHandle player, GGPONetworkStats *stats) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->GetNetworkStats(stats, player); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_get_network_stats: %s", e.what()); + return e.ggpoError; } - return ggpo->GetNetworkStats(stats, player); } @@ -177,19 +222,27 @@ ggpo_close_session(GGPOSession *ggpo) GGPOErrorCode ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->SetDisconnectTimeout(timeout); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_set_disconnect_timeout: %s", e.what()); + return e.ggpoError; } - return ggpo->SetDisconnectTimeout(timeout); } GGPOErrorCode ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout) { - if (!ggpo) { + if (!ggpo) return GGPO_ERRORCODE_INVALID_SESSION; + try { + return ggpo->SetDisconnectNotifyStart(timeout); + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_set_disconnect_notify_start: %s", e.what()); + return e.ggpoError; } - return ggpo->SetDisconnectNotifyStart(timeout); } GGPOErrorCode ggpo_start_spectating(GGPOSession **session, @@ -201,13 +254,18 @@ GGPOErrorCode ggpo_start_spectating(GGPOSession **session, char *host_ip, unsigned short host_port) { - *session= (GGPOSession *)new SpectatorBackend(cb, - game, - local_port, - num_players, - input_size, - host_ip, - host_port); - return GGPO_OK; + try { + *session= (GGPOSession *)new SpectatorBackend(cb, + game, + local_port, + num_players, + input_size, + host_ip, + host_port); + return GGPO_OK; + } catch (const GGPOException& e) { + Log("GGPOException in ggpo_start_spectating: %s", e.what()); + return e.ggpoError; + } } diff --git a/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp b/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp index f180b1d6a..77ffc5e09 100644 --- a/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp +++ b/core/deps/ggpo/lib/ggpo/network/udp_proto.cpp @@ -478,7 +478,6 @@ UdpProtocol::OnSyncRequest(UdpMsg *msg, int len) return false; } // FIXME - //bool requeueSyncRequest = _last_send_time && _last_send_time + 20 < Platform::GetCurrentTimeMS(); if (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS && msg->hdr.sequence_number == 0) { Log("Sync request 0 received... Re-queueing sync packet.\n"); SendSyncRequest(); diff --git a/core/network/ggpo.cpp b/core/network/ggpo.cpp index f162792f5..357e4f55e 100644 --- a/core/network/ggpo.cpp +++ b/core/network/ggpo.cpp @@ -450,7 +450,12 @@ void getInput(MapleInputState inputState[4]) u32 inputSize = sizeof(u32) + config::GGPOAnalogAxes; std::vector inputs(inputSize * MAX_PLAYERS); // should not call any callback - ggpo_synchronize_input(ggpoSession, (void *)&inputs[0], inputs.size(), nullptr); + GGPOErrorCode error = ggpo_synchronize_input(ggpoSession, (void *)&inputs[0], inputs.size(), nullptr); + if (error != GGPO_OK) + { + stopSession(); + throw FlycastException("GGPO error"); + } for (int player = 0; player < MAX_PLAYERS; player++) { @@ -486,10 +491,20 @@ bool nextFrame() if (ggpoSession == nullptr) return false; // will call save_game_state - ggpo_advance_frame(ggpoSession); + GGPOErrorCode error = ggpo_advance_frame(ggpoSession); // may rollback - ggpo_idle(ggpoSession, 0); + if (error == GGPO_OK) + error = ggpo_idle(ggpoSession, 0); + if (error != GGPO_OK) + { + stopSession(); + if (error == GGPO_ERRORCODE_INPUT_SIZE_DIFF) + throw FlycastException("GGPO analog settings are different from peer"); + else if (error != GGPO_OK) + throw FlycastException("GGPO error"); + } + // may call save_game_state do { u32 input = ~kcode[localPlayerNum]; @@ -519,8 +534,7 @@ bool nextFrame() WARN_LOG(NETWORK, "ggpo_add_local_input failed %d", result); if (result != GGPO_ERRORCODE_PREDICTION_THRESHOLD) { - ggpo_close_session(ggpoSession); - ggpoSession = nullptr; + stopSession(); throw FlycastException("GGPO error"); } std::this_thread::sleep_for(std::chrono::milliseconds(5));