WithSession helper function

Handles the repeated boiler plate of using a weak reference to NetplaySession from NetplayUICallbacks
This commit is contained in:
Tom Pratt
2026-05-18 21:31:39 +02:00
committed by Tom Pratt
parent 06cc09cf09
commit 4d1e749977
2 changed files with 129 additions and 204 deletions
+117 -204
View File
@@ -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<NetPlay::NetPlayClient*>(
env->GetLongField(netplay_session, IDCache::GetNetPlayClientPointer()));
if (client)
client->RequestStopGame();
env->DeleteLocalRef(netplay_session);
WithSession([](JNIEnv* env, jobject session) {
auto* client = reinterpret_cast<NetPlay::NetPlayClient*>(
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<jlong>(boot_session_data.release()));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnBootGame(), ToJString(env, filename),
reinterpret_cast<jlong>(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<NetPlay::NetPlayClient*>(
env->GetLongField(session, IDCache::GetNetPlayClientPointer()));
if (!client)
return;
auto* client = reinterpret_cast<NetPlay::NetPlayClient*>(
env->GetLongField(netplay_session, IDCache::GetNetPlayClientPointer()));
if (!client)
{
env->DeleteLocalRef(netplay_session);
return;
}
const std::vector<const NetPlay::Player*> players = client->GetPlayers();
const std::vector<const NetPlay::Player*> players = client->GetPlayers();
jobjectArray player_array = env->NewObjectArray(
static_cast<jsize>(players.size()), IDCache::GetNetplayPlayerClass(), nullptr);
jobjectArray player_array =
env->NewObjectArray(static_cast<jsize>(players.size()), IDCache::GetNetplayPlayerClass(), nullptr);
for (jsize i = 0; i < static_cast<jsize>(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<jint>(player->pid), ToJString(env, player->name),
ToJString(env, player->revision), static_cast<jint>(player->ping),
static_cast<jboolean>(player->IsHost()), ToJString(env, mapping));
env->SetObjectArrayElement(player_array, i, player_obj);
env->DeleteLocalRef(player_obj);
}
for (jsize i = 0; i < static_cast<jsize>(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<jint>(player->pid),
ToJString(env, player->name),
ToJString(env, player->revision),
static_cast<jint>(player->ping),
static_cast<jboolean>(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<NetPlay::NetPlayClient*>(
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<NetPlay::NetPlayClient*>(
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<jint>(buffer));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnPadBufferChanged(),
static_cast<jint>(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<jboolean>(enabled));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnHostInputAuthorityChanged(),
static_cast<jboolean>(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<jint>(frame), ToJString(env, player));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnDesync(),
static_cast<jint>(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<jint>(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<u8, 20>&, 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<jint>(pid), static_cast<jint>(progress));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnSetGameDigestProgress(),
static_cast<jint>(pid), static_cast<jint>(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<jint>(pid), ToJString(env, result));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnSetGameDigestResult(),
static_cast<jint>(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<const int> 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<jsize>(players.size()));
env->SetIntArrayRegion(j_players, 0, static_cast<jsize>(players.size()), players.data());
jintArray j_players = env->NewIntArray(static_cast<jsize>(players.size()));
env->SetIntArrayRegion(j_players, 0, static_cast<jsize>(players.size()), players.data());
env->CallVoidMethod(netplay_session, IDCache::GetNetplayOnShowChunkedProgressDialog(),
ToJString(env, title), static_cast<jlong>(data_size), j_players);
env->DeleteLocalRef(j_players);
env->DeleteLocalRef(netplay_session);
env->CallVoidMethod(session, IDCache::GetNetplayOnShowChunkedProgressDialog(),
ToJString(env, title), static_cast<jlong>(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<jint>(pid), static_cast<jlong>(progress));
env->DeleteLocalRef(netplay_session);
WithSession([&](JNIEnv* env, jobject session) {
env->CallVoidMethod(session, IDCache::GetNetplayOnSetChunkedProgress(),
static_cast<jint>(pid), static_cast<jlong>(progress));
});
}
void NetPlayUICallbacks::SetHostWiiSyncData(std::vector<u64>, std::string) {}
@@ -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 <typename F>
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<std::shared_ptr<const UICommon::GameFile>> m_games;
NetPlay::SyncIdentifier m_current_game_identifier;