Przeglądaj źródła

sample multiplayer movement added

Arnis Lielturks 7 lat temu
rodzic
commit
ba659d50a1

+ 176 - 73
Source/Samples/54_P2PMultiplayer/P2PMultiplayer.cpp

@@ -46,6 +46,7 @@
 #include <Urho3D/UI/Font.h>
 #include <Urho3D/UI/LineEdit.h>
 #include <Urho3D/UI/Text.h>
+#include <Urho3D/UI/Text3D.h>
 #include <Urho3D/UI/UI.h>
 #include <Urho3D/UI/UIEvents.h>
 #include <Urho3D/Core/CoreEvents.h>
@@ -66,6 +67,13 @@ P2PMultiplayer::P2PMultiplayer(Context* context) :
 {
 }
 
+// Control bits we define
+static const unsigned CTRL_FORWARD = 1;
+static const unsigned CTRL_BACK = 2;
+static const unsigned CTRL_LEFT = 4;
+static const unsigned CTRL_RIGHT = 8;
+
+
 void P2PMultiplayer::Start()
 {
     // Execute base class startup
@@ -114,14 +122,7 @@ void P2PMultiplayer::CreateUI()
     roleTitle_->SetTextAlignment(HA_CENTER);
     roleTitle_->SetColor(Color::GREEN);
     roleTitle_->SetFontSize(40);
-    
-//	stopServer_->SetVisible(false);
-//
-//    // Create client connection related fields
-//    marginTop += 80;
-//    CreateLabel("2. Discover LAN servers", IntVector2(20, marginTop-20));
-//    refreshServerList_ = CreateButton("Search...", 160, IntVector2(20, marginTop));
-//
+
 	marginTop += 80;
     clientCount_ = CreateLabel("Connections: 0", IntVector2(20, marginTop));
     marginTop += 40;
@@ -139,14 +140,14 @@ void P2PMultiplayer::CreateUI()
     marginTop += 40;
     disconnect_ = CreateButton("Disconnect", 160, 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));
+//     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));
 }
 
 void P2PMultiplayer::SubscribeToEvents()
 {
-    SubscribeToEvent(E_SERVERCONNECTED, URHO3D_HANDLER(P2PMultiplayer, HandleServerConnected));
     SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(P2PMultiplayer, HandleUpdate));
+    SubscribeToEvent(E_PHYSICSPRESTEP, URHO3D_HANDLER(P2PMultiplayer, HandlePhysicsPrestep));
 //
     SubscribeToEvent(startSession_, "Released", URHO3D_HANDLER(P2PMultiplayer, HandleStartP2PSession));
     SubscribeToEvent(joinSession_, "Released", URHO3D_HANDLER(P2PMultiplayer, HandleJoinP2PSession));
@@ -163,11 +164,6 @@ void P2PMultiplayer::SubscribeToEvents()
 //    SubscribeToEvent(refreshServerList_, "Released", URHO3D_HANDLER(LANDiscovery, HandleDoNetworkDiscovery));
 }
 
-void P2PMultiplayer::HandleServerConnected(StringHash eventType, VariantMap& eventData)
-{
-    URHO3D_LOGINFO("HandleServerConnected");
-}
-
 void P2PMultiplayer::HandleStartP2PSession(StringHash eventType, VariantMap& eventData)
 {
     URHO3D_LOGINFO("HandleStartP2PSession");
@@ -181,6 +177,7 @@ void P2PMultiplayer::HandleJoinP2PSession(StringHash eventType, VariantMap& even
 {
     URHO3D_LOGINFO("HandleJoinP2PSession " + guid_->GetText());
     GetSubsystem<Network>()->P2PJoinSession(guid_->GetText(), scene_);
+    GetSubsystem<Network>()->SetSimulatedLatency(Random(10.0f));
 }
 
 void P2PMultiplayer::HandleSessionStarted(StringHash eventType, VariantMap& eventData)
@@ -204,9 +201,6 @@ void P2PMultiplayer::HandleReady(StringHash eventType, VariantMap& eventData)
 
 void P2PMultiplayer::HandleUpdate(StringHash eventType, VariantMap& eventData)
 {
-    if (cameraNode_) {
-        cameraNode_->LookAt(ball_->GetPosition());
-    }
     using namespace Update;
     static int i = 0;
     auto input = GetSubsystem<Input>();
@@ -215,21 +209,45 @@ void P2PMultiplayer::HandleUpdate(StringHash eventType, VariantMap& eventData)
     gametime += timestep * 10;
 
     if (GetSubsystem<Network>()->P2PIsHostSystem() && _allReady) {
-        //if (body_) {
-        //    body_->ApplyImpulse(Vector3(0, 10, 0));
-        //}
-        ball_->SetWorldPosition(Vector3(0, Sin(gametime) * 5 + 6, 0));
-        body_->SetLinearVelocity(Vector3(0, 0, 0));
+    }
+
+    // Mouse sensitivity as degrees per pixel
+    const float MOUSE_SENSITIVITY = 0.1f;
+
+    // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch and only move the camera
+    // when the cursor is hidden
+    IntVector2 mouseMove = input->GetMouseMove();
+    yaw_ += MOUSE_SENSITIVITY * mouseMove.x_;
+    pitch_ += MOUSE_SENSITIVITY * mouseMove.y_;
+    pitch_ = Clamp(pitch_, 1.0f, 90.0f);
+
+    // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
+    cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f));
+
+    if (GetSubsystem<Network>()->GetServerConnection()) {
+        Controls controls;
+        // Copy mouse yaw
+        controls.yaw_ = yaw_;
+
+        controls.Set(CTRL_FORWARD, input->GetKeyDown(KEY_W));
+        controls.Set(CTRL_BACK, input->GetKeyDown(KEY_S));
+        controls.Set(CTRL_LEFT, input->GetKeyDown(KEY_A));
+        controls.Set(CTRL_RIGHT, input->GetKeyDown(KEY_D));
+        GetSubsystem<Network>()->GetServerConnection()->SetControls(controls);
     }
 
     if (timer_.GetMSec(false) > 1000) {
-        PODVector<Node*> nodes;
-        scene_->GetNodesWithTag(nodes, "Player");
-        URHO3D_LOGINFO("-------- NODES " + String(nodes.Size()));
-        for (auto it = nodes.Begin(); it != nodes.End(); ++it) {
-            URHO3D_LOGINFO("Node " + String((*it)->GetID()) + " => " + (*it)->GetVar("GUID").GetString());
+        if (GetSubsystem<Network>()->GetClientConnections().Size() != playerNodes_.Size() - 1) {
+            UpdateClientObjects();
         }
-        URHO3D_LOGINFO("----------------");
+
+//        PODVector<Node*> nodes;
+//        scene_->GetNodesWithTag(nodes, "Player");
+//        URHO3D_LOGINFO("-------- NODES " + String(nodes.Size()));
+//        for (auto it = nodes.Begin(); it != nodes.End(); ++it) {
+//            URHO3D_LOGINFO("Node " + String((*it)->GetID()) + " => " + (*it)->GetVar("GUID").GetString());
+//        }
+//        URHO3D_LOGINFO("----------------");
 //        GetSubsystem<Network>()->DisplayPingTimes();
         i++;
         timer_.Reset();
@@ -294,14 +312,96 @@ void P2PMultiplayer::HandleUpdate(StringHash eventType, VariantMap& eventData)
             static_cast<Text*>(readyButton_->GetChild(0))->SetColor(Color::GREEN);
         }
     }
+
+    auto serverConnection = GetSubsystem<Network>()->GetServerConnection();
+    if (serverConnection) {
+        if (playerNodes_[serverConnection]) {
+//            GetSubsystem<Input>()->SetMouseVisible(false);
+//            cameraNode_->LookAt(playerNodes_[serverConnection]->GetWorldPosition());
+            const float CAMERA_DISTANCE = 5.0f;
+
+            // Move camera some distance away from the ball
+            cameraNode_->SetPosition(playerNodes_[serverConnection]->GetPosition() + cameraNode_->GetRotation() * Vector3::BACK * CAMERA_DISTANCE);
+        } else {
+            UpdateClientObjects();
+//            GetSubsystem<Input>()->SetMouseVisible(true);
+        }
+    }
+}
+
+void P2PMultiplayer::HandlePhysicsPrestep(StringHash eventType, VariantMap& eventData)
+{
+    if (!GetSubsystem<Network>()->P2PIsHostSystem()) {
+        return;
+    }
+
+    // Apply client controls to the nodes only if we're the host
+    using namespace PhysicsPreStep;
+    float timestep = eventData[P_TIMESTEP].GetFloat();
+    auto clients = GetSubsystem<Network>()->GetClientConnections();
+    for (auto it = clients.Begin(); it != clients.End(); ++it) {
+        // Get the last controls sent by the client
+        const Controls& controls = (*it)->GetControls();
+        // Torque is relative to the forward vector
+        Quaternion rotation(0.0f, controls.yaw_, 0.0f);
+
+        const float MOVE_TORQUE = 3.0f;
+
+        if (!playerNodes_[(*it)]) {
+            continue;
+        }
+        RigidBody* body = playerNodes_[(*it)]->GetComponent<RigidBody>();
+        // Movement torque is applied before each simulation step, which happen at 60 FPS. This makes the simulation
+        // independent from rendering framerate. We could also apply forces (which would enable in-air control),
+        // but want to emphasize that it's a ball which should only control its motion by rolling along the ground
+        if (controls.buttons_ & CTRL_FORWARD) {
+            body->ApplyTorque(rotation * Vector3::RIGHT * MOVE_TORQUE);
+        }
+        if (controls.buttons_ & CTRL_BACK) {
+            body->ApplyTorque(rotation * Vector3::LEFT * MOVE_TORQUE);
+        }
+        if (controls.buttons_ & CTRL_LEFT) {
+            body->ApplyTorque(rotation * Vector3::FORWARD * MOVE_TORQUE);
+        }
+        if (controls.buttons_ & CTRL_RIGHT) {
+            body->ApplyTorque(rotation * Vector3::BACK * MOVE_TORQUE);
+        }
+    }
+
+    auto serverConnection = GetSubsystem<Network>()->GetServerConnection();
+    if (serverConnection) {
+        const Controls& controls = serverConnection->GetControls();
+        // Torque is relative to the forward vector
+        Quaternion rotation(0.0f, controls.yaw_, 0.0f);
+
+        const float MOVE_TORQUE = 3.0f;
+        if (!playerNodes_[serverConnection]) {
+            return;
+        }
+
+        RigidBody* body = playerNodes_[serverConnection]->GetComponent<RigidBody>();
+        // Movement torque is applied before each simulation step, which happen at 60 FPS. This makes the simulation
+        // independent from rendering framerate. We could also apply forces (which would enable in-air control),
+        // but want to emphasize that it's a ball which should only control its motion by rolling along the ground
+        if (controls.buttons_ & CTRL_FORWARD) {
+            body->ApplyTorque(rotation * Vector3::RIGHT * MOVE_TORQUE);
+        }
+        if (controls.buttons_ & CTRL_BACK) {
+            body->ApplyTorque(rotation * Vector3::LEFT * MOVE_TORQUE);
+        }
+        if (controls.buttons_ & CTRL_LEFT) {
+            body->ApplyTorque(rotation * Vector3::FORWARD * MOVE_TORQUE);
+        }
+        if (controls.buttons_ & CTRL_RIGHT) {
+            body->ApplyTorque(rotation * Vector3::BACK * MOVE_TORQUE);
+        }
+    }
 }
 
 void P2PMultiplayer::Init()
 {
     GetSubsystem<Network>()->SetMode(NetworkMode::PEER_TO_PEER);
-//    GetSubsystem<Network>()->SetNATServerInfo("frameskippers.com", 61111);
     GetSubsystem<Network>()->SetNATServerInfo("frameskippers.com", 61111);
-//    GetSubsystem<Network>()->BanAddress("192.168.68.*");
     GetSubsystem<Network>()->SetUpdateFps(30);
 
     httpRequest_ = GetSubsystem<Network>()->MakeHttpRequest("http://frameskippers.com:82/guid.txt");
@@ -352,43 +452,6 @@ Text* P2PMultiplayer::CreateLabel(const String& text, IntVector2 pos)
     label->SetTextEffect(TextEffect::TE_STROKE);
 	return label;
 }
-//
-//void LANDiscovery::HandleNetworkHostDiscovered(StringHash eventType, VariantMap& eventData)
-//{
-//	using namespace NetworkHostDiscovered;
-//	URHO3D_LOGINFO("Server discovered!");
-//	String text = serverList_->GetText();
-//	VariantMap data = eventData[P_BEACON].GetVariantMap();
-//	text += "\n" + data["Name"].GetString() + "(" + String(data["Players"].GetInt()) + ")" + eventData[P_ADDRESS].GetString() + ":" + String(eventData[P_PORT].GetInt());
-//	serverList_->SetText(text);
-//}
-//
-//void LANDiscovery::HandleStartServer(StringHash eventType, VariantMap& eventData)
-//{
-//	if (GetSubsystem<Network>()->StartServer(SERVER_PORT)) {
-//		VariantMap data;
-//		data["Name"] = "Test server";
-//		data["Players"] = 100;
-//		/// Set data which will be sent to all who requests LAN network discovery
-//		GetSubsystem<Network>()->SetDiscoveryBeacon(data);
-//		startServer_->SetVisible(false);
-//		stopServer_->SetVisible(true);
-//	}
-//}
-//
-//void LANDiscovery::HandleStopServer(StringHash eventType, VariantMap& eventData)
-//{
-//	GetSubsystem<Network>()->StopServer();
-//	startServer_->SetVisible(true);
-//	stopServer_->SetVisible(false);
-//}
-//
-//void LANDiscovery::HandleDoNetworkDiscovery(StringHash eventType, VariantMap& eventData)
-//{
-//	/// Pass in the port that should be checked
-//	GetSubsystem<Network>()->DiscoverHosts(SERVER_PORT);
-//	serverList_->SetText("");
-//}
 
 void P2PMultiplayer::CreateScene()
 {
@@ -454,7 +517,6 @@ void P2PMultiplayer::CreateScene()
 
     // Create the scene node & visual representation. This will be a replicated object
     Node* ballNode = scene_->CreateChild("Ball");
-    ball_ = ballNode;
     ballNode->SetPosition(Vector3(0, 10, 0));
     ballNode->SetScale(0.5f);
     auto* ballObject = ballNode->CreateComponent<StaticModel>();
@@ -466,7 +528,6 @@ void P2PMultiplayer::CreateScene()
     body->SetMass(1.0f);
     body->SetFriction(1.0f);
     body->SetRestitution(0.0);
-    body_ = body;
     // In addition to friction, use motion damping so that the ball can not accelerate limitlessly
     body->SetLinearDamping(0.5f);
 //    body->SetAngularDamping(0.5f);
@@ -495,6 +556,7 @@ void P2PMultiplayer::SetupViewport()
 
 void P2PMultiplayer::HandleClientConnected(StringHash eventType, VariantMap& eventData)
 {
+    URHO3D_LOGERROR("CLIENT CONNECTED!");
 //    return;
     using namespace ClientConnected;
 
@@ -503,15 +565,44 @@ void P2PMultiplayer::HandleClientConnected(StringHash eventType, VariantMap& eve
     newConnection->SetScene(scene_);
 
     CreatePlayerNode(newConnection);
+
+    UpdateClientObjects();
 }
 
 void P2PMultiplayer::HandleClientDisconnected(StringHash eventType, VariantMap& eventData)
 {
+    URHO3D_LOGERROR("CLIENT DISCONNECTED!");
     using namespace ClientConnected;
 //
 //    // When a client disconnects, remove the controlled object
     auto* connection = static_cast<Connection*>(eventData[P_CONNECTION].GetPtr());
     DestroyPlayerNode(connection);
+
+    UpdateClientObjects();
+}
+
+void P2PMultiplayer::UpdateClientObjects()
+{
+    PODVector<Node*> playerNodes;
+    scene_->GetNodesWithTag(playerNodes, "Player");
+    auto clients = GetSubsystem<Network>()->GetClientConnections();
+    for (auto it = clients.Begin(); it != clients.End(); ++it) {
+        for (auto it2 = playerNodes.Begin(); it2 != playerNodes.End(); ++it2) {
+            if ((*it2)->GetVar("GUID").GetString() == (*it)->GetGUID()) {
+//                URHO3D_LOGERROR("Found client controlled node");
+                playerNodes_[(*it)] = (*it2);
+            }
+        }
+    }
+    for (auto it2 = playerNodes.Begin(); it2 != playerNodes.End(); ++it2) {
+//        URHO3D_LOGERROR("GUID: " + (*it2)->GetVar("GUID").GetString() + " == " + GetSubsystem<Network>()->P2PGetGUID());
+        if ((*it2)->GetVar("GUID").GetString() == GetSubsystem<Network>()->P2PGetGUID()) {
+//            URHO3D_LOGERROR("We found our node with specific GUID!");
+            playerNodes_[GetSubsystem<Network>()->GetServerConnection()] = (*it2);
+        }
+    }
+//    URHO3D_LOGINFOF("Player nodes: %i", playerNodes_.Size());
+
 }
 
 void P2PMultiplayer::HandleResetHost(StringHash eventType, VariantMap& eventData)
@@ -538,6 +629,13 @@ void P2PMultiplayer::HandleDisconnect(StringHash eventType, VariantMap& eventDat
 
 void P2PMultiplayer::CreatePlayerNode(Connection* connection)
 {
+    if (playerNodes_[connection]) {
+        return;
+    }
+
+    if (GetSubsystem<Network>()->GetClientConnections().Size() != 0 && !GetSubsystem<Network>()->P2PIsHostSystem()) {
+        return;
+    }
     // Then create a controllable object for that client
 //    Node* newObject = CreateControllableObject();
 //    serverObjects_[newConnection] = newObject;
@@ -558,13 +656,18 @@ void P2PMultiplayer::CreatePlayerNode(Connection* connection)
     ballObject->SetModel(cache->GetResource<Model>("Models/Sphere.mdl"));
     ballObject->SetMaterial(cache->GetResource<Material>("Materials/StoneSmall.xml"));
 
+    auto* titleText = ballNode->CreateComponent<Text3D>(REPLICATED);
+    titleText->SetText(connection->GetGUID());
+    titleText->SetFaceCameraMode(FaceCameraMode::FC_LOOKAT_XYZ);
+    titleText->SetFont(cache->GetResource<Font>("Fonts/BlueHighway.sdf"), 24);
+
     // 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);
+    body->SetLinearDamping(0.5f);
+    body->SetAngularDamping(0.5f);
     //body->SetLinearVelocity(Vector3(0.1, 1, 0.1));
     auto* shape = ballNode->CreateComponent<CollisionShape>();
     shape->SetSphere(1.0f);

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

@@ -31,6 +31,8 @@ class Button;
 class LineEdit;
 class Text;
 class UIElement;
+class RigidBody;
+class HttpRequest;
 
 }
 
@@ -88,11 +90,9 @@ private:
     LineEdit* CreateLineEdit(const String& placeholder, int width, IntVector2 pos);
 //    /// Create label
     Text* CreateLabel(const String& text, IntVector2 pos);
-//
-//    /// Handle found LAN server
-    void HandleServerConnected(StringHash eventType, VariantMap& eventData);
 //    /// Start server
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
+    void HandlePhysicsPrestep(StringHash eventType, VariantMap& eventData);
 
     void HandleStartP2PSession(StringHash eventType, VariantMap& eventData);
     void HandleJoinP2PSession(StringHash eventType, VariantMap& eventData);
@@ -104,18 +104,14 @@ private:
 
     void HandleSessionStarted(StringHash eventType, VariantMap& eventData);
 
+    void UpdateClientObjects();
+
     void HandleDisconnect(StringHash eventType, VariantMap& eventData);
 
     void CreatePlayerNode(Connection* connection);
     void DestroyPlayerNode(Connection* connection);
 
     Timer timer_;
-//    /// Stop server
-//	void HandleStopServer(StringHash eventType, VariantMap& eventData);
-//	/// Start network discovery
-//	void HandleDoNetworkDiscovery(StringHash eventType, VariantMap& eventData);
-//    /// Start server
-//    SharedPtr<Button> startServer_;
     /// Start P2P Session
     SharedPtr<Button> startSession_;
     /// Join P2P Session
@@ -129,11 +125,8 @@ private:
     SharedPtr<Text> roleTitle_;
     SharedPtr<Text> myGuid_;
     SharedPtr<Text> hostGuid_;
-    SharedPtr<RigidBody> body_;
     HashMap<Connection*, WeakPtr<Node>> playerNodes_;
     String message_;
     SharedPtr<HttpRequest> httpRequest_;
-
-    SharedPtr<Node> ball_;
     bool _allReady;
 };

+ 1 - 1
Source/ThirdParty/SLikeNet/CMakeLists.txt

@@ -24,11 +24,11 @@ add_definitions (-D_RAKNET_SUPPORT_ConsoleServer=0 -D_RAKNET_SUPPORT_RakNetTrans
 add_definitions (-D_RAKNET_SUPPORT_Rackspace=0 -D_RAKNET_SUPPORT_PacketizedTCP=0 -D_RAKNET_SUPPORT_RPC4Plugin=0 -D_RAKNET_SUPPORT_Router2=0)
 add_definitions (-D_RAKNET_SUPPORT_MessageFilter=0 -D_RAKNET_SUPPORT_FileListTransfer=0)
 add_definitions (-D_RAKNET_SUPPORT_HTTPConnection2=0 -D_RAKNET_SUPPORT_HTTPConnection=0)
+add_definitions (-D_RAKNET_SUPPORT_PacketLogger=0)
 
 # Enable the ones we actually need
 # P2P Multiplayer
 add_definitions (-D_RAKNET_SUPPORT_FullyConnectedMesh2=1)
-add_definitions (-D_RAKNET_SUPPORT_PacketLogger=1)
 add_definitions (-D_RAKNET_SUPPORT_ReplicaManager3=1)
 add_definitions (-D_RAKNET_SUPPORT_ReadyEvent=1)
 

+ 7 - 6
Source/Urho3D/Network/Network.cpp

@@ -196,7 +196,7 @@ static const char* RAKNET_MESSAGEID_STRINGS[] = {
 };
 
 static const int DEFAULT_UPDATE_FPS = 30;
-static const int SERVER_TIMEOUT_TIME = 500;
+static const int SERVER_TIMEOUT_TIME = 5000;
 
 Network::Network(Context* context) :
     Object(context),
@@ -357,7 +357,6 @@ void Network::NewConnectionEstablished(const SLNet::AddressOrGUID& connection)
 {
     P2PReadyStatusChanged();
     if (networkMode_ == PEER_TO_PEER && clientConnections_[connection]) {
-        URHO3D_LOGERROR("3");
         URHO3D_LOGWARNINGF("Client already in the client list.", connection.rakNetGuid.ToString());
         //TODO proper scene state management
         clientConnections_[connection]->SetSceneLoaded(true);
@@ -859,7 +858,7 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
         }
         packetHandled = true;
     }
-    else if (packetID == ID_REMOTE_CONNECTION_LOST)
+    else if (packetID == ID_REMOTE_CONNECTION_LOST || packetID == ID_REMOTE_DISCONNECTION_NOTIFICATION)
     {
         //TODO find out who's really sending out this message
         URHO3D_LOGWARNING("ID_REMOTE_CONNECTION_LOST");
@@ -869,7 +868,7 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
     {
         if (natPunchServerAddress_ && packet->systemAddress == *natPunchServerAddress_) {
             URHO3D_LOGINFO("Already connected to NAT server! ");
-            if (!isServer)
+            if (!isServer && networkMode_ == SERVER_CLIENT)
             {
                 natPunchthroughClient_->OpenNAT(*remoteGUID_, *natPunchServerAddress_);
             }
@@ -889,8 +888,7 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
             if (networkMode_ == SERVER_CLIENT) {
                 OnServerConnected(packet->guid);
             } else {
-                URHO3D_LOGINFOF("ID_CONNECTION_REQUEST_ACCEPTED from %s,guid=%s", packet->systemAddress.ToString(true),
-                                packet->guid.ToString());
+                URHO3D_LOGINFOF("ID_CONNECTION_REQUEST_ACCEPTED from %s,guid=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
                 // Assume that we're connecting to the P2P host
 //                serverConnection_->SetAddressOrGUID(packet->guid);
 
@@ -902,6 +900,8 @@ void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
                 SLNet::BitStream bsOut;
                 bsOut.Write((unsigned char) MSG_P2P_JOIN_REQUEST);
                 rakPeer_->Send(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false);
+
+                //TODO send out our identity
             }
         }
         packetHandled = true;
@@ -1379,6 +1379,7 @@ void Network::HandleNATStartP2PSession(StringHash eventType, VariantMap& eventDa
     fullyConnectedMesh2_->ResetHostCalculation();
 
     hostGuid_ = P2PGetGUID();
+    isServer_ = true;
     P2PSetReady(false);
 
     SendEvent(E_P2PSESSIONSTARTED);