From 4d1e74997749bca7744c1bbe78225e76f57a260c Mon Sep 17 00:00:00 2001 From: Tom Pratt Date: Mon, 18 May 2026 21:31:39 +0200 Subject: [PATCH] WithSession helper function Handles the repeated boiler plate of using a weak reference to NetplaySession from NetplayUICallbacks --- .../jni/NetPlay/NetPlayUICallbacks.cpp | 321 +++++++----------- .../Android/jni/NetPlay/NetPlayUICallbacks.h | 12 + 2 files changed, 129 insertions(+), 204 deletions(-) diff --git a/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp b/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp index 9f9c406846..de119b43c8 100644 --- a/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp +++ b/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp @@ -68,17 +68,12 @@ NetPlayUICallbacks::NetPlayUICallbacks(jobject netplay_session, if ((state == Core::State::Uninitialized || state == Core::State::Stopping) && !m_got_stop_request) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - auto* client = reinterpret_cast( - env->GetLongField(netplay_session, IDCache::GetNetPlayClientPointer())); - if (client) - client->RequestStopGame(); - - env->DeleteLocalRef(netplay_session); + WithSession([](JNIEnv* env, jobject session) { + auto* client = reinterpret_cast( + env->GetLongField(session, IDCache::GetNetPlayClientPointer())); + if (client) + client->RequestStopGame(); + }); } }); } @@ -99,14 +94,10 @@ void NetPlayUICallbacks::BootGame(const std::string& filename, { m_got_stop_request = false; - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnBootGame(), ToJString(env, filename), - reinterpret_cast(boot_session_data.release())); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnBootGame(), ToJString(env, filename), + reinterpret_cast(boot_session_data.release())); + }); } void NetPlayUICallbacks::StopGame() @@ -116,13 +107,9 @@ void NetPlayUICallbacks::StopGame() m_got_stop_request = true; - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnStopGame()); - env->DeleteLocalRef(netplay_session); + WithSession([](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnStopGame()); + }); } // Only used by Qt UI code, never by the C++ core. On Android, hosting state @@ -131,56 +118,43 @@ bool NetPlayUICallbacks::IsHosting() const { return false; } void NetPlayUICallbacks::Update() { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; + WithSession([](JNIEnv* env, jobject session) { + auto* client = reinterpret_cast( + env->GetLongField(session, IDCache::GetNetPlayClientPointer())); + if (!client) + return; - auto* client = reinterpret_cast( - env->GetLongField(netplay_session, IDCache::GetNetPlayClientPointer())); - if (!client) - { - env->DeleteLocalRef(netplay_session); - return; - } + const std::vector players = client->GetPlayers(); - const std::vector players = client->GetPlayers(); + jobjectArray player_array = env->NewObjectArray( + static_cast(players.size()), IDCache::GetNetplayPlayerClass(), nullptr); - jobjectArray player_array = - env->NewObjectArray(static_cast(players.size()), IDCache::GetNetplayPlayerClass(), nullptr); + for (jsize i = 0; i < static_cast(players.size()); i++) + { + const NetPlay::Player* player = players[i]; + const std::string mapping = NetPlay::GetPlayerMappingString( + player->pid, client->GetPadMapping(), client->GetGBAConfig(), + client->GetWiimoteMapping()); + jobject player_obj = env->NewObject( + IDCache::GetNetplayPlayerClass(), IDCache::GetNetplayPlayerConstructor(), + static_cast(player->pid), ToJString(env, player->name), + ToJString(env, player->revision), static_cast(player->ping), + static_cast(player->IsHost()), ToJString(env, mapping)); + env->SetObjectArrayElement(player_array, i, player_obj); + env->DeleteLocalRef(player_obj); + } - for (jsize i = 0; i < static_cast(players.size()); i++) - { - const NetPlay::Player* player = players[i]; - const std::string mapping = NetPlay::GetPlayerMappingString( - player->pid, client->GetPadMapping(), client->GetGBAConfig(), client->GetWiimoteMapping()); - jobject player_obj = env->NewObject( - IDCache::GetNetplayPlayerClass(), IDCache::GetNetplayPlayerConstructor(), - static_cast(player->pid), - ToJString(env, player->name), - ToJString(env, player->revision), - static_cast(player->ping), - static_cast(player->IsHost()), - ToJString(env, mapping)); - env->SetObjectArrayElement(player_array, i, player_obj); - env->DeleteLocalRef(player_obj); - } - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayUpdate(), player_array); - env->DeleteLocalRef(player_array); - env->DeleteLocalRef(netplay_session); + env->CallVoidMethod(session, IDCache::GetNetplayUpdate(), player_array); + env->DeleteLocalRef(player_array); + }); } void NetPlayUICallbacks::AppendChat(const std::string& message) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnChatMessageReceived(), - ToJString(env, message)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnChatMessageReceived(), + ToJString(env, message)); + }); } void NetPlayUICallbacks::OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_identifier, @@ -189,34 +163,25 @@ void NetPlayUICallbacks::OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_ide m_current_game_identifier = sync_identifier; m_current_game_name = netplay_name; - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnGameChanged(), - ToJString(env, netplay_name)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnGameChanged(), + ToJString(env, netplay_name)); + }); } void NetPlayUICallbacks::OnMsgChangeGBARom(int, const NetPlay::GBAConfig&) {} void NetPlayUICallbacks::OnMsgStartGame() { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - auto* client = reinterpret_cast( - env->GetLongField(netplay_session, IDCache::GetNetPlayClientPointer())); - if (client) - { - if (const auto game = FindGameFile(m_current_game_identifier)) - client->StartGame(game->GetFilePath()); - } - - env->DeleteLocalRef(netplay_session); + WithSession([this](JNIEnv* env, jobject session) { + auto* client = reinterpret_cast( + env->GetLongField(session, IDCache::GetNetPlayClientPointer())); + if (client) + { + if (const auto game = FindGameFile(m_current_game_identifier)) + client->StartGame(game->GetFilePath()); + } + }); } void NetPlayUICallbacks::OnMsgStopGame() {} @@ -232,61 +197,41 @@ void NetPlayUICallbacks::OnPlayerDisconnect(const std::string&) {} void NetPlayUICallbacks::OnPadBufferChanged(u32 buffer) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnPadBufferChanged(), - static_cast(buffer)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnPadBufferChanged(), + static_cast(buffer)); + }); } void NetPlayUICallbacks::OnHostInputAuthorityChanged(bool enabled) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnHostInputAuthorityChanged(), - static_cast(enabled)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnHostInputAuthorityChanged(), + static_cast(enabled)); + }); } void NetPlayUICallbacks::OnDesync(u32 frame, const std::string& player) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnDesync(), - static_cast(frame), ToJString(env, player)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnDesync(), + static_cast(frame), ToJString(env, player)); + }); } void NetPlayUICallbacks::OnConnectionLost() { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnConnectionLost()); - env->DeleteLocalRef(netplay_session); + WithSession([](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnConnectionLost()); + }); } void NetPlayUICallbacks::OnConnectionError(const std::string& message) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnConnectionError(), - ToJString(env, message)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnConnectionError(), + ToJString(env, message)); + }); } // No-op — all error info is captured by OnTraversalStateChanged which always fires alongside. @@ -294,17 +239,14 @@ void NetPlayUICallbacks::OnTraversalError(Common::TraversalClient::FailureReason void NetPlayUICallbacks::OnTraversalStateChanged(Common::TraversalClient::State state) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; + WithSession([&](JNIEnv* env, jobject session) { + if (!Common::g_TraversalClient) + return; - jstring host_code = nullptr; - jstring external_address = nullptr; - jstring failure_reason = nullptr; + jstring host_code = nullptr; + jstring external_address = nullptr; + jstring failure_reason = nullptr; - if (Common::g_TraversalClient) - { if (state == Common::TraversalClient::State::Connected) { const auto host_id = Common::g_TraversalClient->GetHostID(); @@ -318,17 +260,16 @@ void NetPlayUICallbacks::OnTraversalStateChanged(Common::TraversalClient::State ToJString(env, FailureReasonToString(Common::g_TraversalClient->GetFailureReason())); } - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnTraversalStateChanged(), + env->CallVoidMethod(session, IDCache::GetNetplayOnTraversalStateChanged(), static_cast(state), host_code, external_address, failure_reason); - } - if (host_code) - env->DeleteLocalRef(host_code); - if (external_address) - env->DeleteLocalRef(external_address); - if (failure_reason) - env->DeleteLocalRef(failure_reason); - env->DeleteLocalRef(netplay_session); + if (host_code) + env->DeleteLocalRef(host_code); + if (external_address) + env->DeleteLocalRef(external_address); + if (failure_reason) + env->DeleteLocalRef(failure_reason); + }); } void NetPlayUICallbacks::OnGameStartAborted() {} @@ -365,89 +306,61 @@ std::string NetPlayUICallbacks::FindGBARomPath(const std::array&, std::s void NetPlayUICallbacks::ShowGameDigestDialog(const std::string& title) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnShowGameDigestDialog(), - ToJString(env, title)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnShowGameDigestDialog(), + ToJString(env, title)); + }); } void NetPlayUICallbacks::SetGameDigestProgress(int pid, int progress) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnSetGameDigestProgress(), - static_cast(pid), static_cast(progress)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnSetGameDigestProgress(), + static_cast(pid), static_cast(progress)); + }); } void NetPlayUICallbacks::SetGameDigestResult(int pid, const std::string& result) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnSetGameDigestResult(), - static_cast(pid), ToJString(env, result)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnSetGameDigestResult(), + static_cast(pid), ToJString(env, result)); + }); } void NetPlayUICallbacks::AbortGameDigest() { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnAbortGameDigest()); - env->DeleteLocalRef(netplay_session); + WithSession([](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnAbortGameDigest()); + }); } void NetPlayUICallbacks::ShowChunkedProgressDialog(const std::string& title, u64 data_size, std::span players) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; + WithSession([&](JNIEnv* env, jobject session) { + jintArray j_players = env->NewIntArray(static_cast(players.size())); + env->SetIntArrayRegion(j_players, 0, static_cast(players.size()), players.data()); - jintArray j_players = env->NewIntArray(static_cast(players.size())); - env->SetIntArrayRegion(j_players, 0, static_cast(players.size()), players.data()); - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnShowChunkedProgressDialog(), - ToJString(env, title), static_cast(data_size), j_players); - env->DeleteLocalRef(j_players); - env->DeleteLocalRef(netplay_session); + env->CallVoidMethod(session, IDCache::GetNetplayOnShowChunkedProgressDialog(), + ToJString(env, title), static_cast(data_size), j_players); + env->DeleteLocalRef(j_players); + }); } void NetPlayUICallbacks::HideChunkedProgressDialog() { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnHideChunkedProgressDialog()); - env->DeleteLocalRef(netplay_session); + WithSession([](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnHideChunkedProgressDialog()); + }); } void NetPlayUICallbacks::SetChunkedProgress(int pid, u64 progress) { - JNIEnv* env = IDCache::GetEnvForThread(); - jobject netplay_session = GetNetplaySessionLocalRef(env); - if (!netplay_session) - return; - - env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnSetChunkedProgress(), - static_cast(pid), static_cast(progress)); - env->DeleteLocalRef(netplay_session); + WithSession([&](JNIEnv* env, jobject session) { + env->CallVoidMethod(session, IDCache::GetNetplayOnSetChunkedProgress(), + static_cast(pid), static_cast(progress)); + }); } void NetPlayUICallbacks::SetHostWiiSyncData(std::vector, std::string) {} diff --git a/Source/Android/jni/NetPlay/NetPlayUICallbacks.h b/Source/Android/jni/NetPlay/NetPlayUICallbacks.h index 83ea2c06bc..602512e3b8 100644 --- a/Source/Android/jni/NetPlay/NetPlayUICallbacks.h +++ b/Source/Android/jni/NetPlay/NetPlayUICallbacks.h @@ -13,6 +13,7 @@ #include "Common/HookableEvent.h" #include "Core/NetPlayClient.h" #include "UICommon/GameFile.h" +#include "jni/AndroidCommon/IDCache.h" namespace NetPlay { @@ -67,6 +68,17 @@ public: private: jobject GetNetplaySessionLocalRef(JNIEnv* env) const; + template + void WithSession(F&& callback) const + { + JNIEnv* env = IDCache::GetEnvForThread(); + jobject netplay_session = GetNetplaySessionLocalRef(env); + if (!netplay_session) + return; + callback(env, netplay_session); + env->DeleteLocalRef(netplay_session); + } + jweak m_netplay_session; std::vector> m_games; NetPlay::SyncIdentifier m_current_game_identifier;