Browse Source

additional updates to p2p, sample scene added

Arnis Lielturks 7 years ago
parent
commit
8fd86b8177

+ 202 - 28
Source/Samples/54_P2PMultiplayer/P2PMultiplayer.cpp

@@ -24,7 +24,10 @@
 #include <Urho3D/Audio/Sound.h>
 #include <Urho3D/Engine/Engine.h>
 #include <Urho3D/Graphics/Graphics.h>
+#include <Urho3D/Graphics/Model.h>
 #include <Urho3D/Graphics/Zone.h>
+#include <Urho3D/Graphics/Octree.h>
+#include <Urho3D/Graphics/StaticModel.h>
 #include <Urho3D/Input/Input.h>
 #include <Urho3D/IO/IOEvents.h>
 #include <Urho3D/IO/Log.h>
@@ -32,6 +35,10 @@
 #include <Urho3D/IO/VectorBuffer.h>
 #include <Urho3D/Network/Network.h>
 #include <Urho3D/Network/NetworkEvents.h>
+#include <Urho3D/Physics/CollisionShape.h>
+#include <Urho3D/Physics/PhysicsEvents.h>
+#include <Urho3D/Physics/PhysicsWorld.h>
+#include <Urho3D/Physics/RigidBody.h>
 #include <Urho3D/Resource/ResourceCache.h>
 #include <Urho3D/Scene/Scene.h>
 #include <Urho3D/UI/Button.h>
@@ -69,6 +76,10 @@ void P2PMultiplayer::Start()
     // Create the user interface
     CreateUI();
 
+    CreateScene();
+
+    SetupViewport();
+
     // Subscribe to UI and network events
     SubscribeToEvents();
 
@@ -89,10 +100,13 @@ void P2PMultiplayer::CreateUI()
     // Set style to the UI root so that elements will inherit it
     root->SetDefaultStyle(uiStyle);
 //
-//    int marginTop = 20;
+    int marginTop = 20;
 //    CreateLabel("1. Start server", IntVector2(20, marginTop-20));
-//    startServer_ = CreateButton("Start server", 160, IntVector2(20, marginTop));
-//    stopServer_ = CreateButton("Stop server", 160, IntVector2(20, marginTop));
+    startSession_ = CreateButton("Start session", 160, IntVector2(20, marginTop));
+    marginTop += 40;
+    guid_ = CreateLineEdit("1234", 200, IntVector2(20, marginTop));
+    marginTop += 40;
+    joinSession_ = CreateButton("Join session", 160, IntVector2(20, marginTop));
 //	stopServer_->SetVisible(false);
 //
 //    // Create client connection related fields
@@ -105,7 +119,7 @@ void P2PMultiplayer::CreateUI()
 //	serverList_ = CreateLabel("", IntVector2(20, marginTop));
 
     // No viewports or scene is defined. However, the default zone's fog color controls the fill color
-    GetSubsystem<Renderer>()->GetDefaultZone()->SetFogColor(Color(0.0f, 0.0f, 0.1f));
+    //GetSubsystem<Renderer>()->GetDefaultZone()->SetFogColor(Color(0.0f, 0.0f, 0.1f));
 }
 
 void P2PMultiplayer::SubscribeToEvents()
@@ -113,55 +127,85 @@ void P2PMultiplayer::SubscribeToEvents()
     SubscribeToEvent(E_SERVERCONNECTED, URHO3D_HANDLER(P2PMultiplayer, HandleServerConnected));
     SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(P2PMultiplayer, HandleUpdate));
 //
-//    SubscribeToEvent(startServer_, "Released", URHO3D_HANDLER(LANDiscovery, HandleStartServer));
-//    SubscribeToEvent(stopServer_, "Released", URHO3D_HANDLER(LANDiscovery, HandleStopServer));
+    SubscribeToEvent(startSession_, "Released", URHO3D_HANDLER(P2PMultiplayer, HandleStartP2PSession));
+    SubscribeToEvent(joinSession_, "Released", URHO3D_HANDLER(P2PMultiplayer, HandleJoinP2PSession));
+
+    SubscribeToEvent(E_CLIENTCONNECTED, URHO3D_HANDLER(P2PMultiplayer, HandleClientConnected));
+    SubscribeToEvent(E_CLIENTDISCONNECTED, URHO3D_HANDLER(P2PMultiplayer, HandleClientDisconnected));
 //    SubscribeToEvent(refreshServerList_, "Released", URHO3D_HANDLER(LANDiscovery, HandleDoNetworkDiscovery));
 }
 
 void P2PMultiplayer::HandleServerConnected(StringHash eventType, VariantMap& eventData)
 {
-    URHO3D_LOGINFO("Start P2P Session");
-    GetSubsystem<Network>()->StartP2PSession();
+    URHO3D_LOGINFO("HandleServerConnected");
+}
+
+void P2PMultiplayer::HandleStartP2PSession(StringHash eventType, VariantMap& eventData)
+{
+    URHO3D_LOGINFO("HandleStartP2PSession");
+    GetSubsystem<Network>()->StartP2PSession(scene_);
+}
 
+void P2PMultiplayer::HandleJoinP2PSession(StringHash eventType, VariantMap& eventData)
+{
+    URHO3D_LOGINFO("HandleJoinP2PSession " + guid_->GetText());
+    GetSubsystem<Network>()->JoinP2PSession(guid_->GetText(), scene_);
 }
 
 void P2PMultiplayer::HandleUpdate(StringHash eventType, VariantMap& eventData)
 {
-    if (timer_.GetMSec(false) > 2000) {
+    static int i = 0;
+    if (timer_.GetMSec(false) > 10000) {
+        i++;
         timer_.Reset();
-        URHO3D_LOGINFO("-----");
+        URHO3D_LOGINFO(" ");
+        URHO3D_LOGINFO(" " + String(i));
         URHO3D_LOGINFO("Participats: " + String(GetSubsystem<Network>()->GetP2PParticipantCount()));
         URHO3D_LOGINFO("P2PIsConnectedHost: " + String(GetSubsystem<Network>()->P2PIsConnectedHost()));
         URHO3D_LOGINFO("P2PIsHostSystem: " + String(GetSubsystem<Network>()->P2PIsHostSystem()));
         URHO3D_LOGINFO("P2PGetGUID: " + GetSubsystem<Network>()->P2PGetGUID());
+        URHO3D_LOGINFO("");
     }
 }
 
 void P2PMultiplayer::Init()
 {
 //    GetSubsystem<Network>()->SetNATServerInfo("frameskippers.com", 61111);
+    GetSubsystem<Network>()->SetNATServerInfo("frameskippers.com", 61111);
     GetSubsystem<Network>()->Connect("frameskippers.com", 61111, nullptr);
 }
 
 //
-//Button* LANDiscovery::CreateButton(const String& text, int width, IntVector2 position)
-//{
-//    auto* cache = GetSubsystem<ResourceCache>();
-//    auto* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
-//
-//    auto* button = GetSubsystem<UI>()->GetRoot()->CreateChild<Button>();
-//    button->SetStyleAuto();
-//    button->SetFixedWidth(width);
-//    button->SetFixedHeight(30);
-//    button->SetPosition(position);
-//
-//    auto* buttonText = button->CreateChild<Text>();
-//    buttonText->SetFont(font, 12);
-//    buttonText->SetAlignment(HA_CENTER, VA_CENTER);
-//    buttonText->SetText(text);
-//
-//    return button;
-//}
+Button* P2PMultiplayer::CreateButton(const String& text, int width, IntVector2 position)
+{
+    auto* cache = GetSubsystem<ResourceCache>();
+    auto* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
+
+    auto* button = GetSubsystem<UI>()->GetRoot()->CreateChild<Button>();
+    button->SetStyleAuto();
+    button->SetFixedWidth(width);
+    button->SetFixedHeight(30);
+    button->SetPosition(position);
+
+    auto* buttonText = button->CreateChild<Text>();
+    buttonText->SetFont(font, 12);
+    buttonText->SetAlignment(HA_CENTER, VA_CENTER);
+    buttonText->SetText(text);
+
+    return button;
+}
+
+LineEdit* P2PMultiplayer::CreateLineEdit(const String& placeholder, int width, IntVector2 pos)
+{
+    auto* textEdit = GetSubsystem<UI>()->GetRoot()->CreateChild<LineEdit>("");
+    textEdit->SetStyleAuto();
+    textEdit->SetFixedWidth(width);
+    textEdit->SetFixedHeight(30);
+    textEdit->SetText(placeholder);
+    textEdit->SetPosition(pos);
+    return textEdit;
+}
+
 //
 //Text* LANDiscovery::CreateLabel(const String& text, IntVector2 pos)
 //{
@@ -212,3 +256,133 @@ void P2PMultiplayer::Init()
 //	GetSubsystem<Network>()->DiscoverHosts(SERVER_PORT);
 //	serverList_->SetText("");
 //}
+
+void P2PMultiplayer::CreateScene()
+{
+    scene_ = new Scene(context_);
+
+    auto* cache = GetSubsystem<ResourceCache>();
+
+    // Create octree and physics world with default settings. Create them as local so that they are not needlessly replicated
+    // when a client connects
+    scene_->CreateComponent<Octree>(LOCAL);
+    scene_->CreateComponent<PhysicsWorld>(LOCAL);
+
+    // All static scene content and the camera are also created as local, so that they are unaffected by scene replication and are
+    // not removed from the client upon connection. Create a Zone component first for ambient lighting & fog control.
+    Node* zoneNode = scene_->CreateChild("Zone", LOCAL);
+    auto* zone = zoneNode->CreateComponent<Zone>();
+    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
+    zone->SetAmbientColor(Color(0.1f, 0.1f, 0.1f));
+    zone->SetFogStart(100.0f);
+    zone->SetFogEnd(300.0f);
+
+    // Create a directional light without shadows
+    Node* lightNode = scene_->CreateChild("DirectionalLight", LOCAL);
+    lightNode->SetDirection(Vector3(0.5f, -1.0f, 0.5f));
+    auto* light = lightNode->CreateComponent<Light>();
+    light->SetLightType(LIGHT_DIRECTIONAL);
+    light->SetColor(Color(0.2f, 0.2f, 0.2f));
+    light->SetSpecularIntensity(1.0f);
+
+    // Create a "floor" consisting of several tiles. Make the tiles physical but leave small cracks between them
+    for (int y = -20; y <= 20; ++y)
+    {
+        for (int x = -20; x <= 20; ++x)
+        {
+            Node* floorNode = scene_->CreateChild("FloorTile", LOCAL);
+            floorNode->SetPosition(Vector3(x * 20.2f, -0.5f, y * 20.2f));
+            floorNode->SetScale(Vector3(20.0f, 1.0f, 20.0f));
+            auto* floorObject = floorNode->CreateComponent<StaticModel>();
+            floorObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
+            floorObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
+
+            auto* body = floorNode->CreateComponent<RigidBody>();
+            body->SetFriction(1.0f);
+            auto* shape = floorNode->CreateComponent<CollisionShape>();
+            shape->SetBox(Vector3::ONE);
+        }
+    }
+
+    // Create the camera. Limit far clip distance to match the fog
+    // The camera needs to be created into a local node so that each client can retain its own camera, that is unaffected by
+    // network messages. Furthermore, because the client removes all replicated scene nodes when connecting to a server scene,
+    // the screen would become blank if the camera node was replicated (as only the locally created camera is assigned to a
+    // viewport in SetupViewports() below)
+    cameraNode_ = scene_->CreateChild("Camera", LOCAL);
+    auto* camera = cameraNode_->CreateComponent<Camera>();
+    camera->SetFarClip(300.0f);
+
+    // Set an initial position for the camera scene node above the plane
+    cameraNode_->SetPosition(Vector3(-10.0f, 10.0f, 10.0f));
+    cameraNode_->LookAt(Vector3(0, 0, 0));
+}
+
+void P2PMultiplayer::SetupViewport()
+{
+    auto* renderer = GetSubsystem<Renderer>();
+
+    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen
+    SharedPtr<Viewport> viewport(new Viewport(context_, scene_, cameraNode_->GetComponent<Camera>()));
+    renderer->SetViewport(0, viewport);
+}
+
+
+
+void P2PMultiplayer::HandleClientConnected(StringHash eventType, VariantMap& eventData)
+{
+    using namespace ClientConnected;
+
+    // When a client connects, assign to scene to begin scene replication
+    auto* newConnection = static_cast<Connection*>(eventData[P_CONNECTION].GetPtr());
+    newConnection->SetScene(scene_);
+
+    // Then create a controllable object for that client
+//    Node* newObject = CreateControllableObject();
+//    serverObjects_[newConnection] = newObject;
+
+    // Finally send the object's node ID using a remote event
+//    VariantMap remoteEventData;
+//    remoteEventData[P_ID] = newObject->GetID();
+//    newConnection->SendRemoteEvent(E_CLIENTOBJECTID, true, remoteEventData);
+    auto* cache = GetSubsystem<ResourceCache>();
+
+    // Create the scene node & visual representation. This will be a replicated object
+    Node* ballNode = scene_->CreateChild(newConnection->GetAddress());
+    ballNode->SetPosition(Vector3(0, 10, 0));
+    ballNode->SetScale(0.5f);
+    auto* ballObject = ballNode->CreateComponent<StaticModel>();
+    ballObject->SetModel(cache->GetResource<Model>("Models/Sphere.mdl"));
+    ballObject->SetMaterial(cache->GetResource<Material>("Materials/StoneSmall.xml"));
+
+    // Create the physics components
+    auto* body = ballNode->CreateComponent<RigidBody>();
+    body->SetMass(1.0f);
+    body->SetFriction(1.0f);
+    // In addition to friction, use motion damping so that the ball can not accelerate limitlessly
+    body->SetLinearDamping(0.5f);
+    body->SetAngularDamping(0.5f);
+    auto* shape = ballNode->CreateComponent<CollisionShape>();
+    shape->SetSphere(1.0f);
+
+    // Create a random colored point light at the ball so that can see better where is going
+    auto* light = ballNode->CreateComponent<Light>();
+    light->SetRange(3.0f);
+    light->SetColor(
+            Color(0.5f + ((unsigned)Rand() & 1u) * 0.5f, 0.5f + ((unsigned)Rand() & 1u) * 0.5f, 0.5f + ((unsigned)Rand() & 1u) * 0.5f));
+}
+
+void P2PMultiplayer::HandleClientDisconnected(StringHash eventType, VariantMap& eventData)
+{
+    using namespace ClientConnected;
+//
+//    // When a client disconnects, remove the controlled object
+    auto* connection = static_cast<Connection*>(eventData[P_CONNECTION].GetPtr());
+    Node* node = scene_->GetChild(connection->GetAddress());
+    node->Remove();
+//    Node* object = serverObjects_[connection];
+//    if (object)
+//        object->Remove();
+//
+//    serverObjects_.Erase(connection);
+}

+ 20 - 5
Source/Samples/54_P2PMultiplayer/P2PMultiplayer.h

@@ -73,8 +73,19 @@ private:
     //
     void Init();
 
+    void CreateScene();
+
+    /// Set up viewport.
+    void SetupViewport();
+
+    /// Handle a client connecting to the server.
+    void HandleClientConnected(StringHash eventType, VariantMap& eventData);
+    /// Handle a client disconnecting from the server.
+    void HandleClientDisconnected(StringHash eventType, VariantMap& eventData);
+
     /// Create a button to the button container.
-//    Button* CreateButton(const String& text, int width, IntVector2 position);
+    Button* CreateButton(const String& text, int width, IntVector2 position);
+    LineEdit* CreateLineEdit(const String& placeholder, int width, IntVector2 pos);
 //    /// Create label
 //    Text* CreateLabel(const String& text, IntVector2 pos);
 //
@@ -83,6 +94,9 @@ private:
 //    /// Start server
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
 
+    void HandleStartP2PSession(StringHash eventType, VariantMap& eventData);
+    void HandleJoinP2PSession(StringHash eventType, VariantMap& eventData);
+
     Timer timer_;
 //    /// Stop server
 //	void HandleStopServer(StringHash eventType, VariantMap& eventData);
@@ -90,10 +104,11 @@ private:
 //	void HandleDoNetworkDiscovery(StringHash eventType, VariantMap& eventData);
 //    /// Start server
 //    SharedPtr<Button> startServer_;
-//    /// Stop server
-//    SharedPtr<Button> stopServer_;
-//    /// Redo LAN discovery
-//    SharedPtr<Button> refreshServerList_;
+    /// Start P2P Session
+    SharedPtr<Button> startSession_;
+    /// Join P2P Session
+    SharedPtr<Button> joinSession_;
+    SharedPtr<LineEdit> guid_;
 //    /// Found server list
 //	SharedPtr<Text> serverList_;
 };

+ 171 - 18
Source/Urho3D/Network/Network.cpp

@@ -44,6 +44,7 @@
 #include <SLikeNet/statistics.h>
 #include <SLikeNet/FullyConnectedMesh2.h>
 #include <SLikeNet/DS_List.h>
+#include <SLikeNet/BitStream.h>
 
 #ifdef SendMessage
 #undef SendMessage
@@ -214,7 +215,7 @@ Network::Network(Context* context) :
 #if NETWORK_P2P
     fullyConnectedMesh2_ = SLNet::FullyConnectedMesh2::GetInstance();
     rakPeerClient_->AttachPlugin(fullyConnectedMesh2_);
-    fullyConnectedMesh2_->SetAutoparticipateConnections(true);
+    fullyConnectedMesh2_->SetAutoparticipateConnections(false);
 #endif
 
     rakPeer_->SetTimeoutTime(SERVER_TIMEOUT_TIME, SLNet::UNASSIGNED_SYSTEM_ADDRESS);
@@ -377,7 +378,8 @@ void Network::DiscoverHosts(unsigned port)
     {
         SLNet::SocketDescriptor socket;
         // Startup local connection with max 1 incoming connection(first param) and 1 socket description (third param)
-        rakPeerClient_->Startup(1, &socket, 1);
+        rakPeerClient_->Startup(32, &socket, 1);
+        rakPeerClient_->SetMaximumIncomingConnections(32);
     }
     rakPeerClient_->Ping("255.255.255.255", port, false);
 }
@@ -397,7 +399,8 @@ bool Network::Connect(const String& address, unsigned short port, Scene* scene,
         URHO3D_LOGINFO("Initializing client connection...");
         SLNet::SocketDescriptor socket;
         // Startup local connection with max 2 incoming connections(first param) and 1 socket description (third param)
-        rakPeerClient_->Startup(2, &socket, 1);
+        rakPeerClient_->Startup(32, &socket, 1);
+        rakPeerClient_->SetMaximumIncomingConnections(32);
     } else {
         OnServerDisconnected();
     }
@@ -519,7 +522,8 @@ void Network::AttemptNATPunchtrough(const String& guid, Scene* scene, const Vari
     else {
         SLNet::SocketDescriptor socket;
         // Startup local connection with max 2 incoming connections(first param) and 1 socket description (third param)
-        rakPeerClient_->Startup(2, &socket, 1);
+        rakPeerClient_->Startup(32, &socket, 1);
+        rakPeerClient_->SetMaximumIncomingConnections(32);
     }
 
     rakPeerClient_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
@@ -716,6 +720,11 @@ bool Network::CheckRemoteEvent(StringHash eventType) const
 void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
 {
     unsigned char packetID = packet->data[0];
+
+    if (packetID < sizeof(RAKNET_MESSAGEID_STRINGS)) {
+        URHO3D_LOGERROR("-------------------------------- HandleIncomingPacket: " + String(RAKNET_MESSAGEID_STRINGS[packetID]));
+    }
+
     bool packetHandled = false;
 
     // Deal with timestamped backents
@@ -729,11 +738,13 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
 
     if (packetID == ID_NEW_INCOMING_CONNECTION)
     {
+        URHO3D_LOGINFOF("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.", packet->systemAddress.ToString(true), packet->guid.ToString());
         if (isServer)
         {
             NewConnectionEstablished(packet->systemAddress);
-            packetHandled = true;
         }
+        fullyConnectedMesh2_->ResetHostCalculation();
+        packetHandled = true;
     }
     else if (packetID == ID_ALREADY_CONNECTED)
     {
@@ -751,15 +762,43 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
         if(natPunchServerAddress_ && packet->systemAddress == *natPunchServerAddress_) {
             URHO3D_LOGINFO("Succesfully connected to NAT punchtrough server! ");
             SendEvent(E_NATMASTERCONNECTIONSUCCEEDED);
-            if (!isServer)
+            if (!isServer && remoteGUID_)
             {
                 natPunchthroughClient_->OpenNAT(*remoteGUID_, *natPunchServerAddress_);
             }
         } else {
-            if (!isServer)
-            {
-                OnServerConnected(packet->systemAddress);
-            }
+//            if (!isServer)
+//            {
+//
+//            }
+            URHO3D_LOGINFOF("ID_CONNECTION_REQUEST_ACCEPTED from %s,guid=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
+            fullyConnectedMesh2_->ResetHostCalculation();
+//                SLNet::ConnectionAttemptResult car = rakPeerClient_->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(), 0, 0);
+//                OnServerConnected(packet->systemAddress);
+            SLNet::BitStream bsOut;
+            bsOut.Write((unsigned char)MSG_P2P_REQUEST);
+            rakPeerClient_->Send(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false);
+            URHO3D_LOGINFO("ID_CONNECTION_REQUEST_ACCEPTED >>>>>>>>>>>>>>>>>>>>>");
+//                DataStructures::List <SLNet::SystemAddress> addresses;
+//                DataStructures::List <SLNet::RakNetGUID> guids;
+//                DataStructures::List < SLNet::BitStream * > userData;
+//                fullyConnectedMesh2_->GetVerifiedJoinRequiredProcessingList(packet->guid, addresses, guids, userData);
+//                URHO3D_LOGINFO("Verified connections " + String(guids.Size()));
+//                for (unsigned int i = 0; i < guids.Size(); i++)
+//                {
+//                    URHO3D_LOGINFO("VERIFIED GUID: " + String(guids[i].ToString()));
+//                    natPunchthroughClient_->OpenNAT(guids[i], *natPunchServerAddress_);
+//                }
+//
+//                URHO3D_LOGINFO("All connections " + String(guids.Size()));
+//                DataStructures::List<SLNet::RakNetGUID> participantList;
+//                fullyConnectedMesh2_->GetParticipantList(participantList);
+//                for (unsigned int i = 0; i < participantList.Size(); i++) {
+//                    URHO3D_LOGINFO("CONNECTION GUID: " + String(participantList[i].ToString()));
+//                    if (participantList[i] != rakPeerClient_->GetMyGUID()) {
+//                        natPunchthroughClient_->OpenNAT(participantList[i], *natPunchServerAddress_);
+//                    }
+//                }
         }
         packetHandled = true;
     }
@@ -820,6 +859,8 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
             SendEvent(E_NETWORKNATPUNCHTROUGHSUCCEEDED, eventMap);
             URHO3D_LOGINFO("Connecting to server behind NAT: " + String(remotePeer.ToString()));
             Connect(String(remotePeer.ToString(false)), remotePeer.GetPort(), scene_, identity_);
+        } else {
+            SLNet::ConnectionAttemptResult car = rakPeerClient_->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(), 0, 0);
         }
         packetHandled = true;
     }
@@ -880,29 +921,108 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
 #if NETWORK_P2P
     else if (packetID == ID_FCM2_NEW_HOST)
     {
-        URHO3D_LOGINFO("ID_FCM2_NEW_HOST");
+        URHO3D_LOGINFO("");
+        URHO3D_LOGINFOF("ID_FCM2_NEW_HOST: System %s is host, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
+        SLNet::BitStream bs(packet->data,packet->length,false);
+        bs.IgnoreBytes(1);
+        SLNet::RakNetGUID oldHost;
+        bs.Read(oldHost);
+
+        if (packet->guid == rakPeerClient_->GetMyGUID())
+        {
+            if (oldHost != SLNet::UNASSIGNED_RAKNET_GUID)
+            {
+                URHO3D_LOGINFOF("ID_FCM2_NEW_HOST: Taking over as host from the old host [%s].", oldHost.ToString());
+            }
+            else
+            {
+                // Room not hosted if we become host the first time since this was done in CreateRoom() already
+                URHO3D_LOGINFO("ID_FCM2_NEW_HOST: We have become host for the first time");
+            }
+        }
+        else
+        {
+            if (oldHost != SLNet::UNASSIGNED_RAKNET_GUID) {
+                URHO3D_LOGINFOF("ID_FCM2_NEW_HOST: A new system %s has become host, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
+            }
+            else {
+                URHO3D_LOGINFOF("ID_FCM2_NEW_HOST: System %s is host, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
+            }
+        }
+
+        URHO3D_LOGINFO("");
+
+
+        packetHandled = true;
     }
-    else if (packetID == ID_FCM2_VERIFIED_JOIN_START)
-    {
-        URHO3D_LOGINFO("ID_FCM2_VERIFIED_JOIN_START");
+    else if (packetID == ID_FCM2_VERIFIED_JOIN_START) {
+
+        URHO3D_LOGINFO("------------------ ID_FCM2_VERIFIED_JOIN_START");
+        DataStructures::List <SLNet::SystemAddress> addresses;
+        DataStructures::List <SLNet::RakNetGUID> guids;
+        DataStructures::List < SLNet::BitStream * > userData;
+        fullyConnectedMesh2_->GetVerifiedJoinRequiredProcessingList(packet->guid, addresses, guids, userData);
+        for (unsigned int i = 0; i < guids.Size(); i++)
+        {
+            natPunchthroughClient_->OpenNAT(guids[i], *natPunchServerAddress_);
+        }
+
     }
     else if (packetID == ID_FCM2_VERIFIED_JOIN_CAPABLE)
     {
         URHO3D_LOGINFO("ID_FCM2_VERIFIED_JOIN_CAPABLE");
+        URHO3D_LOGINFO("Client is capable of joining FullyConnectedMesh2.");
+        fullyConnectedMesh2_->RespondOnVerifiedJoinCapable(packet, true, 0);
+        packetHandled = true;
     }
     else if (packetID == ID_FCM2_VERIFIED_JOIN_ACCEPTED)
     {
-        URHO3D_LOGINFO("ID_FCM2_VERIFIED_JOIN_ACCEPTED");
+        DataStructures::List<SLNet::RakNetGUID> systemsAccepted;
+        bool thisSystemAccepted;
+        fullyConnectedMesh2_->GetVerifiedJoinAcceptedAdditionalData(packet, &thisSystemAccepted, systemsAccepted, 0);
+        if (thisSystemAccepted) {
+            URHO3D_LOGINFO("Game join request accepted");
+        }
+        URHO3D_LOGINFO("+++++++++++++++++++++++++++++ ID_FCM2_VERIFIED_JOIN_ACCEPTED");
+        packetHandled = true;
     }
     else if (packetID == ID_FCM2_VERIFIED_JOIN_REJECTED)
     {
         URHO3D_LOGINFO("ID_FCM2_VERIFIED_JOIN_REJECTED");
     }
+    else if (packetID == ID_FCM2_REQUEST_FCMGUID)
+    {
+        URHO3D_LOGINFO("ID_FCM2_REQUEST_FCMGUID");
+    }
+    else if (packetID == ID_FCM2_RESPOND_CONNECTION_COUNT)
+    {
+        URHO3D_LOGINFO("ID_FCM2_RESPOND_CONNECTION_COUNT");
+    }
+    else if (packetID == ID_FCM2_INFORM_FCMGUID)
+    {
+        URHO3D_LOGINFO("ID_FCM2_INFORM_FCMGUID");
+    }
+    else if (packetID == ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT)
+    {
+        URHO3D_LOGINFO("ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT");
+    }
+    else if (packetID == ID_FCM2_UPDATE_USER_CONTEXT)
+    {
+        URHO3D_LOGINFO("ID_FCM2_UPDATE_USER_CONTEXT");
+    }
+
 #endif
     // Urho3D messages
     if (packetID >= ID_USER_PACKET_ENUM)
     {
-        if (isServer)
+        URHO3D_LOGINFOF("ID_USER_PACKET_ENUM %i", packetID);
+        if (packetID == MSG_P2P_REQUEST) {
+            URHO3D_LOGINFO("...........MSG_P2P_REQUEST.............");
+            URHO3D_LOGINFO("Got request from client to join session. Executing StartVerifiedJoin()");
+            fullyConnectedMesh2_->StartVerifiedJoin(packet->guid);
+        } else if (packetID == MSG_P2P_DENY) {
+            URHO3D_LOGERROR("MSG_P2P_DENY");
+        } else if (isServer)
         {
             HandleMessage(packet->systemAddress, 0, packetID, (const char*)(packet->data + dataStart), packet->length - dataStart);
         }
@@ -942,9 +1062,11 @@ void Network::Update(float timeStep)
     // Process all incoming messages for the client
     if (rakPeerClient_->IsActive())
     {
+        bool isHost = P2PIsHostSystem();
         while (SLNet::Packet* packet = rakPeerClient_->Receive())
         {
-            HandleIncomingPacket(packet, false);
+            HandleIncomingPacket(packet, isHost);
+//            HandleIncomingPacket(packet, false);
             rakPeerClient_->DeallocatePacket(packet);
         }
     }
@@ -1064,12 +1186,41 @@ void Network::ConfigureNetworkSimulator()
         i->second_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
 }
 
-bool Network::StartP2PSession()
+bool Network::StartP2PSession(Scene* scene, const VariantMap& identity)
 {
+    if (!serverConnection_) {
+        serverConnection_ = new Connection(context_, false, rakPeerClient_->GetMyBoundAddress(), rakPeerClient_);
+        serverConnection_->SetScene(scene);
+        serverConnection_->SetIdentity(identity);
+        serverConnection_->SetConnectPending(true);
+        serverConnection_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
+    }
+    rakPeerClient_->AttachPlugin(natPunchthroughClient_);
+    fullyConnectedMesh2_->Clear();
     fullyConnectedMesh2_->ResetHostCalculation();
     return true;
 }
 
+void Network::JoinP2PSession(String guid, Scene* scene, const VariantMap& identity)
+{
+    if (!serverConnection_) {
+        serverConnection_ = new Connection(context_, false, rakPeerClient_->GetMyBoundAddress(), rakPeerClient_);
+        serverConnection_->SetScene(scene);
+        serverConnection_->SetIdentity(identity);
+        serverConnection_->SetConnectPending(true);
+        serverConnection_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
+    }
+
+    rakPeerClient_->AttachPlugin(natPunchthroughClient_);
+    fullyConnectedMesh2_->ResetHostCalculation();
+    fullyConnectedMesh2_->Clear();
+    SLNet::RakNetGUID remoteGUID;
+
+    remoteGUID.FromString(guid.CString());
+    URHO3D_LOGINFO("Attempting to Join P2P Session : " + guid);
+    natPunchthroughClient_->OpenNAT(remoteGUID, *natPunchServerAddress_);
+}
+
 int Network::GetP2PParticipantCount()
 {
     // First time calculated host. Add existing connections to ReplicaManager3
@@ -1093,6 +1244,8 @@ bool Network::P2PIsHostSystem()
 
 String Network::P2PGetGUID()
 {
+    URHO3D_LOGINFO("HOST GUID: " + String(fullyConnectedMesh2_->GetHostSystem().ToString()));
+//    URHO3D_LOGINFO("MY GUID: " + String(rakPeerClient_->GetGuidFromSystemAddress(SLNet::UNASSIGNED_SYSTEM_ADDRESS).ToString()));
     return String(rakPeerClient_->GetGuidFromSystemAddress(SLNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
 }
 void RegisterNetworkLibrary(Context* context)

+ 2 - 1
Source/Urho3D/Network/Network.h

@@ -70,7 +70,8 @@ public:
     bool StartServer(unsigned short port);
 #if NETWORK_P2P
     /// Start P2P session
-    bool StartP2PSession();
+    bool StartP2PSession(Scene* scene, const VariantMap& identity = Variant::emptyVariantMap);
+    void JoinP2PSession(String guid, Scene* scene, const VariantMap& identity = Variant::emptyVariantMap);
     int GetP2PParticipantCount();
     bool P2PIsConnectedHost();
     bool P2PIsHostSystem();

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

@@ -63,6 +63,8 @@ static const int MSG_REMOTEEVENT = 0x96;
 static const int MSG_REMOTENODEEVENT = 0x97;
 /// Server->client: info about package.
 static const int MSG_PACKAGEINFO = 0x98;
+static const int MSG_P2P_REQUEST = 0x99;
+static const int MSG_P2P_DENY = 0x9A;
 
 /// Fixed content ID for client controls update.
 static const unsigned CONTROLS_CONTENT_ID = 1;