summaryrefslogtreecommitdiff
path: root/Runtime/Network/PlayerCommunicator/EditorConnection.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Network/PlayerCommunicator/EditorConnection.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Network/PlayerCommunicator/EditorConnection.cpp')
-rw-r--r--Runtime/Network/PlayerCommunicator/EditorConnection.cpp335
1 files changed, 335 insertions, 0 deletions
diff --git a/Runtime/Network/PlayerCommunicator/EditorConnection.cpp b/Runtime/Network/PlayerCommunicator/EditorConnection.cpp
new file mode 100644
index 0000000..d8814fa
--- /dev/null
+++ b/Runtime/Network/PlayerCommunicator/EditorConnection.cpp
@@ -0,0 +1,335 @@
+#include "UnityPrefix.h"
+
+#if UNITY_EDITOR
+
+#include "EditorConnection.h"
+#include "Editor/Platform/Interface/EditorWindows.h"
+#include "Runtime/Misc/SystemInfo.h"
+
+#include "Runtime/Serialize/FileCache.h"
+#include "Runtime/Serialize/CacheWrap.h"
+
+#include "Runtime/Network/NetworkUtility.h"
+#include "Runtime/Profiler/TimeHelper.h"
+#include "Runtime/Math/Random/rand.h"
+#include "Runtime/Utilities/PathNameUtility.h"
+#include "Runtime/Utilities/PlayerPrefs.h"
+#include "Runtime/Threads/Thread.h"
+
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "Runtime/Network/PlayerCommunicator/GeneralConnectionInternals.h"
+#include "Runtime/Network/PlayerCommunicator/PlayerConnection.h"
+
+static const char* kLastConnectedPlayer = "LastConnectedPlayer";
+
+EditorConnection* EditorConnection::ms_Instance = NULL;
+
+
+EditorConnection::EditorConnection(unsigned short multicastPort)
+: GeneralConnection()
+{
+ ABSOLUTE_TIME_INIT(m_LastCleanup);
+ if (!m_MulticastSocket.Initialize(PLAYER_MULTICAST_GROUP, multicastPort))
+ ErrorStringMsg("Failed to setup multicast socket for player connection.");
+ if (!m_MulticastSocket.Join())
+ ErrorStringMsg("Unable to join player connection multicast group.");
+}
+
+EditorConnection& EditorConnection::Get()
+{
+ return *ms_Instance;
+}
+
+void EditorConnection::Initialize ()
+{
+ GeneralConnection::Initialize();
+ Assert(ms_Instance == NULL);
+ ms_Instance = new EditorConnection();
+}
+void EditorConnection::Cleanup ()
+{
+ Assert(ms_Instance != NULL);
+ delete ms_Instance;
+ ms_Instance = NULL;
+ GeneralConnection::Cleanup();
+}
+
+int EditorConnection::ConnectPlayerDirectIP(const std::string& IP)
+{
+ Connection* cnx = GetConnection(PLAYER_DIRECT_IP_CONNECT_GUID);
+ if (cnx && cnx->IsValid())
+ return PLAYER_DIRECT_IP_CONNECT_GUID;
+
+ int socketHandle = -1;
+ int timeout = 1;
+ // Poll at 1 ms, 10 ms, and 100 ms before giving up
+ while (socketHandle == -1)
+ {
+ // A forced repaint is required, since this method is a blocking call
+ LogStringMsg("Attempting to connect to player ip: %s with a %d ms timeout", IP.c_str(), timeout);
+ ForceRepaintOnAllViews();
+
+ for(int i = 0; i <= PLAYER_PORT_MASK; i++)
+ {
+ socketHandle = ::Socket::Connect(IP.c_str(), PLAYER_LISTEN_PORT + i, timeout, true, false);
+ if(socketHandle != -1)
+ break;
+ }
+ if (socketHandle != -1)
+ break;
+
+ timeout *= 10;
+ if (timeout > 100)
+ break;
+ }
+ if(socketHandle == -1)
+ {
+ ErrorStringMsg("Failed to connect to player ip: %s", IP.c_str());
+ return -1;
+ }
+
+ RegisterConnection(PLAYER_DIRECT_IP_CONNECT_GUID, socketHandle);
+ if (!ms_RunningUnitTests)
+ EditorPrefs::SetString(kLastConnectedPlayer, "");
+
+ return PLAYER_DIRECT_IP_CONNECT_GUID;
+}
+
+int EditorConnection::ConnectPlayer (UInt32 guid)
+{
+ AvailablePlayerMap::iterator found = m_AvailablePlayers.find(guid);
+ if (found == m_AvailablePlayers.end())
+ return -1;
+
+ MulticastInfo& multicastInfo = found->second.m_MulticastInfo;
+ if(!multicastInfo.IsValid())
+ return -1;
+
+ Assert(multicastInfo.GetGuid() == guid);
+ Connection* cnx = GetConnection(guid);
+ if (cnx && cnx->IsValid())
+ return guid;
+
+ int socketHandle;
+ if (SOCK_ERROR(socketHandle = ::Socket::Connect(multicastInfo.GetIP().c_str(), multicastInfo.GetPort(), 500 /*timeout*/)))
+ {
+ ErrorStringMsg("Failed to connect to player ip: %s, port: %d", multicastInfo.GetIP().c_str(), multicastInfo.GetPort());
+ return 0;
+ }
+
+ RegisterConnection(guid, socketHandle);
+ if (!ms_RunningUnitTests)
+ EditorPrefs::SetString(kLastConnectedPlayer, multicastInfo.GetIdentifier());
+
+ return guid;
+}
+
+UInt32 EditorConnection::AddPlayer(std::string hostName, std::string localIP, unsigned short port, UInt32 guid, int flags)
+{
+ std::string buffer = Format(SERVER_IDENTIFICATION_FORMAT, localIP.c_str(), port, flags, guid, -1, ms_Version, hostName.c_str(), 0 );
+ MulticastInfo multicastInfo;
+ if(multicastInfo.Parse(buffer.c_str()))
+ {
+ AvailablePlayerMap::iterator found = m_AvailablePlayers.find(multicastInfo.GetGuid());
+ if(found != m_AvailablePlayers.end())
+ {
+ // entry already in the list - renew the timestamp
+ found->second.m_LastPing = START_TIME;
+ }
+ else
+ {
+ m_AvailablePlayers.insert (std::make_pair(multicastInfo.GetGuid(), AvailablePlayer(START_TIME, multicastInfo))).first;
+ }
+ return multicastInfo.GetGuid();
+ }
+ return 0;
+}
+
+void EditorConnection::RemovePlayer(UInt32 guid)
+{
+ Disconnect(guid);
+ AvailablePlayerMap::iterator found = m_AvailablePlayers.find(guid);
+ if(found != m_AvailablePlayers.end())
+ m_AvailablePlayers.erase(found);
+}
+
+void EditorConnection::EnablePlayer(UInt32 guid, bool enable)
+{
+ AvailablePlayerMap::iterator player = m_AvailablePlayers.find(guid);
+ if (player != m_AvailablePlayers.end())
+ player->second.m_Enabled = enable;
+}
+
+void
+EditorConnection::ResetLastPlayer()
+{
+ EditorPrefs::SetString(kLastConnectedPlayer, "");
+}
+
+void EditorConnection::GetAvailablePlayers( std::vector<UInt32>& values )
+{
+ AvailablePlayerMap::iterator it = m_AvailablePlayers.begin();
+ for( ; it != m_AvailablePlayers.end(); ++it){
+ if (it->second.m_Enabled && it->second.m_MulticastInfo.GetIP() == m_LocalIP)
+ values.push_back(it->second.m_MulticastInfo.GetGuid());
+ }
+ it = m_AvailablePlayers.begin();
+ for( ; it != m_AvailablePlayers.end(); ++it){
+ if (it->second.m_Enabled && it->second.m_MulticastInfo.GetIP() != m_LocalIP)
+ values.push_back(it->second.m_MulticastInfo.GetGuid());
+ }
+}
+
+void EditorConnection::GetAvailablePlayers(RuntimePlatform platform, vector<UInt32>& values)
+{
+ string const id = systeminfo::GetRuntimePlatformString(platform);
+
+ for (AvailablePlayerMap::const_iterator it = m_AvailablePlayers.begin() ; it != m_AvailablePlayers.end(); ++it)
+ {
+ AvailablePlayer const& player = it->second;
+ if (player.m_Enabled && BeginsWith(player.m_MulticastInfo.GetIdentifier(), id) && (player.m_MulticastInfo.GetIP() == m_LocalIP))
+ values.push_back(player.m_MulticastInfo.GetGuid());
+ }
+
+ for (AvailablePlayerMap::const_iterator it = m_AvailablePlayers.begin() ; it != m_AvailablePlayers.end(); ++it)
+ {
+ AvailablePlayer const& player = it->second;
+ if (player.m_Enabled && BeginsWith(player.m_MulticastInfo.GetIdentifier(), id) && (player.m_MulticastInfo.GetIP() != m_LocalIP))
+ values.push_back(player.m_MulticastInfo.GetGuid());
+ }
+}
+
+std::string EditorConnection::GetConnectionIdentifier( UInt32 guid )
+{
+ AvailablePlayerMap::iterator it = m_AvailablePlayers.find(guid);
+ if (it != m_AvailablePlayers.end())
+ return it->second.m_MulticastInfo.GetIdentifier();
+ return "None";
+}
+
+bool EditorConnection::IsIdentifierConnectable( UInt32 guid )
+{
+ AvailablePlayerMap::iterator it = m_AvailablePlayers.find(guid);
+ if (it != m_AvailablePlayers.end())
+ return it->second.m_MulticastInfo.IsValid();
+ return false;
+}
+
+bool EditorConnection::IsIdentifierOnLocalhost( UInt32 guid )
+{
+ AvailablePlayerMap::iterator it = m_AvailablePlayers.find(guid);
+ if (it != m_AvailablePlayers.end())
+ return it->second.m_MulticastInfo.IsLocalhost();
+ return false;
+}
+
+GeneralConnection::MulticastInfo EditorConnection::PollWithCustomMessage()
+{
+ MulticastInfo multicastInfo;
+
+ sockaddr_in srcaddr;
+ socklen_t srcaddr_len = sizeof(srcaddr);
+ char buffer[kMulticastBufferSize];
+ RecvUserData recvData;
+ recvData.srcAddr = (struct sockaddr*)&srcaddr;
+ recvData.srcLen = srcaddr_len;
+ int size = m_MulticastSocket.Recv(buffer, kMulticastBufferSize, &recvData);
+ if (!SOCK_ERROR(size))
+ {
+ // Ensure that buffer is null terminated string
+ buffer[size] = 0;
+ if(multicastInfo.Parse(buffer, &srcaddr))
+ {
+ AvailablePlayerMap::iterator found = m_AvailablePlayers.find(multicastInfo.GetGuid());
+ if(found != m_AvailablePlayers.end())
+ {
+ // entry already in the list - renew the timestamp
+ found->second.m_LastPing = START_TIME;
+ }
+ else
+ {
+ // remove old player if new one has connected
+ for (AvailablePlayerMap::const_iterator it = m_AvailablePlayers.begin(); it != m_AvailablePlayers.end(); ++it)
+ if (!it->second.m_Enabled && !StrCmp(it->second.m_MulticastInfo.GetIdentifier(), multicastInfo.GetIdentifier()))
+ {
+ RemovePlayer(it->first);
+ break;
+ }
+
+ m_AvailablePlayers.insert (std::make_pair(multicastInfo.GetGuid(), AvailablePlayer(START_TIME, multicastInfo)));
+ if (multicastInfo.IsValid() && multicastInfo.ImmediateConnect())
+ {
+ bool atemptAutoConnect;
+ if (ms_RunningUnitTests)
+ {
+ atemptAutoConnect = false;
+ if (!IsConnected())
+ {
+ const char* connectingIp = multicastInfo.GetIP().c_str();
+
+ const int maxNumberOfIps = 10;
+ char localIps[maxNumberOfIps][16];
+ GetIPs(localIps);
+ for (int i = 0; i < maxNumberOfIps; ++i)
+ {
+ if (strcmp(localIps[i], connectingIp) == 0)
+ {
+ atemptAutoConnect = true;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ string lastPlayerId = EditorPrefs::GetString(kLastConnectedPlayer);
+
+ // No prior player are known and new player is built by us and requires autoconnection
+ if (lastPlayerId.empty() && multicastInfo.GetEditorGuid() == GetLocalGuid())
+ atemptAutoConnect = true;
+ else
+ atemptAutoConnect = (lastPlayerId == multicastInfo.GetIdentifier());
+ }
+
+ if (atemptAutoConnect)
+ ConnectPlayer(multicastInfo.GetGuid());
+ }
+ }
+ }
+ else
+ {
+ // can not connect to this player (version mismatch)
+
+ }
+ }
+
+ // clean up the list every 2 seconds ( players not pinging in 10 seconds are removed from the map )
+ if(GetProfileTime(ELAPSED_TIME(m_LastCleanup)) > 2*kTimeSecond)
+ {
+ m_LastCleanup = START_TIME;
+ AvailablePlayerMap::iterator it = m_AvailablePlayers.begin();
+ while (it != m_AvailablePlayers.end())
+ {
+ UInt32 guid = it->first;
+ AvailablePlayer& player = it->second;
+ if (player.m_MulticastInfo.GetGuid() == PLAYER_DIRECTCONNECT_GUID)
+ {
+ ++it;
+ continue;
+ }
+ if (!GetConnection(guid) && (GetProfileTime(ELAPSED_TIME(player.m_LastPing)) > 10*kTimeSecond))
+ {
+ AvailablePlayerMap::iterator erase = it++;
+ m_AvailablePlayers.erase(erase);
+ }
+ else
+ ++it;
+ }
+ }
+
+ GeneralConnection::Poll();
+
+ return multicastInfo;
+}
+
+#endif // ENABLE_PLAYERCONNECTION