Skip to content
This repository has been archived by the owner on Jan 25, 2023. It is now read-only.

P2P multiplayer support with samples #2400

Open
wants to merge 60 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
51e145a
initial attempt
ArnisLielturks Oct 23, 2018
8fd86b8
additional updates to p2p, sample scene added
ArnisLielturks Oct 23, 2018
c149b6c
fully connected mesh and connection graph updates
ArnisLielturks Oct 24, 2018
153ada2
p2p flow updated
ArnisLielturks Oct 24, 2018
360498d
controls sent to host only, host updates replicated scene nodes
ArnisLielturks Oct 25, 2018
a307a45
remote connection lost message handled by peers
ArnisLielturks Oct 25, 2018
3a2f624
log cleanup, scene ready state for peers updated
ArnisLielturks Oct 25, 2018
56bb3b3
external server used for automatic guid detection, http calls are mad…
ArnisLielturks Oct 25, 2018
90f4705
minor updates to the peer/host indication, todo's added
ArnisLielturks Oct 25, 2018
b3abef4
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Oct 29, 2018
24890f0
Merge branch 'p2p-multiplayer' of github.com:urho3d/Urho3D into p2p-m…
ArnisLielturks Oct 29, 2018
7b9b24c
additional events and statuses
ArnisLielturks Oct 29, 2018
aff8d7a
p2p and server-client mode switching, ready event handling in p2p fixed
ArnisLielturks Oct 30, 2018
3bc4150
flows updated, disconnect functionality added
ArnisLielturks Oct 31, 2018
223efd9
sample updated, http request changes reverted
ArnisLielturks Nov 2, 2018
ba659d5
sample multiplayer movement added
ArnisLielturks Nov 5, 2018
76bd854
sample updated, unused functionality removed
ArnisLielturks Nov 6, 2018
d286526
linter errors fixed, MSG_IDENTITY flows updated for p2p
ArnisLielturks Nov 7, 2018
d0b1480
new host event added, identity sent out when host changes
ArnisLielturks Nov 7, 2018
018dcff
sample fixed, network interface updated, few methods improved regardi…
ArnisLielturks Nov 7, 2018
1986c9e
Connection ready state added, sample improved, ready state utilized
ArnisLielturks Nov 7, 2018
20de49c
ban logic added, code cleanup, network interface refactoring
ArnisLielturks Nov 8, 2018
c7d0abf
lobby started, message handling between client/server fixed, addition…
ArnisLielturks Nov 9, 2018
60ae0e9
server-client mode fixed
ArnisLielturks Nov 9, 2018
7fe6319
ready event fixes, minor sample updates
ArnisLielturks Nov 12, 2018
b69c760
player list added, network server connection guid fixed, client contr…
ArnisLielturks Nov 12, 2018
07d6e9b
ping added to player list, jump controls added to sample
ArnisLielturks Nov 12, 2018
08147cd
linter fixes
ArnisLielturks Nov 12, 2018
9c882d5
maximum incomming connections are now configurable, additional networ…
ArnisLielturks Nov 13, 2018
3742397
p2p and server-client mode mismatch, nat punchtrough sample updated
ArnisLielturks Nov 14, 2018
817c938
master server updating
ArnisLielturks Nov 14, 2018
0c3f5dc
master server conections updated
ArnisLielturks Nov 14, 2018
aa74b9d
sample updated
ArnisLielturks Nov 14, 2018
b4913e9
Merge remote-tracking branch 'origin/master' into p2p-multiplayer
ArnisLielturks Nov 14, 2018
325f2b6
small update
ArnisLielturks Nov 15, 2018
9f4d9cd
Master server API address updated, NAT master server address updated,…
ArnisLielturks Nov 20, 2018
9fbc2b0
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Nov 20, 2018
903b17c
randomness added to nickname, MessageBox issue fixed (hopefully)
ArnisLielturks Nov 20, 2018
455c565
Merge remote-tracking branch 'origin/master' into p2p-multiplayer
ArnisLielturks Dec 1, 2018
8b1248c
AS and LUA integration started, AS and LUA samples added, minor code …
ArnisLielturks Dec 3, 2018
ffea9f3
Merge branch 'p2p-multiplayer' of github.com:urho3d/Urho3D into p2p-m…
ArnisLielturks Dec 3, 2018
c421bcf
simplified C++ sample added, Lua, AS samples updated
ArnisLielturks Dec 6, 2018
0c1c9c5
sample bugs fixed, additional information added to p2p samples
ArnisLielturks Dec 6, 2018
0bfe71a
CMakeLists changes reverted to original
ArnisLielturks Dec 6, 2018
0bac396
packet logger removed
ArnisLielturks Dec 6, 2018
d4a35e2
PacketLogger fix
ArnisLielturks Dec 7, 2018
501fd6b
reset host button added to all samples
ArnisLielturks Dec 7, 2018
e8de34f
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Dec 17, 2018
0020ec7
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Jan 22, 2019
0660acb
P2P multiplayer extended sample removed
ArnisLielturks Feb 14, 2019
e71e751
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Feb 25, 2019
31fb5dc
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Apr 9, 2019
043f954
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Apr 11, 2019
7bcd6be
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks May 20, 2019
c89e98c
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Aug 20, 2019
f3b62a8
minor fix
ArnisLielturks Aug 23, 2019
816e705
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Aug 23, 2019
9680a2e
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Mar 8, 2020
0b43521
small fix
ArnisLielturks Mar 8, 2020
90b7585
Merge branch 'master' of github.com:urho3d/Urho3D into p2p-multiplayer
ArnisLielturks Sep 17, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Docs/Reference.dox
Original file line number Diff line number Diff line change
Expand Up @@ -3111,7 +3111,7 @@ The event includes the attribute name, index, new value as a Variant, and the la

\section Network_Messages Raw network messages

All network messages have an integer ID. The first ID you can use for custom messages is 153 (lower ID's are either reserved for SLikeNet's or the %Network subsystem's internal use.) Messages can be sent either unreliably or reliably, in-order or unordered. The data payload is simply raw binary data that can be crafted by using for example VectorBuffer.
All network messages have an integer ID. The first ID you can use for custom messages is 155 (lower ID's are either reserved for SLikeNet's or the %Network subsystem's internal use.) Messages can be sent either unreliably or reliably, in-order or unordered. The data payload is simply raw binary data that can be crafted by using for example VectorBuffer.

To send a message to a Connection, use its \ref Connection::SendMessage "SendMessage()" function. On the server, messages can also be broadcast to all client connections by calling the \ref Network::BroadcastMessage "BroadcastMessage()" function.

Expand Down
3 changes: 2 additions & 1 deletion Source/Samples/16_Chat/Chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
#endif

// Identifier for the chat network messages
const int MSG_CHAT = 154;
const int MSG_CHAT = 200;

// UDP port we will use
const unsigned short CHAT_SERVER_PORT = 2345;

Expand Down
37 changes: 37 additions & 0 deletions Source/Samples/55_P2PMultiplayer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Copyright (c) 2008-2018 the Urho3D project.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

if (NOT URHO3D_NETWORK)
return ()
endif ()

# Define target name
set (TARGET_NAME 55_P2PMultiplayer)

# Define source files
define_source_files (EXTRA_H_FILES ${COMMON_SAMPLE_H_FILES})

# Setup target with resource copying
setup_main_executable ()

# Setup test cases
setup_test ()
303 changes: 303 additions & 0 deletions Source/Samples/55_P2PMultiplayer/P2PMultiplayer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
//
// Copyright (c) 2008-2018 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <Urho3D/Audio/Audio.h>
#include <Urho3D/Audio/Sound.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Engine/Engine.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/Zone.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/IO/IOEvents.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/IO/MemoryBuffer.h>
#include <Urho3D/IO/VectorBuffer.h>
#include <Urho3D/Network/Network.h>
#include <Urho3D/Network/NetworkEvents.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/UI/Button.h>
#include <Urho3D/UI/Font.h>
#include <Urho3D/UI/LineEdit.h>
#include <Urho3D/UI/Text.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/UI/UIEvents.h>

#include "P2PMultiplayer.h"

#include <Urho3D/DebugNew.h>

// Undefine Windows macro, as our Connection class has a function called SendMessage
#ifdef SendMessage
#undef SendMessage
#endif

URHO3D_DEFINE_APPLICATION_MAIN(P2PMultplayer)

P2PMultplayer::P2PMultplayer(Context* context) :
Sample(context)
{
}

void P2PMultplayer::Start()
{
// Execute base class startup
Sample::Start();

// Enable OS cursor
GetSubsystem<Input>()->SetMouseVisible(true);

// Create the user interface
CreateUI();

// Subscribe to UI and network events
SubscribeToEvents();

// Set the mouse mode to use in the sample
Sample::InitMouseMode(MM_FREE);

GetSubsystem<Network>()->SetMode(PEER_TO_PEER);
}

void P2PMultplayer::CreateUI()
{
SetLogoVisible(true); // We need the full rendering window

auto* graphics = GetSubsystem<Graphics>();
UIElement* root = GetSubsystem<UI>()->GetRoot();
auto* cache = GetSubsystem<ResourceCache>();
auto* uiStyle = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
// Set style to the UI root so that elements will inherit it
root->SetDefaultStyle(uiStyle);

auto* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
logHistoryText_ = root->CreateChild<Text>();
logHistoryText_->SetFont(font, 12);
logHistoryText_->SetPosition(20, 200);
logHistory_.Resize(20);

// Create NAT server config fields
int marginTop = 40;
CreateLabel("1. Run NAT server somewhere, enter NAT server info and press 'Save NAT settings'", IntVector2(20, marginTop-20));
natServerAddress_ = CreateLineEdit("nat.frameskippers.com", 200, IntVector2(20, marginTop));
natServerPort_ = CreateLineEdit("30123", 100, IntVector2(240, marginTop));
saveNatSettingsButton_ = CreateButton("Save NAT settings", 160, IntVector2(360, marginTop));

// Create server start button
marginTop = 120;
CreateLabel("2. Create server and give others your server GUID", IntVector2(20, marginTop-20));
guid_ = CreateLineEdit("Your server GUID", 200, IntVector2(20, marginTop));
startServerButton_ = CreateButton("Start server", 160, IntVector2(240, marginTop));

// Create client connection related fields
marginTop = 200;
CreateLabel("3. Input remote server GUID", IntVector2(20, marginTop-20));
serverGuid_ = CreateLineEdit("Remote server GUID", 200, IntVector2(20, marginTop));
connectButton_ = CreateButton("Connect", 160, IntVector2(240, marginTop));

marginTop = 240;
peerCount_ = CreateLabel("Peers: 0", IntVector2(20, marginTop));
marginTop = 260;
myInfo_ = CreateLabel("My GUID: ", IntVector2(20, marginTop));
marginTop = 280;
hostInfo_ = CreateLabel("Host: ", IntVector2(20, marginTop));

marginTop = 340;
CreateLabel("Give the 'host' role to other peers. Whoever is the host acts as a server.", IntVector2(20, marginTop));
marginTop = 360;
resetHost_ = CreateButton("Reset host", 240, 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));
}

void P2PMultplayer::SubscribeToEvents()
{
SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(P2PMultplayer, HandleUpdate));
SubscribeToEvent(E_SERVERCONNECTED, URHO3D_HANDLER(P2PMultplayer, HandleServerConnected));
SubscribeToEvent(E_SERVERDISCONNECTED, URHO3D_HANDLER(P2PMultplayer, HandleServerDisconnected));
SubscribeToEvent(E_CONNECTFAILED, URHO3D_HANDLER(P2PMultplayer, HandleConnectFailed));

// NAT server connection related events
SubscribeToEvent(E_NATMASTERCONNECTIONFAILED, URHO3D_HANDLER(P2PMultplayer, HandleNatConnectionFailed));
SubscribeToEvent(E_NATMASTERCONNECTIONSUCCEEDED, URHO3D_HANDLER(P2PMultplayer, HandleNatConnectionSucceeded));

// NAT punchtrough request events
SubscribeToEvent(E_NETWORKNATPUNCHTROUGHSUCCEEDED, URHO3D_HANDLER(P2PMultplayer, HandleNatPunchtroughSucceeded));
SubscribeToEvent(E_NETWORKNATPUNCHTROUGHFAILED, URHO3D_HANDLER(P2PMultplayer, HandleNatPunchtroughFailed));

SubscribeToEvent(E_CLIENTCONNECTED, URHO3D_HANDLER(P2PMultplayer, HandleClientConnected));
SubscribeToEvent(E_CLIENTDISCONNECTED, URHO3D_HANDLER(P2PMultplayer, HandleClientDisconnected));

SubscribeToEvent(saveNatSettingsButton_, "Released", URHO3D_HANDLER(P2PMultplayer, HandleSaveNatSettings));
SubscribeToEvent(startServerButton_, "Released", URHO3D_HANDLER(P2PMultplayer, HandleStartServer));
SubscribeToEvent(connectButton_, "Released", URHO3D_HANDLER(P2PMultplayer, HandleConnect));
SubscribeToEvent(resetHost_, "Released", URHO3D_HANDLER(P2PMultplayer, HandleResetHost));
}

Button* P2PMultplayer::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* P2PMultplayer::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* P2PMultplayer::CreateLabel(const String& text, IntVector2 pos)
{
auto* cache = GetSubsystem<ResourceCache>();
// Create log element to view latest logs from the system
auto* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
auto* label = GetSubsystem<UI>()->GetRoot()->CreateChild<Text>();
label->SetFont(font, 12);
label->SetColor(Color(0.0f, 1.0f, 0.0f));
label->SetPosition(pos);
label->SetText(text);

return label;
}

void P2PMultplayer::ShowLogMessage(const String& row)
{
logHistory_.Erase(0);
logHistory_.Push(row);

// Concatenate all the rows in history
String allRows;
for (unsigned i = 0; i < logHistory_.Size(); ++i)
allRows += logHistory_[i] + "\n";

logHistoryText_->SetText(allRows);
}

void P2PMultplayer::HandleSaveNatSettings(StringHash eventType, VariantMap& eventData)
{
// Save NAT server configuration
GetSubsystem<Network>()->SetNATServerInfo(natServerAddress_->GetText(), ToInt(natServerPort_->GetText()));
ShowLogMessage("Saving NAT settings: " + natServerAddress_->GetText() + ":" + natServerPort_->GetText());
}

void P2PMultplayer::HandleServerConnected(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Client: Server connected!");
}

void P2PMultplayer::HandleServerDisconnected(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Client: Server disconnected!");
}

void P2PMultplayer::HandleConnectFailed(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Client: Connection failed!");
}

void P2PMultplayer::HandleStartServer(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Server: Server started P2P session");

GetSubsystem<Network>()->StartSession(scene_);
// Output our assigned GUID which others will use to connect to our server
guid_->SetText(GetSubsystem<Network>()->GetGUID());
}

void P2PMultplayer::HandleConnect(StringHash eventType, VariantMap& eventData)
{
VariantMap userData = GetEventDataMap();
userData["Name"] = "Urho3D";

// Attempt connecting to server using custom GUID, Scene = null as a second parameter and user identity is passed as third parameter
GetSubsystem<Network>()->JoinSession(serverGuid_->GetText(), scene_, userData);
ShowLogMessage("Client: Attempting Join P2@ session " + serverGuid_->GetText());
}

void P2PMultplayer::HandleNatConnectionFailed(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Connection to NAT master server failed!");
}

void P2PMultplayer::HandleNatConnectionSucceeded(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Connection to NAT master server succeeded!");
}

void P2PMultplayer::HandleNatPunchtroughSucceeded(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("NAT punchtrough succeeded!");
}

void P2PMultplayer::HandleNatPunchtroughFailed(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("NAT punchtrough failed!");
}

void P2PMultplayer::HandleClientConnected(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Server: Client connected!");
}

void P2PMultplayer::HandleClientDisconnected(StringHash eventType, VariantMap& eventData)
{
ShowLogMessage("Server: Client disconnected!");
}

void P2PMultplayer::UpdateInfo()
{
peerCount_->SetText("Peers: " + String(GetSubsystem<Network>()->GetParticipantCount()));
hostInfo_->SetText("Host: " + GetSubsystem<Network>()->GetHostAddress());
myInfo_->SetText("My GUID: " + GetSubsystem<Network>()->GetGUID());
}

void P2PMultplayer::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
if (updateTimer_.GetMSec(false) > 500) {
updateTimer_.Reset();
UpdateInfo();
}
}

void P2PMultplayer::HandleResetHost(StringHash eventType, VariantMap& eventData)
{
GetSubsystem<Network>()->ResetHost();
}
Loading