summaryrefslogtreecommitdiff
path: root/Source/Android
diff options
context:
space:
mode:
authorTom Pratt <tom.pratt@outlook.com>2026-05-06 13:44:53 +0200
committerTom Pratt <tompratt@squareup.com>2026-05-19 12:02:54 +0200
commit766374434c56bb8d77a5676870a6779b2ee1799f (patch)
treefd0d309dfbd7df277d0eac39a11e3cbc15b31081 /Source/Android
parent1464fdfc2845817b52c204b719e16975e5182fe5 (diff)
Pass game list to NetPlayUICallbacks and implement OnMsgChangeGame, OnMsgStartGame, FindGameFile
Diffstat (limited to 'Source/Android')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt9
-rw-r--r--Source/Android/jni/AndroidCommon/IDCache.cpp44
-rw-r--r--Source/Android/jni/AndroidCommon/IDCache.h6
-rw-r--r--Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp52
-rw-r--r--Source/Android/jni/NetPlay/NetPlayUICallbacks.h11
-rw-r--r--Source/Android/jni/NetPlay/Netplay.cpp17
6 files changed, 131 insertions, 8 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt
index 34cee1e5bf..5ede907e85 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/netplay/model/NetplaySetupViewModel.kt
@@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import org.dolphinemu.dolphinemu.features.netplay.Netplay
+import org.dolphinemu.dolphinemu.services.GameFileCacheManager
class NetplaySetupViewModel : ViewModel() {
private val _connectionRole = MutableStateFlow<ConnectionRole>(ConnectionRole.Connect)
@@ -26,6 +27,10 @@ class NetplaySetupViewModel : ViewModel() {
private val _connectPort = MutableStateFlow(Netplay.getConnectPort().toString())
val connectPort = _connectPort.asStateFlow()
+ init {
+ GameFileCacheManager.startLoad()
+ }
+
fun setConnectionRole(connectionRole: ConnectionRole) {
_connectionRole.value = connectionRole
}
@@ -55,6 +60,10 @@ class NetplaySetupViewModel : ViewModel() {
}
fun connect() {
+ if (GameFileCacheManager.isLoading().value == true) {
+ return
+ }
+
Netplay.saveSetup(
nickname = nickname.value,
connectionType = connectionType.value,
diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp
index 18b486023a..1cd6e257e6 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.cpp
+++ b/Source/Android/jni/AndroidCommon/IDCache.cpp
@@ -25,6 +25,13 @@ static jmethodID s_game_file_constructor;
static jclass s_game_file_cache_class;
static jfieldID s_game_file_cache_pointer;
+static jclass s_game_file_cache_manager_class;
+static jfieldID s_game_file_cache_manager_instance;
+
+static jclass s_netplay_class;
+static jfieldID s_net_play_client_pointer;
+static jmethodID s_netplay_on_msg_start_game;
+
static jclass s_analytics_class;
static jmethodID s_get_analytics_value;
@@ -220,6 +227,26 @@ jfieldID GetGameFileCachePointer()
return s_game_file_cache_pointer;
}
+jclass GetGameFileCacheManagerClass()
+{
+ return s_game_file_cache_manager_class;
+}
+
+jfieldID GetGameFileCacheManagerInstance()
+{
+ return s_game_file_cache_manager_instance;
+}
+
+jclass GetNetplayClass()
+{
+ return s_netplay_class;
+}
+
+jfieldID GetNetPlayClientPointer()
+{
+ return s_net_play_client_pointer;
+}
+
jclass GetPairClass()
{
return s_pair_class;
@@ -615,6 +642,21 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_game_file_cache_pointer = env->GetFieldID(game_file_cache_class, "pointer", "J");
env->DeleteLocalRef(game_file_cache_class);
+ const jclass game_file_cache_manager_class =
+ env->FindClass("org/dolphinemu/dolphinemu/services/GameFileCacheManager");
+ s_game_file_cache_manager_class =
+ reinterpret_cast<jclass>(env->NewGlobalRef(game_file_cache_manager_class));
+ s_game_file_cache_manager_instance = env->GetStaticFieldID(
+ game_file_cache_manager_class, "gameFileCache",
+ "Lorg/dolphinemu/dolphinemu/model/GameFileCache;");
+ env->DeleteLocalRef(game_file_cache_manager_class);
+
+ const jclass netplay_class =
+ env->FindClass("org/dolphinemu/dolphinemu/features/netplay/Netplay");
+ s_netplay_class = reinterpret_cast<jclass>(env->NewGlobalRef(netplay_class));
+ s_net_play_client_pointer = env->GetStaticFieldID(netplay_class, "netPlayClientPointer", "J");
+ env->DeleteLocalRef(netplay_class);
+
const jclass analytics_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Analytics");
s_analytics_class = reinterpret_cast<jclass>(env->NewGlobalRef(analytics_class));
s_get_analytics_value = env->GetStaticMethodID(s_analytics_class, "getValue",
@@ -828,6 +870,8 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
env->DeleteGlobalRef(s_native_library_class);
env->DeleteGlobalRef(s_game_file_class);
env->DeleteGlobalRef(s_game_file_cache_class);
+ env->DeleteGlobalRef(s_game_file_cache_manager_class);
+ env->DeleteGlobalRef(s_netplay_class);
env->DeleteGlobalRef(s_analytics_class);
env->DeleteGlobalRef(s_pair_class);
env->DeleteGlobalRef(s_hash_map_class);
diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h
index 0aaa9feec3..e13646eb5a 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.h
+++ b/Source/Android/jni/AndroidCommon/IDCache.h
@@ -28,6 +28,12 @@ jmethodID GetGameFileConstructor();
jclass GetGameFileCacheClass();
jfieldID GetGameFileCachePointer();
+jclass GetGameFileCacheManagerClass();
+jfieldID GetGameFileCacheManagerInstance();
+
+jclass GetNetplayClass();
+jfieldID GetNetPlayClientPointer();
+
jclass GetPairClass();
jmethodID GetPairConstructor();
diff --git a/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp b/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp
index ab56458eff..31bc977e2a 100644
--- a/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp
+++ b/Source/Android/jni/NetPlay/NetPlayUICallbacks.cpp
@@ -3,9 +3,15 @@
#include "jni/NetPlay/NetPlayUICallbacks.h"
+#include "jni/AndroidCommon/IDCache.h"
+
namespace NetPlay {
-NetPlayUICallbacks::NetPlayUICallbacks() = default;
+NetPlayUICallbacks::NetPlayUICallbacks(std::vector<std::shared_ptr<const UICommon::GameFile>> games)
+ : m_games(std::move(games))
+{
+}
+
NetPlayUICallbacks::~NetPlayUICallbacks() = default;
void NetPlayUICallbacks::BootGame(const std::string&, std::unique_ptr<BootSessionData>) {}
@@ -13,9 +19,28 @@ void NetPlayUICallbacks::StopGame() {}
bool NetPlayUICallbacks::IsHosting() const { return false; }
void NetPlayUICallbacks::Update() {}
void NetPlayUICallbacks::AppendChat(const std::string&) {}
-void NetPlayUICallbacks::OnMsgChangeGame(const NetPlay::SyncIdentifier&, const std::string&) {}
+
+void NetPlayUICallbacks::OnMsgChangeGame(const NetPlay::SyncIdentifier& sync_identifier,
+ const std::string& netplay_name)
+{
+ m_current_game_identifier = sync_identifier;
+ m_current_game_name = netplay_name;
+}
+
void NetPlayUICallbacks::OnMsgChangeGBARom(int, const NetPlay::GBAConfig&) {}
-void NetPlayUICallbacks::OnMsgStartGame() {}
+
+void NetPlayUICallbacks::OnMsgStartGame()
+{
+ JNIEnv* env = IDCache::GetEnvForThread();
+ auto* client = reinterpret_cast<NetPlay::NetPlayClient*>(
+ env->GetStaticLongField(IDCache::GetNetplayClass(), IDCache::GetNetPlayClientPointer()));
+ if (client)
+ {
+ if (const auto game = FindGameFile(m_current_game_identifier))
+ client->StartGame(game->GetFilePath());
+ }
+}
+
void NetPlayUICallbacks::OnMsgStopGame() {}
void NetPlayUICallbacks::OnMsgPowerButton() {}
void NetPlayUICallbacks::OnPlayerConnect(const std::string&) {}
@@ -35,9 +60,26 @@ void NetPlayUICallbacks::OnIndexRefreshFailed(std::string) {}
bool NetPlayUICallbacks::IsRecording() { return false; }
std::shared_ptr<const UICommon::GameFile>
-NetPlayUICallbacks::FindGameFile(const NetPlay::SyncIdentifier&, NetPlay::SyncIdentifierComparison*)
+NetPlayUICallbacks::FindGameFile(const NetPlay::SyncIdentifier& sync_identifier,
+ NetPlay::SyncIdentifierComparison* found)
{
- return nullptr;
+ NetPlay::SyncIdentifierComparison temp;
+ if (!found)
+ found = &temp;
+
+ *found = NetPlay::SyncIdentifierComparison::DifferentGame;
+
+ std::shared_ptr<const UICommon::GameFile> result;
+ for (const auto& game : m_games)
+ {
+ const auto cmp = game->CompareSyncIdentifier(sync_identifier);
+ if (cmp < *found)
+ {
+ *found = cmp;
+ result = game;
+ }
+ }
+ return result;
}
std::string NetPlayUICallbacks::FindGBARomPath(const std::array<u8, 20>&, std::string_view, int) { return {}; }
diff --git a/Source/Android/jni/NetPlay/NetPlayUICallbacks.h b/Source/Android/jni/NetPlay/NetPlayUICallbacks.h
index 18fdf1df93..acccfccabf 100644
--- a/Source/Android/jni/NetPlay/NetPlayUICallbacks.h
+++ b/Source/Android/jni/NetPlay/NetPlayUICallbacks.h
@@ -1,14 +1,18 @@
#pragma once
+#include <memory>
#include <span>
+#include <string>
+#include <vector>
#include "Core/NetPlayClient.h"
+#include "UICommon/GameFile.h"
namespace NetPlay {
class NetPlayUICallbacks : public NetPlay::NetPlayUI {
public:
- NetPlayUICallbacks();
+ NetPlayUICallbacks(std::vector<std::shared_ptr<const UICommon::GameFile>> games);
~NetPlayUICallbacks() override;
void BootGame(const std::string& filename,
@@ -52,6 +56,11 @@ public:
void HideChunkedProgressDialog() override;
void SetChunkedProgress(int pid, u64 progress) override;
void SetHostWiiSyncData(std::vector<u64> titles, std::string redirect_folder) override;
+
+private:
+ std::vector<std::shared_ptr<const UICommon::GameFile>> m_games;
+ NetPlay::SyncIdentifier m_current_game_identifier;
+ std::string m_current_game_name;
};
} // namespace NetPlay
diff --git a/Source/Android/jni/NetPlay/Netplay.cpp b/Source/Android/jni/NetPlay/Netplay.cpp
index 42ed6483ce..2346b685e0 100644
--- a/Source/Android/jni/NetPlay/Netplay.cpp
+++ b/Source/Android/jni/NetPlay/Netplay.cpp
@@ -3,14 +3,18 @@
#include <memory>
#include <string>
+#include <vector>
#include <jni.h>
#include "Common/CommonTypes.h"
#include "Core/Config/NetplaySettings.h"
#include "Core/NetPlayClient.h"
+#include "UICommon/GameFile.h"
+#include "UICommon/GameFileCache.h"
#include "jni/AndroidCommon/AndroidCommon.h"
+#include "jni/AndroidCommon/IDCache.h"
#include "jni/NetPlay/NetPlayUICallbacks.h"
extern "C" {
@@ -121,7 +125,7 @@ Java_org_dolphinemu_dolphinemu_features_netplay_Netplay_SaveSetup(
}
JNIEXPORT jlong JNICALL
-Java_org_dolphinemu_dolphinemu_features_netplay_Netplay_Join(JNIEnv*, jclass)
+Java_org_dolphinemu_dolphinemu_features_netplay_Netplay_Join(JNIEnv* env, jclass)
{
const std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
const bool is_traversal = traversal_choice == "traversal";
@@ -135,8 +139,17 @@ Java_org_dolphinemu_dolphinemu_features_netplay_Netplay_Join(JNIEnv*, jclass)
const u16 traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
const std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
+ jobject jgame_file_cache = env->GetStaticObjectField(
+ IDCache::GetGameFileCacheManagerClass(), IDCache::GetGameFileCacheManagerInstance());
+ auto* game_file_cache = reinterpret_cast<UICommon::GameFileCache*>(
+ env->GetLongField(jgame_file_cache, IDCache::GetGameFileCachePointer()));
+
+ std::vector<std::shared_ptr<const UICommon::GameFile>> games;
+ game_file_cache->ForEach(
+ [&games](const std::shared_ptr<const UICommon::GameFile>& game) { games.push_back(game); });
+
auto* client = new NetPlay::NetPlayClient(
- host_ip, host_port, new NetPlay::NetPlayUICallbacks(), nickname,
+ host_ip, host_port, new NetPlay::NetPlayUICallbacks(std::move(games)), nickname,
NetPlay::NetTraversalConfig{is_traversal, traversal_host, traversal_port});
return reinterpret_cast<jlong>(client);