mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-05-09 12:24:04 -05:00
Create NetPlayServer and start game
This commit is contained in:
parent
ccce2b2e9a
commit
fa5facfdfb
|
|
@ -37,6 +37,8 @@ class NetplaySession(
|
|||
|
||||
private var netPlayClientPointer: Long = 0
|
||||
|
||||
private var netPlayServerPointer: Long = 0
|
||||
|
||||
private var bootSessionDataPointer: Long = 0
|
||||
|
||||
private val sessionScope = CoroutineScope(SupervisorJob())
|
||||
|
|
@ -44,6 +46,9 @@ class NetplaySession(
|
|||
@Volatile
|
||||
var isClosing = false
|
||||
private set
|
||||
|
||||
val isHosting: Boolean
|
||||
get() = netPlayServerPointer != 0L
|
||||
|
||||
val isLaunching: Boolean
|
||||
get() = bootSessionDataPointer != 0L
|
||||
|
|
@ -124,10 +129,22 @@ class NetplaySession(
|
|||
true
|
||||
}
|
||||
|
||||
suspend fun host(): Boolean = withContext(Dispatchers.IO) {
|
||||
netPlayServerPointer = nativeHost()
|
||||
if (netPlayServerPointer == 0L || !isActive) {
|
||||
closeBlocking()
|
||||
return@withContext false
|
||||
}
|
||||
|
||||
join()
|
||||
}
|
||||
|
||||
fun sendMessage(message: String) = nativeSendMessage(message)
|
||||
|
||||
fun adjustPadBufferSize(buffer: Int) = nativeAdjustPadBufferSize(buffer)
|
||||
|
||||
fun startGame() = nativeStartGame()
|
||||
|
||||
fun consumeBootSessionData(): Long {
|
||||
return bootSessionDataPointer.also {
|
||||
bootSessionDataPointer = 0
|
||||
|
|
@ -172,6 +189,12 @@ class NetplaySession(
|
|||
nativeReleaseClient(currentNetPlayClientPointer)
|
||||
}
|
||||
|
||||
val currentNetPlayServerPointer = netPlayServerPointer
|
||||
if (currentNetPlayServerPointer != 0L) {
|
||||
netPlayServerPointer = 0
|
||||
nativeReleaseServer(currentNetPlayServerPointer)
|
||||
}
|
||||
|
||||
val currentNetPlayUICallbacksPointer = netPlayUICallbacksPointer
|
||||
if (currentNetPlayUICallbacksPointer != 0L) {
|
||||
netPlayUICallbacksPointer = 0
|
||||
|
|
@ -185,6 +208,8 @@ class NetplaySession(
|
|||
|
||||
private external fun nativeJoin(): Long
|
||||
|
||||
private external fun nativeHost(): Long
|
||||
|
||||
private external fun nativeSendMessage(message: String)
|
||||
|
||||
private external fun nativeAdjustPadBufferSize(buffer: Int)
|
||||
|
|
@ -193,8 +218,12 @@ class NetplaySession(
|
|||
|
||||
private external fun nativeReleaseClient(pointer: Long)
|
||||
|
||||
private external fun nativeReleaseServer(pointer: Long)
|
||||
|
||||
private external fun nativeReleaseBootSessionData(pointer: Long)
|
||||
|
||||
private external fun nativeStartGame()
|
||||
|
||||
// NetPlayUI callbacks
|
||||
|
||||
@Keep
|
||||
|
|
|
|||
|
|
@ -119,11 +119,9 @@ class NetplaySetupViewModel(
|
|||
BooleanSetting.NETPLAY_USE_UPNP.setBoolean(NativeConfig.LAYER_BASE, useUpnp)
|
||||
}
|
||||
|
||||
fun host() {
|
||||
fun host() = connect(host = true)
|
||||
|
||||
}
|
||||
|
||||
fun connect() {
|
||||
fun connect(host: Boolean = false) {
|
||||
if (_connecting.value) return
|
||||
|
||||
_connecting.value = true
|
||||
|
|
@ -139,7 +137,12 @@ class NetplaySetupViewModel(
|
|||
.onEach { _errors.emit(it) }
|
||||
.launchIn(this)
|
||||
|
||||
if (session.join()) {
|
||||
val success = if (host) {
|
||||
session.host()
|
||||
} else {
|
||||
session.join()
|
||||
}
|
||||
if (success) {
|
||||
_showNetplayScreen.trySend(Unit)
|
||||
}
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ class NetplayViewModel(
|
|||
|
||||
val launchGame = netplaySession.launchGame
|
||||
|
||||
val isHosting = netplaySession.isHosting
|
||||
|
||||
val connectionLost = netplaySession.connectionLost
|
||||
|
||||
val players = netplaySession.players
|
||||
|
|
@ -43,6 +45,10 @@ class NetplayViewModel(
|
|||
|
||||
val gameDigestProgress = netplaySession.gameDigestProgress
|
||||
|
||||
fun startGame() {
|
||||
netplaySession.startGame()
|
||||
}
|
||||
|
||||
fun sendMessage(message: String) {
|
||||
val trimmedMessage = message.trim()
|
||||
if (trimmedMessage.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ class NetplayActivity : AppCompatActivity(), ThemeProvider {
|
|||
messages = viewModel.messages.collectAsState().value,
|
||||
onSendMessage = viewModel::sendMessage,
|
||||
game = viewModel.game.collectAsState().value,
|
||||
isHosting = false,
|
||||
onStartGame = {},
|
||||
isHosting = viewModel.isHosting,
|
||||
onStartGame = viewModel::startGame,
|
||||
players = viewModel.players.collectAsState().value,
|
||||
hostInputAuthorityEnabled = viewModel.hostInputAuthority.collectAsState().value,
|
||||
maxBuffer = viewModel.maxBuffer.collectAsState().value,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ static jfieldID s_game_file_cache_manager_instance;
|
|||
static jclass s_netplay_class;
|
||||
static jfieldID s_net_play_ui_callbacks_pointer;
|
||||
static jfieldID s_net_play_client_pointer;
|
||||
static jfieldID s_net_play_server_pointer;
|
||||
static jmethodID s_netplay_on_boot_game;
|
||||
static jmethodID s_netplay_on_stop_game;
|
||||
static jmethodID s_netplay_on_connection_lost;
|
||||
|
|
@ -272,6 +273,11 @@ jfieldID GetNetPlayClientPointer()
|
|||
return s_net_play_client_pointer;
|
||||
}
|
||||
|
||||
jfieldID GetNetPlayServerPointer()
|
||||
{
|
||||
return s_net_play_server_pointer;
|
||||
}
|
||||
|
||||
jmethodID GetNetplayOnBootGame()
|
||||
{
|
||||
return s_netplay_on_boot_game;
|
||||
|
|
@ -777,6 +783,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
s_net_play_ui_callbacks_pointer =
|
||||
env->GetFieldID(netplay_class, "netPlayUICallbacksPointer", "J");
|
||||
s_net_play_client_pointer = env->GetFieldID(netplay_class, "netPlayClientPointer", "J");
|
||||
s_net_play_server_pointer = env->GetFieldID(netplay_class, "netPlayServerPointer", "J");
|
||||
s_netplay_on_boot_game = env->GetMethodID(netplay_class, "onBootGame", "(Ljava/lang/String;J)V");
|
||||
s_netplay_on_stop_game = env->GetMethodID(netplay_class, "onStopGame", "()V");
|
||||
s_netplay_on_connection_lost = env->GetMethodID(netplay_class, "onConnectionLost", "()V");
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ jfieldID GetGameFileCacheManagerInstance();
|
|||
jclass GetNetplayClass();
|
||||
jfieldID GetNetPlayUICallbacksPointer();
|
||||
jfieldID GetNetPlayClientPointer();
|
||||
jfieldID GetNetPlayServerPointer();
|
||||
jmethodID GetNetplayOnBootGame();
|
||||
jmethodID GetNetplayOnStopGame();
|
||||
jmethodID GetNetplayOnConnectionLost();
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ void NetPlayUICallbacks::StopGame()
|
|||
env->DeleteLocalRef(netplay_session);
|
||||
}
|
||||
|
||||
// Only used by Qt UI code, never by the C++ core. On Android, hosting state
|
||||
// is tracked in Kotlin (NetplaySession.isHosting).
|
||||
bool NetPlayUICallbacks::IsHosting() const { return false; }
|
||||
|
||||
void NetPlayUICallbacks::Update()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "Core/Boot/Boot.h"
|
||||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/NetPlayClient.h"
|
||||
#include "Core/NetPlayServer.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
#include "UICommon/GameFileCache.h"
|
||||
|
||||
|
|
@ -20,8 +21,8 @@
|
|||
|
||||
static NetPlay::NetPlayUICallbacks* GetUICallbacksPointer(JNIEnv* env, jobject obj)
|
||||
{
|
||||
return reinterpret_cast<NetPlay::NetPlayUICallbacks*>(
|
||||
env->GetLongField(obj, IDCache::GetNetPlayUICallbacksPointer()));
|
||||
return reinterpret_cast<NetPlay::NetPlayUICallbacks*>(
|
||||
env->GetLongField(obj, IDCache::GetNetPlayUICallbacksPointer()));
|
||||
}
|
||||
|
||||
static NetPlay::NetPlayClient* GetClientPointer(JNIEnv* env, jobject obj)
|
||||
|
|
@ -30,6 +31,12 @@ static NetPlay::NetPlayClient* GetClientPointer(JNIEnv* env, jobject obj)
|
|||
env->GetLongField(obj, IDCache::GetNetPlayClientPointer()));
|
||||
}
|
||||
|
||||
static NetPlay::NetPlayServer* GetServerPointer(JNIEnv* env, jobject obj)
|
||||
{
|
||||
return reinterpret_cast<NetPlay::NetPlayServer*>(
|
||||
env->GetLongField(obj, IDCache::GetNetPlayServerPointer()));
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
|
@ -74,11 +81,25 @@ Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeJoin(JNIEnv
|
|||
const u16 traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
|
||||
const std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
||||
|
||||
const std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
||||
const bool is_traversal = traversal_choice == "traversal";
|
||||
const std::string host_ip = is_traversal ? Config::Get(Config::NETPLAY_HOST_CODE) :
|
||||
Config::Get(Config::NETPLAY_ADDRESS);
|
||||
const u16 host_port = Config::Get(Config::NETPLAY_CONNECT_PORT);
|
||||
std::string host_ip;
|
||||
u16 host_port;
|
||||
bool is_traversal;
|
||||
|
||||
// When hosting, join our own server on localhost
|
||||
if (auto* server = GetServerPointer(env, obj))
|
||||
{
|
||||
host_ip = "127.0.0.1";
|
||||
host_port = server->GetPort();
|
||||
is_traversal = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
||||
is_traversal = traversal_choice == "traversal";
|
||||
host_ip = is_traversal ? Config::Get(Config::NETPLAY_HOST_CODE) :
|
||||
Config::Get(Config::NETPLAY_ADDRESS);
|
||||
host_port = Config::Get(Config::NETPLAY_CONNECT_PORT);
|
||||
}
|
||||
|
||||
auto* client = new NetPlay::NetPlayClient(
|
||||
host_ip, host_port, ui, nickname,
|
||||
|
|
@ -93,6 +114,51 @@ Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeJoin(JNIEnv
|
|||
return reinterpret_cast<jlong>(client);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeHost(JNIEnv* env, jobject obj)
|
||||
{
|
||||
auto* ui = GetUICallbacksPointer(env, obj);
|
||||
|
||||
const std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
||||
const bool is_traversal = traversal_choice == "traversal";
|
||||
const bool use_upnp = Config::Get(Config::NETPLAY_USE_UPNP);
|
||||
const std::string traversal_host = Config::Get(Config::NETPLAY_TRAVERSAL_SERVER);
|
||||
const u16 traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
|
||||
const u16 traversal_port_alt = Config::Get(Config::NETPLAY_TRAVERSAL_PORT_ALT);
|
||||
|
||||
const u16 host_port = is_traversal ? Config::Get(Config::NETPLAY_LISTEN_PORT)
|
||||
: Config::Get(Config::NETPLAY_HOST_PORT);
|
||||
|
||||
auto* server = new NetPlay::NetPlayServer(
|
||||
host_port, use_upnp, ui,
|
||||
NetPlay::NetTraversalConfig{is_traversal, traversal_host, traversal_port, traversal_port_alt});
|
||||
|
||||
if (!server->is_connected)
|
||||
{
|
||||
delete server;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string network_mode = Config::Get(Config::NETPLAY_NETWORK_MODE);
|
||||
const bool host_input_authority =
|
||||
network_mode == "hostinputauthority" || network_mode == "golf";
|
||||
server->SetHostInputAuthority(host_input_authority);
|
||||
server->AdjustPadBufferSize(Config::Get(Config::NETPLAY_BUFFER_SIZE));
|
||||
|
||||
return reinterpret_cast<jlong>(server);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeStartGame(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
auto* server = GetServerPointer(env, obj);
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
server->RequestStartGame();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeReleaseUICallbacks(JNIEnv*,
|
||||
jobject,
|
||||
|
|
@ -116,4 +182,11 @@ Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeReleaseClie
|
|||
delete reinterpret_cast<NetPlay::NetPlayClient*>(pointer);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_netplay_NetplaySession_nativeReleaseServer(JNIEnv*, jobject,
|
||||
jlong pointer)
|
||||
{
|
||||
delete reinterpret_cast<NetPlay::NetPlayServer*>(pointer);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user