2
0
Arnis Lielturks 5 жил өмнө
parent
commit
7b22dd68e4

+ 37 - 3
Source/Urho3D/Network/Connection.cpp

@@ -38,9 +38,11 @@
 #include "../Scene/SceneEvents.h"
 #include "../Scene/SceneEvents.h"
 #include "../Scene/SmoothedTransform.h"
 #include "../Scene/SmoothedTransform.h"
 
 
+#ifndef __EMSCRIPTEN__ 1
 #include <SLikeNet/MessageIdentifiers.h>
 #include <SLikeNet/MessageIdentifiers.h>
 #include <SLikeNet/peerinterface.h>
 #include <SLikeNet/peerinterface.h>
 #include <SLikeNet/statistics.h>
 #include <SLikeNet/statistics.h>
+#endif
 
 
 #ifdef URHO3D_WEBSOCKETS
 #ifdef URHO3D_WEBSOCKETS
 #include "WS/WSPacket.h"
 #include "WS/WSPacket.h"
@@ -90,7 +92,9 @@ Connection::Connection(Context* context, bool isClient, const SLNet::AddressOrGU
     packedMessageLimit_(1024)
     packedMessageLimit_(1024)
 {
 {
     sceneState_.connection_ = this;
     sceneState_.connection_ = this;
+#ifndef __EMSCRIPTEN__
     port_ = address.systemAddress.GetPort();
     port_ = address.systemAddress.GetPort();
+#endif
     SetAddressOrGUID(address);
     SetAddressOrGUID(address);
 }
 }
 
 
@@ -170,7 +174,11 @@ void Connection::SendMessage(int msgID, bool reliable, bool inOrder, const unsig
 
 
     if (buffer.GetSize() == 0)
     if (buffer.GetSize() == 0)
     {
     {
+#ifndef __EMSCRIPTEN__
         buffer.WriteUByte((unsigned char)DefaultMessageIDTypes::ID_USER_PACKET_ENUM);
         buffer.WriteUByte((unsigned char)DefaultMessageIDTypes::ID_USER_PACKET_ENUM);
+#else
+        buffer.WriteUByte((unsigned char)URHO3D_MESSAGE);
+#endif
         buffer.WriteUInt((unsigned int)MSG_PACKED_MESSAGE);
         buffer.WriteUInt((unsigned int)MSG_PACKED_MESSAGE);
     }
     }
 
 
@@ -293,8 +301,10 @@ void Connection::SetLogStatistics(bool enable)
 
 
 void Connection::Disconnect(int waitMSec)
 void Connection::Disconnect(int waitMSec)
 {
 {
+#ifndef __EMSCRIPTEN__
     if (peer_)
     if (peer_)
         peer_->CloseConnection(*address_, true);
         peer_->CloseConnection(*address_, true);
+#endif
 
 
 #ifdef URHO3D_WEBSOCKETS
 #ifdef URHO3D_WEBSOCKETS
     if (!isClient_ && wsHandler_)
     if (!isClient_ && wsHandler_)
@@ -427,6 +437,9 @@ void Connection::SendBuffer(PacketType type)
     if (buffer.GetSize() == 0)
     if (buffer.GetSize() == 0)
         return;
         return;
 
 
+    bool sentOut = false;
+
+#ifndef __EMSCRIPTEN__
     PacketReliability reliability = PacketReliability::UNRELIABLE;
     PacketReliability reliability = PacketReliability::UNRELIABLE;
     if (type == PT_UNRELIABLE_ORDERED)
     if (type == PT_UNRELIABLE_ORDERED)
         reliability = PacketReliability::UNRELIABLE_SEQUENCED;
         reliability = PacketReliability::UNRELIABLE_SEQUENCED;
@@ -437,13 +450,13 @@ void Connection::SendBuffer(PacketType type)
     if (type == PT_RELIABLE_UNORDERED)
     if (type == PT_RELIABLE_UNORDERED)
         reliability = PacketReliability::RELIABLE;
         reliability = PacketReliability::RELIABLE;
 
 
-    bool sentOut = false;
     if (peer_)
     if (peer_)
     {
     {
         peer_->Send((const char *) buffer.GetData(), (int) buffer.GetSize(), HIGH_PRIORITY, reliability, (char) 0, *address_, false);
         peer_->Send((const char *) buffer.GetData(), (int) buffer.GetSize(), HIGH_PRIORITY, reliability, (char) 0, *address_, false);
         tempPacketCounter_.y_++;
         tempPacketCounter_.y_++;
         sentOut = true;
         sentOut = true;
     }
     }
+#endif
 
 
 #ifdef URHO3D_WEBSOCKETS
 #ifdef URHO3D_WEBSOCKETS
     if (wsHandler_)
     if (wsHandler_)
@@ -640,10 +653,12 @@ bool Connection::ProcessMessage(int msgID, MemoryBuffer& buffer)
 
 
 void Connection::Ban()
 void Connection::Ban()
 {
 {
+#ifndef __EMSCRIPTEN__
     if (peer_)
     if (peer_)
     {
     {
         peer_->AddToBanList(address_->ToString(false), 0);
         peer_->AddToBanList(address_->ToString(false), 0);
     }
     }
+#endif
 }
 }
 
 
 void Connection::ProcessLoadScene(int msgID, MemoryBuffer& msg)
 void Connection::ProcessLoadScene(int msgID, MemoryBuffer& msg)
@@ -1198,17 +1213,24 @@ Scene* Connection::GetScene() const
 
 
 bool Connection::IsConnected() const
 bool Connection::IsConnected() const
 {
 {
+#ifndef __EMSCRIPTEN__
     return peer_ && peer_->IsActive();
     return peer_ && peer_->IsActive();
+#else
+    if (ws_.GetWS())
+        return true;
+#endif
 }
 }
 
 
 float Connection::GetRoundTripTime() const
 float Connection::GetRoundTripTime() const
 {
 {
+#ifndef __EMSCRIPTEN__
     if (peer_)
     if (peer_)
     {
     {
         SLNet::RakNetStatistics stats{};
         SLNet::RakNetStatistics stats{};
         if (peer_->GetStatistics(address_->systemAddress, &stats))
         if (peer_->GetStatistics(address_->systemAddress, &stats))
             return (float)peer_->GetAveragePing(*address_);
             return (float)peer_->GetAveragePing(*address_);
     }
     }
+#endif
     return 0.0f;
     return 0.0f;
 }
 }
 
 
@@ -1219,23 +1241,27 @@ unsigned Connection::GetLastHeardTime() const
 
 
 float Connection::GetBytesInPerSec() const
 float Connection::GetBytesInPerSec() const
 {
 {
+#ifndef __EMSCRIPTEN__
     if (peer_)
     if (peer_)
     {
     {
         SLNet::RakNetStatistics stats{};
         SLNet::RakNetStatistics stats{};
         if (peer_->GetStatistics(address_->systemAddress, &stats))
         if (peer_->GetStatistics(address_->systemAddress, &stats))
             return (float)stats.valueOverLastSecond[SLNet::ACTUAL_BYTES_RECEIVED];
             return (float)stats.valueOverLastSecond[SLNet::ACTUAL_BYTES_RECEIVED];
     }
     }
+#endif
     return 0.0f;
     return 0.0f;
 }
 }
 
 
 float Connection::GetBytesOutPerSec() const
 float Connection::GetBytesOutPerSec() const
 {
 {
+#ifndef __EMSCRIPTEN__
     if (peer_)
     if (peer_)
     {
     {
         SLNet::RakNetStatistics stats{};
         SLNet::RakNetStatistics stats{};
         if (peer_->GetStatistics(address_->systemAddress, &stats))
         if (peer_->GetStatistics(address_->systemAddress, &stats))
             return (float)stats.valueOverLastSecond[SLNet::ACTUAL_BYTES_SENT];
             return (float)stats.valueOverLastSecond[SLNet::ACTUAL_BYTES_SENT];
     }
     }
+#endif
     return 0.0f;
     return 0.0f;
 }
 }
 
 
@@ -1314,8 +1340,10 @@ void Connection::SendPackageToClient(PackageFile* package)
 
 
 void Connection::ConfigureNetworkSimulator(int latencyMs, float packetLoss)
 void Connection::ConfigureNetworkSimulator(int latencyMs, float packetLoss)
 {
 {
+#ifndef __EMSCRIPTEN__
     if (peer_)
     if (peer_)
         peer_->ApplyNetworkSimulator(packetLoss, latencyMs, 0);
         peer_->ApplyNetworkSimulator(packetLoss, latencyMs, 0);
+#endif
 }
 }
 
 
 void Connection::SetPacketSizeLimit(int limit)
 void Connection::SetPacketSizeLimit(int limit)
@@ -1798,14 +1826,20 @@ void Connection::ProcessUnknownMessage(int msgID, MemoryBuffer& msg)
 }
 }
 
 
 String Connection::GetAddress() const {
 String Connection::GetAddress() const {
-    return String(address_->ToString(false /*write port*/)); 
+#ifndef __EMSCRIPTEN__
+    return String(address_->ToString(false /*write port*/));
+#else
+    return String::EMPTY;
+#endif
 }
 }
 
 
 void Connection::SetAddressOrGUID(const SLNet::AddressOrGUID& addr)
 void Connection::SetAddressOrGUID(const SLNet::AddressOrGUID& addr)
-{ 
+{
+#ifndef __EMSCRIPTEN__
     delete address_;
     delete address_;
     address_ = nullptr;
     address_ = nullptr;
     address_ = new SLNet::AddressOrGUID(addr);
     address_ = new SLNet::AddressOrGUID(addr);
+#endif
 }
 }
 
 
 }
 }

+ 2 - 0
Source/Urho3D/Network/Connection.h

@@ -129,6 +129,8 @@ public:
     Connection(Context* context, bool isClient, const WSConnection& ws, WSHandler* wsHandler);
     Connection(Context* context, bool isClient, const WSConnection& ws, WSHandler* wsHandler);
     /// Set Websocket connection information
     /// Set Websocket connection information
     void SetWS(const WSConnection& ws);
     void SetWS(const WSConnection& ws);
+    /// Get Websocket connection information
+    const WSConnection& GetWS() const { return ws_; };
     /// Set Websocket handler for this connection
     /// Set Websocket handler for this connection
     void SetWSHandler(WSHandler* server);
     void SetWSHandler(WSHandler* server);
     /// Get current Websocket handler for this connection
     /// Get current Websocket handler for this connection

+ 125 - 4
Source/Urho3D/Network/Network.cpp

@@ -45,10 +45,12 @@
 #include "WS/WSPacket.h"
 #include "WS/WSPacket.h"
 #endif
 #endif
 
 
+#ifndef __EMSCRIPTEN__
 #include <SLikeNet/MessageIdentifiers.h>
 #include <SLikeNet/MessageIdentifiers.h>
 #include <SLikeNet/NatPunchthroughClient.h>
 #include <SLikeNet/NatPunchthroughClient.h>
 #include <SLikeNet/peerinterface.h>
 #include <SLikeNet/peerinterface.h>
 #include <SLikeNet/statistics.h>
 #include <SLikeNet/statistics.h>
+#endif
 
 
 #ifdef SendMessage
 #ifdef SendMessage
 #undef SendMessage
 #undef SendMessage
@@ -63,6 +65,7 @@
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
+#ifndef __EMSCRIPTEN__
 static const char* RAKNET_MESSAGEID_STRINGS[] = {
 static const char* RAKNET_MESSAGEID_STRINGS[] = {
     "ID_CONNECTED_PING",  
     "ID_CONNECTED_PING",  
     "ID_UNCONNECTED_PING",
     "ID_UNCONNECTED_PING",
@@ -200,6 +203,7 @@ static const char* RAKNET_MESSAGEID_STRINGS[] = {
     "ID_RESERVED_9",
     "ID_RESERVED_9",
     "ID_USER_PACKET_ENUM"
     "ID_USER_PACKET_ENUM"
 };
 };
+#endif
 
 
 static const int DEFAULT_UPDATE_FPS = 30;
 static const int DEFAULT_UPDATE_FPS = 30;
 static const int SERVER_TIMEOUT_TIME = 10000;
 static const int SERVER_TIMEOUT_TIME = 10000;
@@ -220,16 +224,20 @@ Network::Network(Context* context) :
     wsClient_ = nullptr;
     wsClient_ = nullptr;
     wsServer_ = nullptr;
     wsServer_ = nullptr;
 
 
+#ifndef __EMSCRIPTEN__
     rakPeer_ = SLNet::RakPeerInterface::GetInstance();
     rakPeer_ = SLNet::RakPeerInterface::GetInstance();
     rakPeerClient_ = SLNet::RakPeerInterface::GetInstance();
     rakPeerClient_ = SLNet::RakPeerInterface::GetInstance();
     rakPeer_->SetTimeoutTime(SERVER_TIMEOUT_TIME, SLNet::UNASSIGNED_SYSTEM_ADDRESS);
     rakPeer_->SetTimeoutTime(SERVER_TIMEOUT_TIME, SLNet::UNASSIGNED_SYSTEM_ADDRESS);
+#endif
+
     SetPassword("");
     SetPassword("");
     SetDiscoveryBeacon(VariantMap());
     SetDiscoveryBeacon(VariantMap());
 
 
+#ifndef __EMSCRIPTEN__
     natPunchthroughClient_ = new SLNet::NatPunchthroughClient;
     natPunchthroughClient_ = new SLNet::NatPunchthroughClient;
     natPunchthroughServerClient_ = new SLNet::NatPunchthroughClient;
     natPunchthroughServerClient_ = new SLNet::NatPunchthroughClient;
-
     SetNATServerInfo("127.0.0.1", 61111);
     SetNATServerInfo("127.0.0.1", 61111);
+#endif
 
 
     // Register Network library object factories
     // Register Network library object factories
     RegisterNetworkLibrary(context_);
     RegisterNetworkLibrary(context_);
@@ -283,13 +291,18 @@ Network::Network(Context* context) :
 
 
 Network::~Network()
 Network::~Network()
 {
 {
+#ifndef __EMSCRIPTEN__
     rakPeer_->DetachPlugin(natPunchthroughServerClient_);
     rakPeer_->DetachPlugin(natPunchthroughServerClient_);
     rakPeerClient_->DetachPlugin(natPunchthroughClient_);
     rakPeerClient_->DetachPlugin(natPunchthroughClient_);
+#endif
+
     // If server connection exists, disconnect, but do not send an event because we are shutting down
     // If server connection exists, disconnect, but do not send an event because we are shutting down
     Disconnect(100);
     Disconnect(100);
     serverConnection_.Reset();
     serverConnection_.Reset();
 
 
+#ifndef __EMSCRIPTEN__
     clientConnections_.Clear();
     clientConnections_.Clear();
+#endif
 
 
     delete natPunchthroughServerClient_;
     delete natPunchthroughServerClient_;
     natPunchthroughServerClient_ = nullptr;
     natPunchthroughServerClient_ = nullptr;
@@ -300,12 +313,16 @@ Network::~Network()
     delete natPunchServerAddress_;
     delete natPunchServerAddress_;
     natPunchServerAddress_ = nullptr;
     natPunchServerAddress_ = nullptr;
 
 
+#ifndef __EMSCRIPTEN__
     SLNet::RakPeerInterface::DestroyInstance(rakPeer_);
     SLNet::RakPeerInterface::DestroyInstance(rakPeer_);
     SLNet::RakPeerInterface::DestroyInstance(rakPeerClient_);
     SLNet::RakPeerInterface::DestroyInstance(rakPeerClient_);
+#endif
+
     rakPeer_ = nullptr;
     rakPeer_ = nullptr;
     rakPeerClient_ = nullptr;
     rakPeerClient_ = nullptr;
 }
 }
 
 
+#ifndef __EMSCRIPTEN__
 void Network::HandleMessage(const SLNet::AddressOrGUID& source, int packetID, int msgID, const char* data, size_t numBytes)
 void Network::HandleMessage(const SLNet::AddressOrGUID& source, int packetID, int msgID, const char* data, size_t numBytes)
 {
 {
     // Only process messages from known sources
     // Only process messages from known sources
@@ -319,6 +336,7 @@ void Network::HandleMessage(const SLNet::AddressOrGUID& source, int packetID, in
     else
     else
         URHO3D_LOGWARNING("Discarding message from unknown MessageConnection " + String(source.ToString()));
         URHO3D_LOGWARNING("Discarding message from unknown MessageConnection " + String(source.ToString()));
 }
 }
+#endif
 
 
 void Network::NewConnectionEstablished(const SharedPtr<Connection> newConnection)
 void Network::NewConnectionEstablished(const SharedPtr<Connection> newConnection)
 {
 {
@@ -329,6 +347,7 @@ void Network::NewConnectionEstablished(const SharedPtr<Connection> newConnection
     newConnection->SendEvent(E_CLIENTCONNECTED, eventData);
     newConnection->SendEvent(E_CLIENTCONNECTED, eventData);
 }
 }
 
 
+#ifndef __EMSCRIPTEN__
 void Network::NewConnectionEstablished(const SLNet::AddressOrGUID& connection)
 void Network::NewConnectionEstablished(const SLNet::AddressOrGUID& connection)
 {
 {
     // Create a new client connection corresponding to this MessageConnection
     // Create a new client connection corresponding to this MessageConnection
@@ -339,6 +358,7 @@ void Network::NewConnectionEstablished(const SLNet::AddressOrGUID& connection)
 
 
     NewConnectionEstablished(clientConnections_[connection]);
     NewConnectionEstablished(clientConnections_[connection]);
 }
 }
+#endif
 
 
 void Network::NewConnectionEstablished(const WSConnection& ws)
 void Network::NewConnectionEstablished(const WSConnection& ws)
 {
 {
@@ -376,6 +396,7 @@ void Network::ClientDisconnected(const WSConnection& ws)
 #endif
 #endif
 }
 }
 
 
+#ifndef __EMSCRIPTEN__
 void Network::ClientDisconnected(const SLNet::AddressOrGUID& connection)
 void Network::ClientDisconnected(const SLNet::AddressOrGUID& connection)
 {
 {
     // Remove the client connection that corresponds to this MessageConnection
     // Remove the client connection that corresponds to this MessageConnection
@@ -394,18 +415,22 @@ void Network::ClientDisconnected(const SLNet::AddressOrGUID& connection)
         clientConnections_.Erase(i);
         clientConnections_.Erase(i);
     }
     }
 }
 }
+#endif
 
 
 void Network::SetDiscoveryBeacon(const VariantMap& data)
 void Network::SetDiscoveryBeacon(const VariantMap& data)
 {
 {
+#ifndef __EMSCRIPTEN__
     VectorBuffer buffer;
     VectorBuffer buffer;
     buffer.WriteVariantMap(data);
     buffer.WriteVariantMap(data);
     if (buffer.GetSize() > 400)
     if (buffer.GetSize() > 400)
         URHO3D_LOGERROR("Discovery beacon of size: " + String(buffer.GetSize()) + " bytes is too large, modify MAX_OFFLINE_DATA_LENGTH in RakNet or reduce size");
         URHO3D_LOGERROR("Discovery beacon of size: " + String(buffer.GetSize()) + " bytes is too large, modify MAX_OFFLINE_DATA_LENGTH in RakNet or reduce size");
     rakPeer_->SetOfflinePingResponse((const char*)buffer.GetData(), buffer.GetSize());
     rakPeer_->SetOfflinePingResponse((const char*)buffer.GetData(), buffer.GetSize());
+#endif
 }
 }
 
 
 void Network::DiscoverHosts(unsigned port)
 void Network::DiscoverHosts(unsigned port)
 {
 {
+#ifndef __EMSCRIPTEN__
     // JSandusky: Contrary to the manual, we actually do have to perform Startup first before we can Ping
     // JSandusky: Contrary to the manual, we actually do have to perform Startup first before we can Ping
     if (!rakPeerClient_->IsActive())
     if (!rakPeerClient_->IsActive())
     {
     {
@@ -414,16 +439,20 @@ void Network::DiscoverHosts(unsigned port)
         rakPeerClient_->Startup(1, &socket, 1);
         rakPeerClient_->Startup(1, &socket, 1);
     }
     }
     rakPeerClient_->Ping("255.255.255.255", port, false);
     rakPeerClient_->Ping("255.255.255.255", port, false);
+#endif
 }
 }
 
 
 void Network::SetPassword(const String& password)
 void Network::SetPassword(const String& password)
 {
 {
+#ifndef __EMSCRIPTEN__
     rakPeer_->SetIncomingPassword(password.CString(), password.Length());
     rakPeer_->SetIncomingPassword(password.CString(), password.Length());
+#endif
     password_ = password;
     password_ = password;
 }
 }
 
 
 bool Network::Connect(const String& address, unsigned short port, Scene* scene, const VariantMap& identity)
 bool Network::Connect(const String& address, unsigned short port, Scene* scene, const VariantMap& identity)
 {
 {
+#ifndef __EMSCRIPTEN__
     URHO3D_PROFILE(Connect);
     URHO3D_PROFILE(Connect);
 
 
     if (!rakPeerClient_->IsActive())
     if (!rakPeerClient_->IsActive())
@@ -463,6 +492,7 @@ bool Network::Connect(const String& address, unsigned short port, Scene* scene,
         SendEvent(E_CONNECTFAILED);
         SendEvent(E_CONNECTFAILED);
         return false;
         return false;
     }
     }
+#endif
 }
 }
 
 
 bool Network::ConnectWS(const String& address, unsigned short port, Scene* scene, const VariantMap& identity)
 bool Network::ConnectWS(const String& address, unsigned short port, Scene* scene, const VariantMap& identity)
@@ -496,6 +526,7 @@ void Network::Disconnect(int waitMSec)
 
 
 bool Network::StartServer(unsigned short port, unsigned int maxConnections)
 bool Network::StartServer(unsigned short port, unsigned int maxConnections)
 {
 {
+#ifndef __EMSCRIPTEN__
     if (IsUDPServerRunning())
     if (IsUDPServerRunning())
         return true;
         return true;
 
 
@@ -521,6 +552,9 @@ bool Network::StartServer(unsigned short port, unsigned int maxConnections)
         URHO3D_LOGINFO("Failed to start server on port " + String(port) + ", error code: " + String((int)startResult));
         URHO3D_LOGINFO("Failed to start server on port " + String(port) + ", error code: " + String((int)startResult));
         return false;
         return false;
     }
     }
+#else
+    return false;
+#endif
 }
 }
 
 
 
 
@@ -548,14 +582,17 @@ bool Network::StartWSServer(unsigned short port, unsigned int maxConnections)
 
 
 void Network::StopServer()
 void Network::StopServer()
 {
 {
+#ifndef __EMSCRIPTEN__
     clientConnections_.Clear();
     clientConnections_.Clear();
     URHO3D_PROFILE(StopServer);
     URHO3D_PROFILE(StopServer);
     StopUDPServer();
     StopUDPServer();
     StopWSServer();
     StopWSServer();
+#endif
 }
 }
 
 
 void Network::StopUDPServer()
 void Network::StopUDPServer()
 {
 {
+#ifndef __EMSCRIPTEN__
     clientConnections_.Clear();
     clientConnections_.Clear();
     URHO3D_PROFILE(StopUDPServer);
     URHO3D_PROFILE(StopUDPServer);
 
 
@@ -569,10 +606,12 @@ void Network::StopUDPServer()
 
 
         URHO3D_LOGINFO("Stopped UDP server");
         URHO3D_LOGINFO("Stopped UDP server");
     }
     }
+#endif
 }
 }
 
 
 void Network::StopWSServer()
 void Network::StopWSServer()
 {
 {
+#ifndef __EMSCRIPTEN__
     clientConnections_.Clear();
     clientConnections_.Clear();
     URHO3D_PROFILE(StopWSServer);
     URHO3D_PROFILE(StopWSServer);
 
 
@@ -585,18 +624,22 @@ void Network::StopWSServer()
         URHO3D_LOGINFO("Stopped Websockets server");
         URHO3D_LOGINFO("Stopped Websockets server");
     }
     }
 #endif
 #endif
+#endif
 }
 }
 
 
 void Network::SetNATServerInfo(const String& address, unsigned short port)
 void Network::SetNATServerInfo(const String& address, unsigned short port)
 {
 {
+#ifndef __EMSCRIPTEN__
     if (!natPunchServerAddress_)
     if (!natPunchServerAddress_)
         natPunchServerAddress_ = new SLNet::SystemAddress;
         natPunchServerAddress_ = new SLNet::SystemAddress;
 
 
     natPunchServerAddress_->FromStringExplicitPort(address.CString(), port);
     natPunchServerAddress_->FromStringExplicitPort(address.CString(), port);
+#endif
 }
 }
 
 
 void Network::StartNATClient()
 void Network::StartNATClient()
 {
 {
+#ifndef __EMSCRIPTEN__
     if (!rakPeer_) {
     if (!rakPeer_) {
         URHO3D_LOGERROR("Unable to start NAT client, client not initialized!");
         URHO3D_LOGERROR("Unable to start NAT client, client not initialized!");
         return;
         return;
@@ -610,10 +653,12 @@ void Network::StartNATClient()
     guid_ = String(rakPeer_->GetGuidFromSystemAddress(SLNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
     guid_ = String(rakPeer_->GetGuidFromSystemAddress(SLNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
     URHO3D_LOGINFO("GUID: " + guid_);
     URHO3D_LOGINFO("GUID: " + guid_);
     rakPeer_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
     rakPeer_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
+#endif
 }
 }
 
 
 void Network::AttemptNATPunchtrough(const String& guid, Scene* scene, const VariantMap& identity)
 void Network::AttemptNATPunchtrough(const String& guid, Scene* scene, const VariantMap& identity)
 {
 {
+#ifndef __EMSCRIPTEN__
     scene_ = scene;
     scene_ = scene;
     identity_ = identity;
     identity_ = identity;
     if (!remoteGUID_)
     if (!remoteGUID_)
@@ -631,6 +676,7 @@ void Network::AttemptNATPunchtrough(const String& guid, Scene* scene, const Vari
     }
     }
 
 
     rakPeerClient_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
     rakPeerClient_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
+#endif
 }
 }
 
 
 void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const VectorBuffer& msg, unsigned contentID)
 void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const VectorBuffer& msg, unsigned contentID)
@@ -641,6 +687,7 @@ void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const Vec
 void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const unsigned char* data, unsigned numBytes,
 void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const unsigned char* data, unsigned numBytes,
     unsigned contentID)
     unsigned contentID)
 {
 {
+#ifndef __EMSCRIPTEN__
     if (!rakPeer_) 
     if (!rakPeer_) 
         return;
         return;
 
 
@@ -653,22 +700,54 @@ void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const uns
         rakPeer_->Send((const char*)msgData.GetData(), (int)msgData.GetSize(), HIGH_PRIORITY, RELIABLE, (char)0, SLNet::UNASSIGNED_RAKNET_GUID, true);
         rakPeer_->Send((const char*)msgData.GetData(), (int)msgData.GetSize(), HIGH_PRIORITY, RELIABLE, (char)0, SLNet::UNASSIGNED_RAKNET_GUID, true);
     else
     else
         URHO3D_LOGERROR("Server not running, can not broadcast messages");
         URHO3D_LOGERROR("Server not running, can not broadcast messages");
+#endif
+
+#ifdef URHO3D_WEBSOCKETS
+    if (wsServer_) {
+        VectorBuffer msgData;
+        msgData.WriteUByte((unsigned char)URHO3D_MESSAGE);
+        msgData.WriteUInt((unsigned int)msgID);
+        msgData.Write(data, numBytes);
+
+        for (HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Begin();
+             i != websocketClientConnections_.End(); ++i)
+        {
+            wsServer_->AddOutgoingPacket(WSPacket(i->second_->GetWS(), msgData));
+        }
+    }
+#endif
 }
 }
 
 
 void Network::BroadcastRemoteEvent(StringHash eventType, bool inOrder, const VariantMap& eventData)
 void Network::BroadcastRemoteEvent(StringHash eventType, bool inOrder, const VariantMap& eventData)
 {
 {
+#ifndef __EMSCRIPTEN__
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin(); i != clientConnections_.End(); ++i)
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin(); i != clientConnections_.End(); ++i)
         i->second_->SendRemoteEvent(eventType, inOrder, eventData);
         i->second_->SendRemoteEvent(eventType, inOrder, eventData);
+#endif
+
+#ifdef URHO3D_WEBSOCKETS
+    for (HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Begin();
+         i != websocketClientConnections_.End(); ++i)
+        i->second_->SendRemoteEvent(eventType, inOrder, eventData);
+#endif
 }
 }
 
 
 void Network::BroadcastRemoteEvent(Scene* scene, StringHash eventType, bool inOrder, const VariantMap& eventData)
 void Network::BroadcastRemoteEvent(Scene* scene, StringHash eventType, bool inOrder, const VariantMap& eventData)
 {
 {
+#ifndef __EMSCRIPTEN__
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
          i != clientConnections_.End(); ++i)
          i != clientConnections_.End(); ++i)
     {
     {
         if (i->second_->GetScene() == scene)
         if (i->second_->GetScene() == scene)
             i->second_->SendRemoteEvent(eventType, inOrder, eventData);
             i->second_->SendRemoteEvent(eventType, inOrder, eventData);
     }
     }
+#endif
+
+#ifdef URHO3D_WEBSOCKETS
+    for (HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Begin();
+         i != websocketClientConnections_.End(); ++i)
+        i->second_->SendRemoteEvent(eventType, inOrder, eventData);
+#endif
 }
 }
 
 
 void Network::BroadcastRemoteEvent(Node* node, StringHash eventType, bool inOrder, const VariantMap& eventData)
 void Network::BroadcastRemoteEvent(Node* node, StringHash eventType, bool inOrder, const VariantMap& eventData)
@@ -685,12 +764,22 @@ void Network::BroadcastRemoteEvent(Node* node, StringHash eventType, bool inOrde
     }
     }
 
 
     Scene* scene = node->GetScene();
     Scene* scene = node->GetScene();
+#ifndef __EMSCRIPTEN__
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
          i != clientConnections_.End(); ++i)
          i != clientConnections_.End(); ++i)
     {
     {
         if (i->second_->GetScene() == scene)
         if (i->second_->GetScene() == scene)
             i->second_->SendRemoteEvent(node, eventType, inOrder, eventData);
             i->second_->SendRemoteEvent(node, eventType, inOrder, eventData);
     }
     }
+
+#endif
+
+#ifdef URHO3D_WEBSOCKETS
+    for (HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Begin();
+         i != websocketClientConnections_.End(); ++i)
+        if (i->second_->GetScene() == scene)
+            i->second_->SendRemoteEvent(node, eventType, inOrder, eventData);
+#endif
 }
 }
 
 
 void Network::SetUpdateFps(int fps)
 void Network::SetUpdateFps(int fps)
@@ -751,12 +840,21 @@ void Network::SendPackageToClients(Scene* scene, PackageFile* package)
         return;
         return;
     }
     }
 
 
+#ifndef __EMSCRIPTEN__
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
          i != clientConnections_.End(); ++i)
          i != clientConnections_.End(); ++i)
     {
     {
         if (i->second_->GetScene() == scene)
         if (i->second_->GetScene() == scene)
             i->second_->SendPackageToClient(package);
             i->second_->SendPackageToClient(package);
     }
     }
+#endif
+
+    for (HashMap<WSConnection, SharedPtr<Connection> >::Iterator i = websocketClientConnections_.Begin();
+         i != websocketClientConnections_.End(); ++i)
+    {
+        if (i->second_->GetScene() == scene)
+            i->second_->SendPackageToClient(package);
+    }
 }
 }
 
 
 SharedPtr<HttpRequest> Network::MakeHttpRequest(const String& url, const String& verb, const Vector<String>& headers,
 SharedPtr<HttpRequest> Network::MakeHttpRequest(const String& url, const String& verb, const Vector<String>& headers,
@@ -771,9 +869,12 @@ SharedPtr<HttpRequest> Network::MakeHttpRequest(const String& url, const String&
 
 
 void Network::BanAddress(const String& address)
 void Network::BanAddress(const String& address)
 {
 {
+#ifndef __EMSCRIPTEN__
     rakPeer_->AddToBanList(address.CString(), 0);
     rakPeer_->AddToBanList(address.CString(), 0);
+#endif
 }
 }
 
 
+#ifndef __EMSCRIPTEN__
 Connection* Network::GetConnection(const SLNet::AddressOrGUID& connection) const
 Connection* Network::GetConnection(const SLNet::AddressOrGUID& connection) const
 {
 {
     if (serverConnection_ && serverConnection_->GetAddressOrGUID() == connection)
     if (serverConnection_ && serverConnection_->GetAddressOrGUID() == connection)
@@ -787,6 +888,7 @@ Connection* Network::GetConnection(const SLNet::AddressOrGUID& connection) const
             return nullptr;
             return nullptr;
     }
     }
 }
 }
+#endif
 
 
 Connection* Network::GetConnection(const WSConnection& ws) const
 Connection* Network::GetConnection(const WSConnection& ws) const
 {
 {
@@ -796,7 +898,7 @@ Connection* Network::GetConnection(const WSConnection& ws) const
     else
     else
     {
     {
         HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Find(WSConnection(ws));
         HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Find(WSConnection(ws));
-        if (i != clientConnections_.End())
+        if (i != websocketClientConnections_.End())
             return i->second_;
             return i->second_;
         else
         else
             return nullptr;
             return nullptr;
@@ -815,9 +917,11 @@ Connection* Network::GetServerConnection() const
 Vector<SharedPtr<Connection> > Network::GetClientConnections() const
 Vector<SharedPtr<Connection> > Network::GetClientConnections() const
 {
 {
     Vector<SharedPtr<Connection> > ret;
     Vector<SharedPtr<Connection> > ret;
+#ifndef __EMSCRIPTEN__
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::ConstIterator i = clientConnections_.Begin();
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::ConstIterator i = clientConnections_.Begin();
          i != clientConnections_.End(); ++i)
          i != clientConnections_.End(); ++i)
         ret.Push(i->second_);
         ret.Push(i->second_);
+#endif
 
 
 #ifdef URHO3D_WEBSOCKETS
 #ifdef URHO3D_WEBSOCKETS
     for (HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Begin();
     for (HashMap<WSConnection, SharedPtr<Connection> >::ConstIterator i = websocketClientConnections_.Begin();
@@ -835,10 +939,14 @@ bool Network::IsServerRunning() const
 
 
 bool Network::IsUDPServerRunning() const
 bool Network::IsUDPServerRunning() const
 {
 {
+#ifndef __EMSCRIPTEN__
     if (!rakPeer_)
     if (!rakPeer_)
         return false;
         return false;
 
 
     return rakPeer_->IsActive() && isServer_;
     return rakPeer_->IsActive() && isServer_;
+#else
+    return false;
+#endif
 }
 }
 
 
 bool Network::IsWSServerRunning() const
 bool Network::IsWSServerRunning() const
@@ -856,6 +964,7 @@ bool Network::CheckRemoteEvent(StringHash eventType) const
 
 
 void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
 void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
 {
 {
+#ifndef __EMSCRIPTEN__
     unsigned char packetID = packet->data[0];
     unsigned char packetID = packet->data[0];
     bool packetHandled = false;
     bool packetHandled = false;
 
 
@@ -1045,7 +1154,7 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
         URHO3D_LOGERROR("Unhandled network packet: " + String(RAKNET_MESSAGEID_STRINGS[packetID]));
         URHO3D_LOGERROR("Unhandled network packet: " + String(RAKNET_MESSAGEID_STRINGS[packetID]));
     else if (!packetHandled)
     else if (!packetHandled)
         URHO3D_LOGERRORF("Unhandled network packet: %i", packetID);
         URHO3D_LOGERRORF("Unhandled network packet: %i", packetID);
-
+#endif
 }
 }
 
 
 void Network::HandleIncomingPacket(const WSPacket* packet, bool isServer)
 void Network::HandleIncomingPacket(const WSPacket* packet, bool isServer)
@@ -1097,6 +1206,8 @@ void Network::Update(float timeStep)
         wsClient_->Update(timeStep);
         wsClient_->Update(timeStep);
     }
     }
 #endif
 #endif
+
+#ifndef __EMSCRIPTEN__
     //Process all incoming messages for the server
     //Process all incoming messages for the server
     if (rakPeer_->IsActive())
     if (rakPeer_->IsActive())
     {
     {
@@ -1116,6 +1227,7 @@ void Network::Update(float timeStep)
             rakPeerClient_->DeallocatePacket(packet);
             rakPeerClient_->DeallocatePacket(packet);
         }
         }
     }
     }
+#endif
 }
 }
 
 
 void Network::PostUpdate(float timeStep)
 void Network::PostUpdate(float timeStep)
@@ -1138,6 +1250,7 @@ void Network::PostUpdate(float timeStep)
                 URHO3D_PROFILE(PrepareServerUpdate);
                 URHO3D_PROFILE(PrepareServerUpdate);
 
 
                 networkScenes_.Clear();
                 networkScenes_.Clear();
+#ifndef __EMSCRIPTEN__
                 for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
                 for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
                      i != clientConnections_.End(); ++i)
                      i != clientConnections_.End(); ++i)
                 {
                 {
@@ -1145,6 +1258,7 @@ void Network::PostUpdate(float timeStep)
                     if (scene)
                     if (scene)
                         networkScenes_.Insert(scene);
                         networkScenes_.Insert(scene);
                 }
                 }
+#endif
 
 
 #ifdef URHO3D_WEBSOCKETS
 #ifdef URHO3D_WEBSOCKETS
                 for (HashMap<WSConnection, SharedPtr<Connection> >::Iterator i = websocketClientConnections_.Begin();
                 for (HashMap<WSConnection, SharedPtr<Connection> >::Iterator i = websocketClientConnections_.Begin();
@@ -1163,6 +1277,7 @@ void Network::PostUpdate(float timeStep)
             {
             {
                 URHO3D_PROFILE(SendServerUpdate);
                 URHO3D_PROFILE(SendServerUpdate);
 
 
+#ifndef __EMSCRIPTEN__
                 // Then send server updates for each UDP client connection
                 // Then send server updates for each UDP client connection
                 for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
                 for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
                      i != clientConnections_.End(); ++i)
                      i != clientConnections_.End(); ++i)
@@ -1172,6 +1287,7 @@ void Network::PostUpdate(float timeStep)
                     i->second_->SendPackages();
                     i->second_->SendPackages();
                     i->second_->SendAllBuffers();
                     i->second_->SendAllBuffers();
                 }
                 }
+#endif
 
 
 #ifdef URHO3D_WEBSOCKETS
 #ifdef URHO3D_WEBSOCKETS
                 // Then send server updates for each Websocket client connection
                 // Then send server updates for each Websocket client connection
@@ -1214,6 +1330,7 @@ void Network::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
     PostUpdate(eventData[P_TIMESTEP].GetFloat());
     PostUpdate(eventData[P_TIMESTEP].GetFloat());
 }
 }
 
 
+#ifndef __EMSCRIPTEN__
 void Network::OnServerConnected(const SLNet::AddressOrGUID& address)
 void Network::OnServerConnected(const SLNet::AddressOrGUID& address)
 {
 {
     serverConnection_->SetConnectPending(false);
     serverConnection_->SetConnectPending(false);
@@ -1227,6 +1344,7 @@ void Network::OnServerConnected(const SLNet::AddressOrGUID& address)
 
 
     SendEvent(E_SERVERCONNECTED);
     SendEvent(E_SERVERCONNECTED);
 }
 }
+#endif
 
 
 void Network::OnServerConnected(const WSConnection& ws)
 void Network::OnServerConnected(const WSConnection& ws)
 {
 {
@@ -1244,7 +1362,7 @@ void Network::OnServerConnected(const WSConnection& ws)
 #endif
 #endif
 }
 }
 
 
-
+#ifndef __EMSCRIPTEN__
 void Network::OnServerDisconnected(const SLNet::AddressOrGUID& address)
 void Network::OnServerDisconnected(const SLNet::AddressOrGUID& address)
 {
 {
     if (natPunchServerAddress_ && *natPunchServerAddress_ == address.systemAddress) {
     if (natPunchServerAddress_ && *natPunchServerAddress_ == address.systemAddress) {
@@ -1267,6 +1385,7 @@ void Network::OnServerDisconnected(const SLNet::AddressOrGUID& address)
         SendEvent(E_CONNECTFAILED);
         SendEvent(E_CONNECTFAILED);
     }
     }
 }
 }
+#endif
 
 
 void Network::OnServerDisconnected(const WSConnection& ws, bool failedConnect)
 void Network::OnServerDisconnected(const WSConnection& ws, bool failedConnect)
 {
 {
@@ -1296,9 +1415,11 @@ void Network::ConfigureNetworkSimulator()
     if (serverConnection_)
     if (serverConnection_)
         serverConnection_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
         serverConnection_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
 
 
+#ifndef __EMSCRIPTEN__
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
     for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
          i != clientConnections_.End(); ++i)
          i != clientConnections_.End(); ++i)
         i->second_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
         i->second_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
+#endif
 }
 }
 
 
 void RegisterNetworkLibrary(Context* context)
 void RegisterNetworkLibrary(Context* context)

+ 14 - 6
Source/Urho3D/Network/Network.h

@@ -53,18 +53,20 @@ public:
     /// Destruct.
     /// Destruct.
     ~Network() override;
     ~Network() override;
 
 
-    /// Handle an inbound message.
-    void HandleMessage(const SLNet::AddressOrGUID& source, int packetID, int msgID, const char* data, size_t numBytes);
+#ifndef __EMSCRIPTEN__
+        /// Handle an inbound message.
+        void HandleMessage(const SLNet::AddressOrGUID& source, int packetID, int msgID, const char* data, size_t numBytes);
+        /// Handle new UDP client connection.
+        void NewConnectionEstablished(const SLNet::AddressOrGUID& connection);
+        /// Handle a client disconnection.
+        void ClientDisconnected(const SLNet::AddressOrGUID& connection);
+#endif
     // Handle new client connection
     // Handle new client connection
     void NewConnectionEstablished(const SharedPtr<Connection> newConnection);
     void NewConnectionEstablished(const SharedPtr<Connection> newConnection);
-    /// Handle new UDP client connection.
-    void NewConnectionEstablished(const SLNet::AddressOrGUID& connection);
     /// Handle new Websockets client connection.
     /// Handle new Websockets client connection.
     void NewConnectionEstablished(const WSConnection& ws);
     void NewConnectionEstablished(const WSConnection& ws);
     /// Handle a client disconnection.
     /// Handle a client disconnection.
     void ClientDisconnected(const WSConnection& ws);
     void ClientDisconnected(const WSConnection& ws);
-    /// Handle a client disconnection.
-    void ClientDisconnected(const SLNet::AddressOrGUID& connection);
 
 
     /// Set the data that will be used for a reply to attempts at host discovery on LAN/subnet.
     /// Set the data that will be used for a reply to attempts at host discovery on LAN/subnet.
     void SetDiscoveryBeacon(const VariantMap& data);
     void SetDiscoveryBeacon(const VariantMap& data);
@@ -140,8 +142,10 @@ public:
     /// Return simulated packet loss probability.
     /// Return simulated packet loss probability.
     float GetSimulatedPacketLoss() const { return simulatedPacketLoss_; }
     float GetSimulatedPacketLoss() const { return simulatedPacketLoss_; }
 
 
+#ifndef __EMSCRIPTEN__
     /// Return a client or server connection by RakNet connection address, or null if none exist.
     /// Return a client or server connection by RakNet connection address, or null if none exist.
     Connection* GetConnection(const SLNet::AddressOrGUID& connection) const;
     Connection* GetConnection(const SLNet::AddressOrGUID& connection) const;
+#endif
     /// Return the connection to the server. Null if not connected.
     /// Return the connection to the server. Null if not connected.
     Connection* GetServerConnection() const;
     Connection* GetServerConnection() const;
     /// Return all client connections.
     /// Return all client connections.
@@ -168,10 +172,12 @@ private:
     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
     /// Handle render update frame event.
     /// Handle render update frame event.
     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
+#ifndef __EMSCRIPTEN__
     /// Handle server connection.
     /// Handle server connection.
     void OnServerConnected(const SLNet::AddressOrGUID& address);
     void OnServerConnected(const SLNet::AddressOrGUID& address);
     /// Handle UDP server disconnection.
     /// Handle UDP server disconnection.
     void OnServerDisconnected(const SLNet::AddressOrGUID& address);
     void OnServerDisconnected(const SLNet::AddressOrGUID& address);
+#endif
     /// Handle Websockets server disconnection.
     /// Handle Websockets server disconnection.
     void OnServerDisconnected(const WSConnection& ws, bool failedConnect = false);
     void OnServerDisconnected(const WSConnection& ws, bool failedConnect = false);
     /// Reconfigure network simulator parameters on all existing connections.
     /// Reconfigure network simulator parameters on all existing connections.
@@ -187,8 +193,10 @@ private:
     SLNet::RakPeerInterface* rakPeerClient_;
     SLNet::RakPeerInterface* rakPeerClient_;
     /// Client's server connection.
     /// Client's server connection.
     SharedPtr<Connection> serverConnection_;
     SharedPtr<Connection> serverConnection_;
+#ifndef __EMSCRIPTEN__
     /// SLikeNet server's client connections.
     /// SLikeNet server's client connections.
     HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> > clientConnections_;
     HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> > clientConnections_;
+#endif
     /// Websocket server's client connections.
     /// Websocket server's client connections.
     HashMap<WSConnection, SharedPtr<Connection> > websocketClientConnections_;
     HashMap<WSConnection, SharedPtr<Connection> > websocketClientConnections_;
     /// Allowed remote events.
     /// Allowed remote events.

+ 134 - 7
Source/Urho3D/Network/WS/WSClient.cpp

@@ -32,8 +32,11 @@
 #include <libwebsockets.h>
 #include <libwebsockets.h>
 #include <string.h>
 #include <string.h>
 
 
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
 static Urho3D::WSClient* WSClientInstance = nullptr;
 static Urho3D::WSClient* WSClientInstance = nullptr;
-static struct lws_context *context;
 
 
 #if defined(WIN32)
 #if defined(WIN32)
 #define HAVE_STRUCT_TIMESPEC
 #define HAVE_STRUCT_TIMESPEC
@@ -42,14 +45,17 @@ static struct lws_context *context;
 #endif
 #endif
 #endif
 #endif
 
 
+#ifndef __EMSCRIPTEN__
 static struct lws *client_wsi;
 static struct lws *client_wsi;
 static lws_sorted_usec_list_t sul;
 static lws_sorted_usec_list_t sul;
-
+static struct lws_context *context;
 static const lws_retry_bo_t retry = {
 static const lws_retry_bo_t retry = {
         .secs_since_valid_ping = 3,
         .secs_since_valid_ping = 3,
         .secs_since_valid_hangup = 10,
         .secs_since_valid_hangup = 10,
 };
 };
+#endif
 
 
+#ifndef __EMSCRIPTEN__
 static void connect_cb(lws_sorted_usec_list_t *_sul)
 static void connect_cb(lws_sorted_usec_list_t *_sul)
 {
 {
     struct lws_client_connect_info i;
     struct lws_client_connect_info i;
@@ -74,6 +80,7 @@ static void connect_cb(lws_sorted_usec_list_t *_sul)
     if (!lws_client_connect_via_info(&i))
     if (!lws_client_connect_via_info(&i))
         lws_sul_schedule(context, 0, _sul, connect_cb, 5 * LWS_USEC_PER_SEC);
         lws_sul_schedule(context, 0, _sul, connect_cb, 5 * LWS_USEC_PER_SEC);
 }
 }
+#endif
 
 
 static int WSCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
 static int WSCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
 {
 {
@@ -110,6 +117,34 @@ static int WSCallback(struct lws *wsi, enum lws_callback_reasons reason, void *u
 
 
         case LWS_CALLBACK_CLIENT_WRITEABLE:
         case LWS_CALLBACK_CLIENT_WRITEABLE:
             if (WSClientInstance) {
             if (WSClientInstance) {
+#ifdef __EMSCRIPTEN__
+                if(WSClientInstance->GetNumOutgoingPackets(wsi))
+                {
+                    auto packet = WSClientInstance->GetOutgoingPacket(wsi);
+                    if (packet)
+                    {
+                        return EM_ASM_INT({
+                            var socket = Module.__libwebsocket.socket;
+                            if( ! socket ) {
+                                return -1;
+                            }
+
+                            // alloc a Uint8Array backed by the incoming data.
+                            var data_in = new Uint8Array(Module.HEAPU8.buffer, $1, $2 );
+                            // allow the dest array
+                            var data = new Uint8Array($2);
+                            // set the dest from the src
+                            data.set(data_in);
+
+                            socket.send( data );
+
+                            return $2;
+
+                        }, packet->second_.GetData(), packet->second_.GetSize());
+                        WSClientInstance->RemoveOutgoingPacket(wsi);
+                    }
+                }
+#else
                 if(WSClientInstance->GetNumOutgoingPackets(wsi)) {
                 if(WSClientInstance->GetNumOutgoingPackets(wsi)) {
                     auto packet = WSClientInstance->GetOutgoingPacket(wsi);
                     auto packet = WSClientInstance->GetOutgoingPacket(wsi);
                     if (packet) {
                     if (packet) {
@@ -124,6 +159,7 @@ static int WSCallback(struct lws *wsi, enum lws_callback_reasons reason, void *u
                     }
                     }
                 }
                 }
                 lws_callback_on_writable(wsi);
                 lws_callback_on_writable(wsi);
+#endif
             }
             }
             break;
             break;
 
 
@@ -141,20 +177,32 @@ static int WSCallback(struct lws *wsi, enum lws_callback_reasons reason, void *u
     return 0;
     return 0;
 }
 }
 
 
+#ifdef __EMSCRIPTEN__
+extern "C" int EMSCRIPTEN_KEEPALIVE WSHelper(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len ) {
+        return WSCallback(wsi, reason, user, in, len);
+}
+#endif
 
 
+#ifndef __EMSCRIPTEN__
 static const struct lws_protocols protocols[] = {
 static const struct lws_protocols protocols[] = {
         {"ws_client", WSCallback,0,0,},
         {"ws_client", WSCallback,0,0,},
         { NULL, NULL, 0, 0 }
         { NULL, NULL, 0, 0 }
 };
 };
+#endif
 
 
 using namespace Urho3D;
 using namespace Urho3D;
 
 
 static void RunService(const WorkItem* item, unsigned threadIndex) {
 static void RunService(const WorkItem* item, unsigned threadIndex) {
+#ifdef __EMSCRIPTEN
+    // Trigger writing on the socket
+    WSCallback(nullptr, LWS_CALLBACK_CLIENT_WRITEABLE, nullptr, nullptr, 0);
+#else
     int result = lws_service(context, 0);
     int result = lws_service(context, 0);
     if (result < 0 && WSClientInstance) {
     if (result < 0 && WSClientInstance) {
         WSClientInstance->Disconnect();
         WSClientInstance->Disconnect();
     }
     }
     URHO3D_LOGINFOF("Running client service");
     URHO3D_LOGINFOF("Running client service");
+#endif
 }
 }
 
 
 WSClient::WSClient(Context* context):
 WSClient::WSClient(Context* context):
@@ -172,13 +220,16 @@ WSClient::~WSClient()
 
 
 int WSClient::Connect(const String& address, unsigned short port)
 int WSClient::Connect(const String& address, unsigned short port)
 {
 {
-    struct lws_context_creation_info info;
-    lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, OutputWSLog);
-
     address_ = address;
     address_ = address;
     port_ = port;
     port_ = port;
     serverProtocol_ = "ws-server";
     serverProtocol_ = "ws-server";
 
 
+    SetState(WCS_CONNECTING);
+    SubscribeToEvent(E_WORKITEMCOMPLETED, URHO3D_HANDLER(WSClient, HandleWorkItemFinished));
+
+    struct lws_context_creation_info info;
+    lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, OutputWSLog);
+
     memset(&info, 0, sizeof info);
     memset(&info, 0, sizeof info);
     info.port = CONTEXT_PORT_NO_LISTEN;
     info.port = CONTEXT_PORT_NO_LISTEN;
     info.protocols = protocols;
     info.protocols = protocols;
@@ -189,9 +240,82 @@ int WSClient::Connect(const String& address, unsigned short port)
         return 1;
         return 1;
     }
     }
 
 
+#ifndef __EMSCRIPTEN__
     lws_sul_schedule(context, 0, &sul, connect_cb, 50);
     lws_sul_schedule(context, 0, &sul, connect_cb, 50);
-    SubscribeToEvent(E_WORKITEMCOMPLETED, URHO3D_HANDLER(WSClient, HandleWorkItemFinished));
-    SetState(WCS_CONNECTING);
+#else
+    EM_ASM_({
+		var libwebsocket = {};
+
+		libwebsocket.socket = false;
+		libwebsocket.on_event = Module.cwrap('WSHelper', 'number', ['number', 'number', 'number', 'number', 'number']);
+		libwebsocket.connect = function( url, protocol, user_data ) {
+			try {
+				var socket = new WebSocket(url,protocol);
+				socket.binaryType = "arraybuffer";
+				socket.user_data = user_data;
+
+				socket.onopen = this.on_connect;
+				socket.onmessage = this.on_message;
+				socket.onclose = this.on_close;
+				socket.onerror = this.on_error;
+				socket.destroy = this.destroy;
+
+				this.socket = socket;
+				return socket;
+			} catch(e) {
+				Module.print("Socket creation failed:" + e);
+				return 0;
+			}
+		};
+		libwebsocket.on_connect = function() {
+			var stack = stackSave();
+			// filter protocol //
+			var ret = libwebsocket.on_event(this.id, 9, this.user_data, allocate(intArrayFromString(this.protocol), 'i8', ALLOC_STACK), this.protocol.length);
+			if( !ret ) {
+				// client established
+				ret = libwebsocket.on_event(this.id, 3, this.user_data, 0, 0);
+			}
+			if( ret ) {
+				this.close();
+			}
+			stackRestore(stack);
+		};
+		libwebsocket.on_message = function(event) {
+			var stack = stackSave();
+			var len = event.data.byteLength;
+			var ptr = allocate( len, 'i8', ALLOC_STACK);
+
+			var data = new Uint8Array( event.data );
+
+			for(var i =0, buf = ptr; i < len; ++i ) {
+				setValue(buf, data[i], 'i8');
+				buf++;
+			}
+
+			// client receive //
+			if(libwebsocket.on_event(this.id, 6, this.user_data, ptr, len)) {
+				this.close();
+			}
+			stackRestore(stack);
+		};
+		libwebsocket.on_close = function() {
+			// closed //
+			libwebsocket.on_event(this.protocol_id, ctx, this.id, 4, this.user_data, 0, 0);
+			this.destroy();
+		};
+		libwebsocket.on_error = function() {
+			// client connection error //
+			libwebsocket.on_event(this.protocol_id, ctx, this.id, 2, this.user_data, 0, 0);
+			this.destroy();
+		};
+		libwebsocket.destroy = function() {
+			libwebsocket.socket = false;
+			libwebsocket.on_event(this.protocol_id, ctx, this.id, 11, this.user_data, 0, 0);
+		};
+
+		Module.__libwebsocket = libwebsocket;
+	});
+#endif
     return 0;
     return 0;
 }
 }
 
 
@@ -206,6 +330,7 @@ void WSClient::Update(float timestep)
     if (nextState_ == WCS_CONNECTION_FAILED) {
     if (nextState_ == WCS_CONNECTION_FAILED) {
         GetSubsystem<Network>()->OnServerDisconnected(GetWSConnection(), true);
         GetSubsystem<Network>()->OnServerDisconnected(GetWSConnection(), true);
     }
     }
+
     if (context) {
     if (context) {
         if (!serviceWorkItem_ && currentState_ != WCS_DISCONNECTED) {
         if (!serviceWorkItem_ && currentState_ != WCS_DISCONNECTED) {
             WorkQueue *workQueue = GetSubsystem<WorkQueue>();
             WorkQueue *workQueue = GetSubsystem<WorkQueue>();
@@ -232,11 +357,13 @@ void WSClient::Update(float timestep)
 void WSClient::Disconnect()
 void WSClient::Disconnect()
 {
 {
     SetState(WCS_DISCONNECTED);
     SetState(WCS_DISCONNECTED);
+#ifndef __EMSCRIPTEN__
     if (context)
     if (context)
     {
     {
         lws_context_destroy(context);
         lws_context_destroy(context);
         context = nullptr;
         context = nullptr;
     }
     }
+#endif
 }
 }
 
 
 void WSClient::SetWSConnection(lws *ws)
 void WSClient::SetWSConnection(lws *ws)