Extract PlatformCallbacks interface and consolidate Emscripten files

Move all Emscripten-specific multiplayer code under platforms/emscripten/
and introduce an abstract PlatformCallbacks interface for outbound
notifications, mirroring the existing NetworkTransport pattern. This
removes all #ifdef __EMSCRIPTEN__ blocks from networkmanager.cpp.
This commit is contained in:
Christian Semmler 2026-03-02 15:46:37 -08:00
parent e47d2dab67
commit 0997610bad
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
12 changed files with 128 additions and 62 deletions

View File

@ -535,9 +535,14 @@ if (ISLE_EXTENSIONS)
extensions/src/multiplayer/charactercloner.cpp extensions/src/multiplayer/charactercloner.cpp
extensions/src/multiplayer/networkmanager.cpp extensions/src/multiplayer/networkmanager.cpp
extensions/src/multiplayer/remoteplayer.cpp extensions/src/multiplayer/remoteplayer.cpp
extensions/src/multiplayer/websockettransport.cpp
extensions/src/multiplayer/worldstatesync.cpp extensions/src/multiplayer/worldstatesync.cpp
) )
if(EMSCRIPTEN)
target_sources(lego1 PRIVATE
extensions/src/multiplayer/platforms/emscripten/websockettransport.cpp
extensions/src/multiplayer/platforms/emscripten/callbacks.cpp
)
endif()
endif() endif()
if (ISLE_BUILD_APP) if (ISLE_BUILD_APP)
@ -595,7 +600,7 @@ if (ISLE_BUILD_APP)
) )
if(ISLE_EXTENSIONS) if(ISLE_EXTENSIONS)
target_sources(isle PRIVATE target_sources(isle PRIVATE
extensions/src/multiplayer/wasm_exports.cpp extensions/src/multiplayer/platforms/emscripten/wasm_exports.cpp
) )
endif() endif()
target_compile_definitions(isle PRIVATE "ISLE_EMSCRIPTEN_HOST=\"${ISLE_EMSCRIPTEN_HOST}\"") target_compile_definitions(isle PRIVATE "ISLE_EMSCRIPTEN_HOST=\"${ISLE_EMSCRIPTEN_HOST}\"")

View File

@ -13,6 +13,7 @@ namespace Multiplayer
{ {
class NetworkManager; class NetworkManager;
class NetworkTransport; class NetworkTransport;
class PlatformCallbacks;
} // namespace Multiplayer } // namespace Multiplayer
namespace Extensions namespace Extensions
@ -42,6 +43,7 @@ class MultiplayerExt {
private: private:
static Multiplayer::NetworkManager* s_networkManager; static Multiplayer::NetworkManager* s_networkManager;
static Multiplayer::NetworkTransport* s_transport; static Multiplayer::NetworkTransport* s_transport;
static Multiplayer::PlatformCallbacks* s_callbacks;
}; };
#ifdef EXTENSIONS #ifdef EXTENSIONS

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "extensions/multiplayer/networktransport.h" #include "extensions/multiplayer/networktransport.h"
#include "extensions/multiplayer/platformcallbacks.h"
#include "extensions/multiplayer/protocol.h" #include "extensions/multiplayer/protocol.h"
#include "extensions/multiplayer/remoteplayer.h" #include "extensions/multiplayer/remoteplayer.h"
#include "extensions/multiplayer/worldstatesync.h" #include "extensions/multiplayer/worldstatesync.h"
@ -33,7 +34,7 @@ class NetworkManager : public MxCore {
return !strcmp(p_name, NetworkManager::ClassName()) || MxCore::IsA(p_name); return !strcmp(p_name, NetworkManager::ClassName()) || MxCore::IsA(p_name);
} }
void Initialize(NetworkTransport* p_transport); void Initialize(NetworkTransport* p_transport, PlatformCallbacks* p_callbacks);
void Shutdown(); void Shutdown();
void Connect(const char* p_roomId); void Connect(const char* p_roomId);
@ -78,6 +79,7 @@ class NetworkManager : public MxCore {
void SendMessage(const T& p_msg); void SendMessage(const T& p_msg);
NetworkTransport* m_transport; NetworkTransport* m_transport;
PlatformCallbacks* m_callbacks;
WorldStateSync m_worldSync; WorldStateSync m_worldSync;
std::map<uint32_t, std::unique_ptr<RemotePlayer>> m_remotePlayers; std::map<uint32_t, std::unique_ptr<RemotePlayer>> m_remotePlayers;

View File

@ -0,0 +1,15 @@
#pragma once
namespace Multiplayer
{
class PlatformCallbacks {
public:
virtual ~PlatformCallbacks() = default;
// Called when the visible player count changes (joins, leaves, world transitions).
// p_count = players visible in current world, or -1 if not in a multiplayer world.
virtual void OnPlayerCountChanged(int p_count) = 0;
};
} // namespace Multiplayer

View File

@ -0,0 +1,17 @@
#pragma once
#ifdef __EMSCRIPTEN__
#include "extensions/multiplayer/platformcallbacks.h"
namespace Multiplayer
{
class EmscriptenCallbacks : public PlatformCallbacks {
public:
void OnPlayerCountChanged(int p_count) override;
};
} // namespace Multiplayer
#endif // __EMSCRIPTEN__

View File

@ -8,8 +8,11 @@
#include "legoentity.h" #include "legoentity.h"
#include "legogamestate.h" #include "legogamestate.h"
#include "misc.h" #include "misc.h"
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#include "extensions/multiplayer/websockettransport.h" #include "extensions/multiplayer/platforms/emscripten/callbacks.h"
#include "extensions/multiplayer/platforms/emscripten/websockettransport.h"
#include <emscripten.h> #include <emscripten.h>
#endif #endif
@ -21,6 +24,7 @@ std::string MultiplayerExt::relayUrl;
std::string MultiplayerExt::room; std::string MultiplayerExt::room;
Multiplayer::NetworkManager* MultiplayerExt::s_networkManager = nullptr; Multiplayer::NetworkManager* MultiplayerExt::s_networkManager = nullptr;
Multiplayer::NetworkTransport* MultiplayerExt::s_transport = nullptr; Multiplayer::NetworkTransport* MultiplayerExt::s_transport = nullptr;
Multiplayer::PlatformCallbacks* MultiplayerExt::s_callbacks = nullptr;
void MultiplayerExt::Initialize() void MultiplayerExt::Initialize()
{ {
@ -33,9 +37,10 @@ void MultiplayerExt::Initialize()
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
s_transport = new Multiplayer::WebSocketTransport(relayUrl); s_transport = new Multiplayer::WebSocketTransport(relayUrl);
s_callbacks = new Multiplayer::EmscriptenCallbacks();
s_networkManager = new Multiplayer::NetworkManager(); s_networkManager = new Multiplayer::NetworkManager();
s_networkManager->Initialize(s_transport); s_networkManager->Initialize(s_transport, s_callbacks);
s_networkManager->Connect(room.c_str()); s_networkManager->Connect(room.c_str());
#endif #endif

View File

@ -11,9 +11,6 @@
#include <SDL3/SDL_stdinc.h> #include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_timer.h> #include <SDL3/SDL_timer.h>
#include <vector> #include <vector>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
using namespace Multiplayer; using namespace Multiplayer;
@ -32,8 +29,9 @@ void NetworkManager::SendMessage(const T& p_msg)
} }
NetworkManager::NetworkManager() NetworkManager::NetworkManager()
: m_transport(nullptr), m_localPeerId(0), m_hostPeerId(0), m_sequence(0), m_lastBroadcastTime(0), : m_transport(nullptr), m_callbacks(nullptr), m_localPeerId(0), m_hostPeerId(0), m_sequence(0),
m_lastValidActorId(0), m_localWalkAnimId(0), m_localIdleAnimId(0), m_inIsleWorld(false), m_registered(false) m_lastBroadcastTime(0), m_lastValidActorId(0), m_localWalkAnimId(0), m_localIdleAnimId(0), m_inIsleWorld(false),
m_registered(false)
{ {
} }
@ -78,9 +76,10 @@ MxResult NetworkManager::Tickle()
return SUCCESS; return SUCCESS;
} }
void NetworkManager::Initialize(NetworkTransport* p_transport) void NetworkManager::Initialize(NetworkTransport* p_transport, PlatformCallbacks* p_callbacks)
{ {
m_transport = p_transport; m_transport = p_transport;
m_callbacks = p_callbacks;
m_worldSync.SetTransport(p_transport); m_worldSync.SetTransport(p_transport);
} }
@ -460,7 +459,10 @@ void NetworkManager::RemoveAllRemotePlayers()
void NetworkManager::NotifyPlayerCountChanged() void NetworkManager::NotifyPlayerCountChanged()
{ {
#ifdef __EMSCRIPTEN__ if (!m_callbacks) {
return;
}
int count = -1; int count = -1;
if (m_inIsleWorld) { if (m_inIsleWorld) {
count = 1; // local player count = 1; // local player
@ -470,17 +472,8 @@ void NetworkManager::NotifyPlayerCountChanged()
} }
} }
} }
// clang-format off
MAIN_THREAD_EM_ASM({ m_callbacks->OnPlayerCountChanged(count);
var canvas = Module.canvas;
if (canvas) {
canvas.dispatchEvent(new CustomEvent('playerCountChanged', {
detail: { count: $0 < 0 ? null : $0 }
}));
}
}, count);
// clang-format on
#endif
} }
int8_t NetworkManager::DetectLocalVehicleType() int8_t NetworkManager::DetectLocalVehicleType()

View File

@ -0,0 +1,26 @@
#ifdef __EMSCRIPTEN__
#include "extensions/multiplayer/platforms/emscripten/callbacks.h"
#include <emscripten.h>
namespace Multiplayer
{
void EmscriptenCallbacks::OnPlayerCountChanged(int p_count)
{
// clang-format off
MAIN_THREAD_EM_ASM({
var canvas = Module.canvas;
if (canvas) {
canvas.dispatchEvent(new CustomEvent('playerCountChanged', {
detail: { count: $0 < 0 ? null : $0 }
}));
}
}, p_count);
// clang-format on
}
} // namespace Multiplayer
#endif // __EMSCRIPTEN__

View File

@ -0,0 +1,39 @@
#ifdef __EMSCRIPTEN__
#include "extensions/multiplayer.h"
#include "extensions/multiplayer/networkmanager.h"
#include <emscripten.h>
using namespace Extensions;
extern "C"
{
EMSCRIPTEN_KEEPALIVE void mp_set_walk_animation(int index)
{
Multiplayer::NetworkManager* mgr = MultiplayerExt::GetNetworkManager();
if (mgr) {
mgr->SetWalkAnimation(static_cast<uint8_t>(index));
}
}
EMSCRIPTEN_KEEPALIVE void mp_set_idle_animation(int index)
{
Multiplayer::NetworkManager* mgr = MultiplayerExt::GetNetworkManager();
if (mgr) {
mgr->SetIdleAnimation(static_cast<uint8_t>(index));
}
}
EMSCRIPTEN_KEEPALIVE void mp_trigger_emote(int index)
{
Multiplayer::NetworkManager* mgr = MultiplayerExt::GetNetworkManager();
if (mgr) {
mgr->SendEmote(static_cast<uint8_t>(index));
}
}
} // extern "C"
#endif

View File

@ -1,6 +1,6 @@
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#include "extensions/multiplayer/websockettransport.h" #include "extensions/multiplayer/platforms/emscripten/websockettransport.h"
#include <SDL3/SDL_stdinc.h> #include <SDL3/SDL_stdinc.h>
#include <emscripten.h> #include <emscripten.h>

View File

@ -1,38 +0,0 @@
#ifdef __EMSCRIPTEN__
#include "extensions/multiplayer.h"
#include "extensions/multiplayer/networkmanager.h"
#include <emscripten.h>
using namespace Extensions;
extern "C" {
EMSCRIPTEN_KEEPALIVE void mp_set_walk_animation(int index)
{
Multiplayer::NetworkManager* mgr = MultiplayerExt::GetNetworkManager();
if (mgr) {
mgr->SetWalkAnimation(static_cast<uint8_t>(index));
}
}
EMSCRIPTEN_KEEPALIVE void mp_set_idle_animation(int index)
{
Multiplayer::NetworkManager* mgr = MultiplayerExt::GetNetworkManager();
if (mgr) {
mgr->SetIdleAnimation(static_cast<uint8_t>(index));
}
}
EMSCRIPTEN_KEEPALIVE void mp_trigger_emote(int index)
{
Multiplayer::NetworkManager* mgr = MultiplayerExt::GetNetworkManager();
if (mgr) {
mgr->SendEmote(static_cast<uint8_t>(index));
}
}
} // extern "C"
#endif