Network.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. //
  2. // Copyright (c) 2008-2020 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Core/Context.h"
  24. #include "../Core/CoreEvents.h"
  25. #include "../Core/Profiler.h"
  26. #include "../Engine/EngineEvents.h"
  27. #include "../IO/FileSystem.h"
  28. #include "../Input/InputEvents.h"
  29. #include "../IO/IOEvents.h"
  30. #include "../IO/Log.h"
  31. #include "../IO/MemoryBuffer.h"
  32. #include "../Network/HttpRequest.h"
  33. #include "../Network/Network.h"
  34. #include "../Network/NetworkEvents.h"
  35. #include "../Network/NetworkPriority.h"
  36. #include "../Network/Protocol.h"
  37. #include "../Scene/Scene.h"
  38. #include <SLikeNet/MessageIdentifiers.h>
  39. #include <SLikeNet/NatPunchthroughClient.h>
  40. #include <SLikeNet/peerinterface.h>
  41. #include <SLikeNet/statistics.h>
  42. #ifdef SendMessage
  43. #undef SendMessage
  44. #endif
  45. #include "../DebugNew.h"
  46. namespace Urho3D
  47. {
  48. static const char* RAKNET_MESSAGEID_STRINGS[] = {
  49. "ID_CONNECTED_PING",
  50. "ID_UNCONNECTED_PING",
  51. "ID_UNCONNECTED_PING_OPEN_CONNECTIONS",
  52. "ID_CONNECTED_PONG",
  53. "ID_DETECT_LOST_CONNECTIONS",
  54. "ID_OPEN_CONNECTION_REQUEST_1",
  55. "ID_OPEN_CONNECTION_REPLY_1",
  56. "ID_OPEN_CONNECTION_REQUEST_2",
  57. "ID_OPEN_CONNECTION_REPLY_2",
  58. "ID_CONNECTION_REQUEST",
  59. "ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY",
  60. "ID_OUR_SYSTEM_REQUIRES_SECURITY",
  61. "ID_PUBLIC_KEY_MISMATCH",
  62. "ID_OUT_OF_BAND_INTERNAL",
  63. "ID_SND_RECEIPT_ACKED",
  64. "ID_SND_RECEIPT_LOSS",
  65. "ID_CONNECTION_REQUEST_ACCEPTED",
  66. "ID_CONNECTION_ATTEMPT_FAILED",
  67. "ID_ALREADY_CONNECTED",
  68. "ID_NEW_INCOMING_CONNECTION",
  69. "ID_NO_FREE_INCOMING_CONNECTIONS",
  70. "ID_DISCONNECTION_NOTIFICATION",
  71. "ID_CONNECTION_LOST",
  72. "ID_CONNECTION_BANNED",
  73. "ID_INVALID_PASSWORD",
  74. "ID_INCOMPATIBLE_PROTOCOL_VERSION",
  75. "ID_IP_RECENTLY_CONNECTED",
  76. "ID_TIMESTAMP",
  77. "ID_UNCONNECTED_PONG",
  78. "ID_ADVERTISE_SYSTEM",
  79. "ID_DOWNLOAD_PROGRESS",
  80. "ID_REMOTE_DISCONNECTION_NOTIFICATION",
  81. "ID_REMOTE_CONNECTION_LOST",
  82. "ID_REMOTE_NEW_INCOMING_CONNECTION",
  83. "ID_FILE_LIST_TRANSFER_HEADER",
  84. "ID_FILE_LIST_TRANSFER_FILE",
  85. "ID_FILE_LIST_REFERENCE_PUSH_ACK",
  86. "ID_DDT_DOWNLOAD_REQUEST",
  87. "ID_TRANSPORT_STRING",
  88. "ID_REPLICA_MANAGER_CONSTRUCTION",
  89. "ID_REPLICA_MANAGER_SCOPE_CHANGE",
  90. "ID_REPLICA_MANAGER_SERIALIZE",
  91. "ID_REPLICA_MANAGER_DOWNLOAD_STARTED",
  92. "ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE",
  93. "ID_RAKVOICE_OPEN_CHANNEL_REQUEST",
  94. "ID_RAKVOICE_OPEN_CHANNEL_REPLY",
  95. "ID_RAKVOICE_CLOSE_CHANNEL",
  96. "ID_RAKVOICE_DATA",
  97. "ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE",
  98. "ID_AUTOPATCHER_CREATION_LIST",
  99. "ID_AUTOPATCHER_DELETION_LIST",
  100. "ID_AUTOPATCHER_GET_PATCH",
  101. "ID_AUTOPATCHER_PATCH_LIST",
  102. "ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR",
  103. "ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES",
  104. "ID_AUTOPATCHER_FINISHED_INTERNAL",
  105. "ID_AUTOPATCHER_FINISHED",
  106. "ID_AUTOPATCHER_RESTART_APPLICATION",
  107. "ID_NAT_PUNCHTHROUGH_REQUEST",
  108. "ID_NAT_CONNECT_AT_TIME",
  109. "ID_NAT_GET_MOST_RECENT_PORT",
  110. "ID_NAT_CLIENT_READY",
  111. "ID_NAT_TARGET_NOT_CONNECTED",
  112. "ID_NAT_TARGET_UNRESPONSIVE",
  113. "ID_NAT_CONNECTION_TO_TARGET_LOST",
  114. "ID_NAT_ALREADY_IN_PROGRESS",
  115. "ID_NAT_PUNCHTHROUGH_FAILED",
  116. "ID_NAT_PUNCHTHROUGH_SUCCEEDED",
  117. "ID_READY_EVENT_SET",
  118. "ID_READY_EVENT_UNSET",
  119. "ID_READY_EVENT_ALL_SET",
  120. "ID_READY_EVENT_QUERY",
  121. "ID_LOBBY_GENERAL",
  122. "ID_RPC_REMOTE_ERROR",
  123. "ID_RPC_PLUGIN",
  124. "ID_FILE_LIST_REFERENCE_PUSH",
  125. "ID_READY_EVENT_FORCE_ALL_SET",
  126. "ID_ROOMS_EXECUTE_FUNC",
  127. "ID_ROOMS_LOGON_STATUS",
  128. "ID_ROOMS_HANDLE_CHANGE",
  129. "ID_LOBBY2_SEND_MESSAGE",
  130. "ID_LOBBY2_SERVER_ERROR",
  131. "ID_FCM2_NEW_HOST",
  132. "ID_FCM2_REQUEST_FCMGUID",
  133. "ID_FCM2_RESPOND_CONNECTION_COUNT",
  134. "ID_FCM2_INFORM_FCMGUID",
  135. "ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT",
  136. "ID_FCM2_VERIFIED_JOIN_START",
  137. "ID_FCM2_VERIFIED_JOIN_CAPABLE",
  138. "ID_FCM2_VERIFIED_JOIN_FAILED",
  139. "ID_FCM2_VERIFIED_JOIN_ACCEPTED",
  140. "ID_FCM2_VERIFIED_JOIN_REJECTED",
  141. "ID_UDP_PROXY_GENERAL",
  142. "ID_SQLite3_EXEC",
  143. "ID_SQLite3_UNKNOWN_DB",
  144. "ID_SQLLITE_LOGGER",
  145. "ID_NAT_TYPE_DETECTION_REQUEST",
  146. "ID_NAT_TYPE_DETECTION_RESULT",
  147. "ID_ROUTER_2_INTERNAL",
  148. "ID_ROUTER_2_FORWARDING_NO_PATH",
  149. "ID_ROUTER_2_FORWARDING_ESTABLISHED",
  150. "ID_ROUTER_2_REROUTED",
  151. "ID_TEAM_BALANCER_INTERNAL",
  152. "ID_TEAM_BALANCER_REQUESTED_TEAM_FULL",
  153. "ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED",
  154. "ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED",
  155. "ID_TEAM_BALANCER_TEAM_ASSIGNED",
  156. "ID_LIGHTSPEED_INTEGRATION",
  157. "ID_XBOX_LOBBY",
  158. "ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS",
  159. "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS",
  160. "ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE",
  161. "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE",
  162. "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT",
  163. "ID_TWO_WAY_AUTHENTICATION_NEGOTIATION",
  164. "ID_CLOUD_POST_REQUEST",
  165. "ID_CLOUD_RELEASE_REQUEST",
  166. "ID_CLOUD_GET_REQUEST",
  167. "ID_CLOUD_GET_RESPONSE",
  168. "ID_CLOUD_UNSUBSCRIBE_REQUEST",
  169. "ID_CLOUD_SERVER_TO_SERVER_COMMAND",
  170. "ID_CLOUD_SUBSCRIPTION_NOTIFICATION",
  171. "ID_LIB_VOICE",
  172. "ID_RELAY_PLUGIN",
  173. "ID_NAT_REQUEST_BOUND_ADDRESSES",
  174. "ID_NAT_RESPOND_BOUND_ADDRESSES",
  175. "ID_FCM2_UPDATE_USER_CONTEXT",
  176. "ID_RESERVED_3",
  177. "ID_RESERVED_4",
  178. "ID_RESERVED_5",
  179. "ID_RESERVED_6",
  180. "ID_RESERVED_7",
  181. "ID_RESERVED_8",
  182. "ID_RESERVED_9",
  183. "ID_USER_PACKET_ENUM"
  184. };
  185. static const int DEFAULT_UPDATE_FPS = 30;
  186. static const int SERVER_TIMEOUT_TIME = 10000;
  187. Network::Network(Context* context) :
  188. Object(context),
  189. updateFps_(DEFAULT_UPDATE_FPS),
  190. simulatedLatency_(0),
  191. simulatedPacketLoss_(0.0f),
  192. updateInterval_(1.0f / (float)DEFAULT_UPDATE_FPS),
  193. updateAcc_(0.0f),
  194. isServer_(false),
  195. scene_(nullptr),
  196. natPunchServerAddress_(nullptr),
  197. remoteGUID_(nullptr)
  198. {
  199. rakPeer_ = SLNet::RakPeerInterface::GetInstance();
  200. rakPeerClient_ = SLNet::RakPeerInterface::GetInstance();
  201. rakPeer_->SetTimeoutTime(SERVER_TIMEOUT_TIME, SLNet::UNASSIGNED_SYSTEM_ADDRESS);
  202. SetPassword("");
  203. SetDiscoveryBeacon(VariantMap());
  204. natPunchthroughClient_ = new SLNet::NatPunchthroughClient;
  205. natPunchthroughServerClient_ = new SLNet::NatPunchthroughClient;
  206. SetNATServerInfo("127.0.0.1", 61111);
  207. // Register Network library object factories
  208. RegisterNetworkLibrary(context_);
  209. SubscribeToEvent(E_BEGINFRAME, URHO3D_HANDLER(Network, HandleBeginFrame));
  210. SubscribeToEvent(E_RENDERUPDATE, URHO3D_HANDLER(Network, HandleRenderUpdate));
  211. // Blacklist remote events which are not to be allowed to be registered in any case
  212. blacklistedRemoteEvents_.Insert(E_CONSOLECOMMAND);
  213. blacklistedRemoteEvents_.Insert(E_LOGMESSAGE);
  214. blacklistedRemoteEvents_.Insert(E_BEGINFRAME);
  215. blacklistedRemoteEvents_.Insert(E_UPDATE);
  216. blacklistedRemoteEvents_.Insert(E_POSTUPDATE);
  217. blacklistedRemoteEvents_.Insert(E_RENDERUPDATE);
  218. blacklistedRemoteEvents_.Insert(E_ENDFRAME);
  219. blacklistedRemoteEvents_.Insert(E_MOUSEBUTTONDOWN);
  220. blacklistedRemoteEvents_.Insert(E_MOUSEBUTTONUP);
  221. blacklistedRemoteEvents_.Insert(E_MOUSEMOVE);
  222. blacklistedRemoteEvents_.Insert(E_MOUSEWHEEL);
  223. blacklistedRemoteEvents_.Insert(E_KEYDOWN);
  224. blacklistedRemoteEvents_.Insert(E_KEYUP);
  225. blacklistedRemoteEvents_.Insert(E_TEXTINPUT);
  226. blacklistedRemoteEvents_.Insert(E_JOYSTICKCONNECTED);
  227. blacklistedRemoteEvents_.Insert(E_JOYSTICKDISCONNECTED);
  228. blacklistedRemoteEvents_.Insert(E_JOYSTICKBUTTONDOWN);
  229. blacklistedRemoteEvents_.Insert(E_JOYSTICKBUTTONUP);
  230. blacklistedRemoteEvents_.Insert(E_JOYSTICKAXISMOVE);
  231. blacklistedRemoteEvents_.Insert(E_JOYSTICKHATMOVE);
  232. blacklistedRemoteEvents_.Insert(E_TOUCHBEGIN);
  233. blacklistedRemoteEvents_.Insert(E_TOUCHEND);
  234. blacklistedRemoteEvents_.Insert(E_TOUCHMOVE);
  235. blacklistedRemoteEvents_.Insert(E_GESTURERECORDED);
  236. blacklistedRemoteEvents_.Insert(E_GESTUREINPUT);
  237. blacklistedRemoteEvents_.Insert(E_MULTIGESTURE);
  238. blacklistedRemoteEvents_.Insert(E_DROPFILE);
  239. blacklistedRemoteEvents_.Insert(E_INPUTFOCUS);
  240. blacklistedRemoteEvents_.Insert(E_MOUSEVISIBLECHANGED);
  241. blacklistedRemoteEvents_.Insert(E_EXITREQUESTED);
  242. blacklistedRemoteEvents_.Insert(E_SERVERCONNECTED);
  243. blacklistedRemoteEvents_.Insert(E_SERVERDISCONNECTED);
  244. blacklistedRemoteEvents_.Insert(E_CONNECTFAILED);
  245. blacklistedRemoteEvents_.Insert(E_CLIENTCONNECTED);
  246. blacklistedRemoteEvents_.Insert(E_CLIENTDISCONNECTED);
  247. blacklistedRemoteEvents_.Insert(E_CLIENTIDENTITY);
  248. blacklistedRemoteEvents_.Insert(E_CLIENTSCENELOADED);
  249. blacklistedRemoteEvents_.Insert(E_NETWORKMESSAGE);
  250. blacklistedRemoteEvents_.Insert(E_NETWORKUPDATE);
  251. blacklistedRemoteEvents_.Insert(E_NETWORKUPDATESENT);
  252. blacklistedRemoteEvents_.Insert(E_NETWORKSCENELOADFAILED);
  253. }
  254. Network::~Network()
  255. {
  256. rakPeer_->DetachPlugin(natPunchthroughServerClient_);
  257. rakPeerClient_->DetachPlugin(natPunchthroughClient_);
  258. // If server connection exists, disconnect, but do not send an event because we are shutting down
  259. Disconnect(100);
  260. serverConnection_.Reset();
  261. clientConnections_.Clear();
  262. delete natPunchthroughServerClient_;
  263. natPunchthroughServerClient_ = nullptr;
  264. delete natPunchthroughClient_;
  265. natPunchthroughClient_ = nullptr;
  266. delete remoteGUID_;
  267. remoteGUID_ = nullptr;
  268. delete natPunchServerAddress_;
  269. natPunchServerAddress_ = nullptr;
  270. SLNet::RakPeerInterface::DestroyInstance(rakPeer_);
  271. SLNet::RakPeerInterface::DestroyInstance(rakPeerClient_);
  272. rakPeer_ = nullptr;
  273. rakPeerClient_ = nullptr;
  274. }
  275. void Network::HandleMessage(const SLNet::AddressOrGUID& source, int packetID, int msgID, const char* data, size_t numBytes)
  276. {
  277. // Only process messages from known sources
  278. Connection* connection = GetConnection(source);
  279. if (connection)
  280. {
  281. MemoryBuffer msg(data, (unsigned)numBytes);
  282. if (connection->ProcessMessage((int)msgID, msg))
  283. return;
  284. // If message was not handled internally, forward as an event
  285. using namespace NetworkMessage;
  286. VariantMap& eventData = GetEventDataMap();
  287. eventData[P_CONNECTION] = connection;
  288. eventData[P_MESSAGEID] = (int)msgID;
  289. eventData[P_DATA].SetBuffer(msg.GetData(), msg.GetSize());
  290. connection->SendEvent(E_NETWORKMESSAGE, eventData);
  291. }
  292. else
  293. URHO3D_LOGWARNING("Discarding message from unknown MessageConnection " + String(source.ToString()));
  294. }
  295. void Network::NewConnectionEstablished(const SLNet::AddressOrGUID& connection)
  296. {
  297. // Create a new client connection corresponding to this MessageConnection
  298. SharedPtr<Connection> newConnection(new Connection(context_, true, connection, rakPeer_));
  299. newConnection->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
  300. clientConnections_[connection] = newConnection;
  301. URHO3D_LOGINFO("Client " + newConnection->ToString() + " connected");
  302. using namespace ClientConnected;
  303. VariantMap& eventData = GetEventDataMap();
  304. eventData[P_CONNECTION] = newConnection;
  305. newConnection->SendEvent(E_CLIENTCONNECTED, eventData);
  306. }
  307. void Network::ClientDisconnected(const SLNet::AddressOrGUID& connection)
  308. {
  309. // Remove the client connection that corresponds to this MessageConnection
  310. HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Find(connection);
  311. if (i != clientConnections_.End())
  312. {
  313. Connection* connection = i->second_;
  314. URHO3D_LOGINFO("Client " + connection->ToString() + " disconnected");
  315. using namespace ClientDisconnected;
  316. VariantMap& eventData = GetEventDataMap();
  317. eventData[P_CONNECTION] = connection;
  318. connection->SendEvent(E_CLIENTDISCONNECTED, eventData);
  319. clientConnections_.Erase(i);
  320. }
  321. }
  322. void Network::SetDiscoveryBeacon(const VariantMap& data)
  323. {
  324. VectorBuffer buffer;
  325. buffer.WriteVariantMap(data);
  326. if (buffer.GetSize() > 400)
  327. URHO3D_LOGERROR("Discovery beacon of size: " + String(buffer.GetSize()) + " bytes is too large, modify MAX_OFFLINE_DATA_LENGTH in RakNet or reduce size");
  328. rakPeer_->SetOfflinePingResponse((const char*)buffer.GetData(), buffer.GetSize());
  329. }
  330. void Network::DiscoverHosts(unsigned port)
  331. {
  332. // JSandusky: Contrary to the manual, we actually do have to perform Startup first before we can Ping
  333. if (!rakPeerClient_->IsActive())
  334. {
  335. SLNet::SocketDescriptor socket;
  336. // Startup local connection with max 1 incoming connection(first param) and 1 socket description (third param)
  337. rakPeerClient_->Startup(1, &socket, 1);
  338. }
  339. rakPeerClient_->Ping("255.255.255.255", port, false);
  340. }
  341. void Network::SetPassword(const String& password)
  342. {
  343. rakPeer_->SetIncomingPassword(password.CString(), password.Length());
  344. password_ = password;
  345. }
  346. bool Network::Connect(const String& address, unsigned short port, Scene* scene, const VariantMap& identity)
  347. {
  348. URHO3D_PROFILE(Connect);
  349. if (!rakPeerClient_->IsActive())
  350. {
  351. URHO3D_LOGINFO("Initializing client connection...");
  352. SLNet::SocketDescriptor socket;
  353. // Startup local connection with max 2 incoming connections(first param) and 1 socket description (third param)
  354. rakPeerClient_->Startup(2, &socket, 1);
  355. }
  356. //isServer_ = false;
  357. SLNet::ConnectionAttemptResult connectResult = rakPeerClient_->Connect(address.CString(), port, password_.CString(), password_.Length());
  358. if (connectResult == SLNet::CONNECTION_ATTEMPT_STARTED)
  359. {
  360. serverConnection_ = new Connection(context_, false, rakPeerClient_->GetMyBoundAddress(), rakPeerClient_);
  361. serverConnection_->SetScene(scene);
  362. serverConnection_->SetIdentity(identity);
  363. serverConnection_->SetConnectPending(true);
  364. serverConnection_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
  365. URHO3D_LOGINFO("Connecting to server " + address + ":" + String(port) + ", Client: " + serverConnection_->ToString());
  366. return true;
  367. }
  368. else if (connectResult == SLNet::ALREADY_CONNECTED_TO_ENDPOINT) {
  369. URHO3D_LOGWARNING("Already connected to server!");
  370. SendEvent(E_CONNECTIONINPROGRESS);
  371. return false;
  372. }
  373. else if (connectResult == SLNet::CONNECTION_ATTEMPT_ALREADY_IN_PROGRESS) {
  374. URHO3D_LOGWARNING("Connection attempt already in progress!");
  375. SendEvent(E_CONNECTIONINPROGRESS);
  376. return false;
  377. }
  378. else
  379. {
  380. URHO3D_LOGERROR("Failed to connect to server " + address + ":" + String(port) + ", error code: " + String((int)connectResult));
  381. SendEvent(E_CONNECTFAILED);
  382. return false;
  383. }
  384. }
  385. void Network::Disconnect(int waitMSec)
  386. {
  387. if (!serverConnection_)
  388. return;
  389. URHO3D_PROFILE(Disconnect);
  390. serverConnection_->Disconnect(waitMSec);
  391. }
  392. bool Network::StartServer(unsigned short port, unsigned int maxConnections)
  393. {
  394. if (IsServerRunning())
  395. return true;
  396. URHO3D_PROFILE(StartServer);
  397. SLNet::SocketDescriptor socket;//(port, AF_INET);
  398. socket.port = port;
  399. socket.socketFamily = AF_INET;
  400. // Startup local connection with max 128 incoming connection(first param) and 1 socket description (third param)
  401. SLNet::StartupResult startResult = rakPeer_->Startup(maxConnections, &socket, 1);
  402. if (startResult == SLNet::RAKNET_STARTED)
  403. {
  404. URHO3D_LOGINFO("Started server on port " + String(port));
  405. rakPeer_->SetMaximumIncomingConnections(maxConnections);
  406. isServer_ = true;
  407. rakPeer_->SetOccasionalPing(true);
  408. rakPeer_->SetUnreliableTimeout(1000);
  409. //rakPeer_->SetIncomingPassword("Parole", (int)strlen("Parole"));
  410. return true;
  411. }
  412. else
  413. {
  414. URHO3D_LOGINFO("Failed to start server on port " + String(port) + ", error code: " + String((int)startResult));
  415. return false;
  416. }
  417. }
  418. void Network::StopServer()
  419. {
  420. clientConnections_.Clear();
  421. if (!rakPeer_)
  422. return;
  423. if (!IsServerRunning())
  424. return;
  425. // Provide 300 ms to notify
  426. rakPeer_->Shutdown(300);
  427. URHO3D_PROFILE(StopServer);
  428. URHO3D_LOGINFO("Stopped server");
  429. }
  430. void Network::SetNATServerInfo(const String& address, unsigned short port)
  431. {
  432. if (!natPunchServerAddress_)
  433. natPunchServerAddress_ = new SLNet::SystemAddress;
  434. natPunchServerAddress_->FromStringExplicitPort(address.CString(), port);
  435. }
  436. void Network::StartNATClient()
  437. {
  438. if (!rakPeer_) {
  439. URHO3D_LOGERROR("Unable to start NAT client, client not initialized!");
  440. return;
  441. }
  442. if (natPunchServerAddress_->GetPort() == 0) {
  443. URHO3D_LOGERROR("NAT master server address incorrect!");
  444. return;
  445. }
  446. rakPeer_->AttachPlugin(natPunchthroughServerClient_);
  447. guid_ = String(rakPeer_->GetGuidFromSystemAddress(SLNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
  448. URHO3D_LOGINFO("GUID: " + guid_);
  449. rakPeer_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
  450. }
  451. void Network::AttemptNATPunchtrough(const String& guid, Scene* scene, const VariantMap& identity)
  452. {
  453. scene_ = scene;
  454. identity_ = identity;
  455. if (!remoteGUID_)
  456. remoteGUID_ = new SLNet::RakNetGUID;
  457. remoteGUID_->FromString(guid.CString());
  458. rakPeerClient_->AttachPlugin(natPunchthroughClient_);
  459. if (rakPeerClient_->IsActive()) {
  460. natPunchthroughClient_->OpenNAT(*remoteGUID_, *natPunchServerAddress_);
  461. }
  462. else {
  463. SLNet::SocketDescriptor socket;
  464. // Startup local connection with max 2 incoming connections(first param) and 1 socket description (third param)
  465. rakPeerClient_->Startup(2, &socket, 1);
  466. }
  467. rakPeerClient_->Connect(natPunchServerAddress_->ToString(false), natPunchServerAddress_->GetPort(), nullptr, 0);
  468. }
  469. void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const VectorBuffer& msg, unsigned contentID)
  470. {
  471. BroadcastMessage(msgID, reliable, inOrder, msg.GetData(), msg.GetSize(), contentID);
  472. }
  473. void Network::BroadcastMessage(int msgID, bool reliable, bool inOrder, const unsigned char* data, unsigned numBytes,
  474. unsigned contentID)
  475. {
  476. if (!rakPeer_)
  477. return;
  478. VectorBuffer msgData;
  479. msgData.WriteUByte((unsigned char)ID_USER_PACKET_ENUM);
  480. msgData.WriteUInt((unsigned int)msgID);
  481. msgData.Write(data, numBytes);
  482. if (isServer_)
  483. rakPeer_->Send((const char*)msgData.GetData(), (int)msgData.GetSize(), HIGH_PRIORITY, RELIABLE, (char)0, SLNet::UNASSIGNED_RAKNET_GUID, true);
  484. else
  485. URHO3D_LOGERROR("Server not running, can not broadcast messages");
  486. }
  487. void Network::BroadcastRemoteEvent(StringHash eventType, bool inOrder, const VariantMap& eventData)
  488. {
  489. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin(); i != clientConnections_.End(); ++i)
  490. i->second_->SendRemoteEvent(eventType, inOrder, eventData);
  491. }
  492. void Network::BroadcastRemoteEvent(Scene* scene, StringHash eventType, bool inOrder, const VariantMap& eventData)
  493. {
  494. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
  495. i != clientConnections_.End(); ++i)
  496. {
  497. if (i->second_->GetScene() == scene)
  498. i->second_->SendRemoteEvent(eventType, inOrder, eventData);
  499. }
  500. }
  501. void Network::BroadcastRemoteEvent(Node* node, StringHash eventType, bool inOrder, const VariantMap& eventData)
  502. {
  503. if (!node)
  504. {
  505. URHO3D_LOGERROR("Null sender node for remote node event");
  506. return;
  507. }
  508. if (!node->IsReplicated())
  509. {
  510. URHO3D_LOGERROR("Sender node has a local ID, can not send remote node event");
  511. return;
  512. }
  513. Scene* scene = node->GetScene();
  514. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
  515. i != clientConnections_.End(); ++i)
  516. {
  517. if (i->second_->GetScene() == scene)
  518. i->second_->SendRemoteEvent(node, eventType, inOrder, eventData);
  519. }
  520. }
  521. void Network::SetUpdateFps(int fps)
  522. {
  523. updateFps_ = Max(fps, 1);
  524. updateInterval_ = 1.0f / (float)updateFps_;
  525. updateAcc_ = 0.0f;
  526. }
  527. void Network::SetSimulatedLatency(int ms)
  528. {
  529. simulatedLatency_ = Max(ms, 0);
  530. ConfigureNetworkSimulator();
  531. }
  532. void Network::SetSimulatedPacketLoss(float probability)
  533. {
  534. simulatedPacketLoss_ = Clamp(probability, 0.0f, 1.0f);
  535. ConfigureNetworkSimulator();
  536. }
  537. void Network::RegisterRemoteEvent(StringHash eventType)
  538. {
  539. if (blacklistedRemoteEvents_.Find(eventType) != blacklistedRemoteEvents_.End())
  540. {
  541. URHO3D_LOGERROR("Attempted to register blacklisted remote event type " + String(eventType));
  542. return;
  543. }
  544. allowedRemoteEvents_.Insert(eventType);
  545. }
  546. void Network::UnregisterRemoteEvent(StringHash eventType)
  547. {
  548. allowedRemoteEvents_.Erase(eventType);
  549. }
  550. void Network::UnregisterAllRemoteEvents()
  551. {
  552. allowedRemoteEvents_.Clear();
  553. }
  554. void Network::SetPackageCacheDir(const String& path)
  555. {
  556. packageCacheDir_ = AddTrailingSlash(path);
  557. }
  558. void Network::SendPackageToClients(Scene* scene, PackageFile* package)
  559. {
  560. if (!scene)
  561. {
  562. URHO3D_LOGERROR("Null scene specified for SendPackageToClients");
  563. return;
  564. }
  565. if (!package)
  566. {
  567. URHO3D_LOGERROR("Null package specified for SendPackageToClients");
  568. return;
  569. }
  570. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
  571. i != clientConnections_.End(); ++i)
  572. {
  573. if (i->second_->GetScene() == scene)
  574. i->second_->SendPackageToClient(package);
  575. }
  576. }
  577. SharedPtr<HttpRequest> Network::MakeHttpRequest(const String& url, const String& verb, const Vector<String>& headers,
  578. const String& postData)
  579. {
  580. URHO3D_PROFILE(MakeHttpRequest);
  581. // The initialization of the request will take time, can not know at this point if it has an error or not
  582. SharedPtr<HttpRequest> request(new HttpRequest(url, verb, headers, postData));
  583. return request;
  584. }
  585. void Network::BanAddress(const String& address)
  586. {
  587. rakPeer_->AddToBanList(address.CString(), 0);
  588. }
  589. Connection* Network::GetConnection(const SLNet::AddressOrGUID& connection) const
  590. {
  591. if (serverConnection_ && serverConnection_->GetAddressOrGUID() == connection)
  592. return serverConnection_;
  593. else
  594. {
  595. HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::ConstIterator i = clientConnections_.Find(connection);
  596. if (i != clientConnections_.End())
  597. return i->second_;
  598. else
  599. return nullptr;
  600. }
  601. }
  602. Connection* Network::GetServerConnection() const
  603. {
  604. return serverConnection_;
  605. }
  606. Vector<SharedPtr<Connection> > Network::GetClientConnections() const
  607. {
  608. Vector<SharedPtr<Connection> > ret;
  609. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::ConstIterator i = clientConnections_.Begin();
  610. i != clientConnections_.End(); ++i)
  611. ret.Push(i->second_);
  612. return ret;
  613. }
  614. bool Network::IsServerRunning() const
  615. {
  616. if (!rakPeer_)
  617. return false;
  618. return rakPeer_->IsActive() && isServer_;
  619. }
  620. bool Network::CheckRemoteEvent(StringHash eventType) const
  621. {
  622. return allowedRemoteEvents_.Contains(eventType);
  623. }
  624. void Network::HandleIncomingPacket(SLNet::Packet* packet, bool isServer)
  625. {
  626. unsigned char packetID = packet->data[0];
  627. bool packetHandled = false;
  628. // Deal with timestamped backents
  629. unsigned dataStart = sizeof(char);
  630. if (packetID == ID_TIMESTAMP)
  631. {
  632. dataStart += sizeof(SLNet::Time);
  633. packetID = packet->data[dataStart];
  634. dataStart += sizeof(char);
  635. }
  636. if (packetID == ID_NEW_INCOMING_CONNECTION)
  637. {
  638. if (isServer)
  639. {
  640. NewConnectionEstablished(packet->systemAddress);
  641. packetHandled = true;
  642. }
  643. }
  644. else if (packetID == ID_ALREADY_CONNECTED)
  645. {
  646. if (natPunchServerAddress_ && packet->systemAddress == *natPunchServerAddress_) {
  647. URHO3D_LOGINFO("Already connected to NAT server! ");
  648. if (!isServer)
  649. {
  650. natPunchthroughClient_->OpenNAT(*remoteGUID_, *natPunchServerAddress_);
  651. }
  652. }
  653. packetHandled = true;
  654. }
  655. else if (packetID == ID_CONNECTION_REQUEST_ACCEPTED) // We're a client, our connection as been accepted
  656. {
  657. if(natPunchServerAddress_ && packet->systemAddress == *natPunchServerAddress_) {
  658. URHO3D_LOGINFO("Succesfully connected to NAT punchtrough server! ");
  659. SendEvent(E_NATMASTERCONNECTIONSUCCEEDED);
  660. if (!isServer)
  661. {
  662. natPunchthroughClient_->OpenNAT(*remoteGUID_, *natPunchServerAddress_);
  663. }
  664. } else {
  665. if (!isServer)
  666. {
  667. OnServerConnected(packet->systemAddress);
  668. }
  669. }
  670. packetHandled = true;
  671. }
  672. else if (packetID == ID_NAT_TARGET_NOT_CONNECTED)
  673. {
  674. URHO3D_LOGERROR("Target server not connected to NAT master server!");
  675. packetHandled = true;
  676. }
  677. else if (packetID == ID_CONNECTION_LOST) // We've lost connectivity with the packet source
  678. {
  679. if (isServer)
  680. {
  681. ClientDisconnected(packet->systemAddress);
  682. }
  683. else
  684. {
  685. OnServerDisconnected(packet->systemAddress);
  686. }
  687. packetHandled = true;
  688. }
  689. else if (packetID == ID_DISCONNECTION_NOTIFICATION) // We've lost connection with the other side
  690. {
  691. if (isServer)
  692. {
  693. ClientDisconnected(packet->systemAddress);
  694. }
  695. else
  696. {
  697. OnServerDisconnected(packet->systemAddress);
  698. }
  699. packetHandled = true;
  700. }
  701. else if (packetID == ID_CONNECTION_ATTEMPT_FAILED) // We've failed to connect to the server/peer
  702. {
  703. if (natPunchServerAddress_ && packet->systemAddress == *natPunchServerAddress_) {
  704. URHO3D_LOGERROR("Connection to NAT punchtrough server failed!");
  705. SendEvent(E_NATMASTERCONNECTIONFAILED);
  706. } else {
  707. if (!isServer)
  708. {
  709. OnServerDisconnected(packet->systemAddress);
  710. }
  711. }
  712. packetHandled = true;
  713. }
  714. else if (packetID == ID_NAT_PUNCHTHROUGH_SUCCEEDED)
  715. {
  716. SLNet::SystemAddress remotePeer = packet->systemAddress;
  717. URHO3D_LOGINFO("NAT punchtrough succeeded! Remote peer: " + String(remotePeer.ToString()));
  718. if (!isServer)
  719. {
  720. using namespace NetworkNatPunchtroughSucceeded;
  721. VariantMap eventMap;
  722. eventMap[P_ADDRESS] = remotePeer.ToString(false);
  723. eventMap[P_PORT] = remotePeer.GetPort();
  724. SendEvent(E_NETWORKNATPUNCHTROUGHSUCCEEDED, eventMap);
  725. URHO3D_LOGINFO("Connecting to server behind NAT: " + String(remotePeer.ToString()));
  726. Connect(String(remotePeer.ToString(false)), remotePeer.GetPort(), scene_, identity_);
  727. }
  728. packetHandled = true;
  729. }
  730. else if (packetID == ID_NAT_PUNCHTHROUGH_FAILED)
  731. {
  732. URHO3D_LOGERROR("NAT punchtrough failed!");
  733. SLNet::SystemAddress remotePeer = packet->systemAddress;
  734. using namespace NetworkNatPunchtroughFailed;
  735. VariantMap eventMap;
  736. eventMap[P_ADDRESS] = remotePeer.ToString(false);
  737. eventMap[P_PORT] = remotePeer.GetPort();
  738. SendEvent(E_NETWORKNATPUNCHTROUGHFAILED, eventMap);
  739. packetHandled = true;
  740. }
  741. else if (packetID == ID_CONNECTION_BANNED) // We're a client and we're on the ban list
  742. {
  743. URHO3D_LOGERROR("Connection failed, you're banned!");
  744. SendEvent(E_NETWORKBANNED);
  745. packetHandled = true;
  746. }
  747. else if (packetID == ID_INVALID_PASSWORD) // We're a client, and we gave an invalid password
  748. {
  749. URHO3D_LOGERROR("Invalid password provided for connection!");
  750. SendEvent(E_NETWORKINVALIDPASSWORD);
  751. packetHandled = true;
  752. }
  753. else if (packetID == ID_DOWNLOAD_PROGRESS) // Part of a file transfer
  754. {
  755. //URHO3D_LOGINFO("101010");
  756. }
  757. else if (packetID == ID_UNCONNECTED_PING)
  758. {
  759. packetHandled = true;
  760. }
  761. else if (packetID == ID_UNCONNECTED_PONG) // Host discovery response
  762. {
  763. if (!isServer)
  764. {
  765. using namespace NetworkHostDiscovered;
  766. dataStart += sizeof(SLNet::TimeMS);
  767. VariantMap& eventMap = context_->GetEventDataMap();
  768. if (packet->length > packet->length - dataStart) {
  769. VectorBuffer buffer(packet->data + dataStart, packet->length - dataStart);
  770. VariantMap srcData = buffer.ReadVariantMap();
  771. eventMap[P_BEACON] = srcData;
  772. }
  773. else {
  774. eventMap[P_BEACON] = VariantMap();
  775. }
  776. eventMap[P_ADDRESS] = String(packet->systemAddress.ToString(false));
  777. eventMap[P_PORT] = (int)packet->systemAddress.GetPort();
  778. SendEvent(E_NETWORKHOSTDISCOVERED, eventMap);
  779. }
  780. packetHandled = true;
  781. }
  782. // Urho3D messages
  783. if (packetID >= ID_USER_PACKET_ENUM)
  784. {
  785. unsigned int messageID = *(unsigned int*)(packet->data + dataStart);
  786. dataStart += sizeof(unsigned int);
  787. if (isServer)
  788. {
  789. HandleMessage(packet->systemAddress, 0, messageID, (const char*)(packet->data + dataStart), packet->length - dataStart);
  790. }
  791. else
  792. {
  793. MemoryBuffer buffer(packet->data + dataStart, packet->length - dataStart);
  794. bool processed = serverConnection_->ProcessMessage(messageID, buffer);
  795. if (!processed)
  796. {
  797. HandleMessage(packet->systemAddress, 0, messageID, (const char*)(packet->data + dataStart), packet->length - dataStart);
  798. }
  799. }
  800. packetHandled = true;
  801. }
  802. if (!packetHandled && packetID < sizeof(RAKNET_MESSAGEID_STRINGS))
  803. URHO3D_LOGERROR("Unhandled network packet: " + String(RAKNET_MESSAGEID_STRINGS[packetID]));
  804. else if (!packetHandled)
  805. URHO3D_LOGERRORF("Unhandled network packet: %i", packetID);
  806. }
  807. void Network::Update(float timeStep)
  808. {
  809. URHO3D_PROFILE(UpdateNetwork);
  810. //Process all incoming messages for the server
  811. if (rakPeer_->IsActive())
  812. {
  813. while (SLNet::Packet* packet = rakPeer_->Receive())
  814. {
  815. HandleIncomingPacket(packet, true);
  816. rakPeer_->DeallocatePacket(packet);
  817. }
  818. }
  819. // Process all incoming messages for the client
  820. if (rakPeerClient_->IsActive())
  821. {
  822. while (SLNet::Packet* packet = rakPeerClient_->Receive())
  823. {
  824. HandleIncomingPacket(packet, false);
  825. rakPeerClient_->DeallocatePacket(packet);
  826. }
  827. }
  828. }
  829. void Network::PostUpdate(float timeStep)
  830. {
  831. URHO3D_PROFILE(PostUpdateNetwork);
  832. // Check if periodic update should happen now
  833. updateAcc_ += timeStep;
  834. bool updateNow = updateAcc_ >= updateInterval_;
  835. if (updateNow)
  836. {
  837. // Notify of the impending update to allow for example updated client controls to be set
  838. SendEvent(E_NETWORKUPDATE);
  839. updateAcc_ = fmodf(updateAcc_, updateInterval_);
  840. if (IsServerRunning())
  841. {
  842. // Collect and prepare all networked scenes
  843. {
  844. URHO3D_PROFILE(PrepareServerUpdate);
  845. networkScenes_.Clear();
  846. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
  847. i != clientConnections_.End(); ++i)
  848. {
  849. Scene* scene = i->second_->GetScene();
  850. if (scene)
  851. networkScenes_.Insert(scene);
  852. }
  853. for (HashSet<Scene*>::ConstIterator i = networkScenes_.Begin(); i != networkScenes_.End(); ++i)
  854. (*i)->PrepareNetworkUpdate();
  855. }
  856. {
  857. URHO3D_PROFILE(SendServerUpdate);
  858. // Then send server updates for each client connection
  859. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
  860. i != clientConnections_.End(); ++i)
  861. {
  862. i->second_->SendServerUpdate();
  863. i->second_->SendRemoteEvents();
  864. i->second_->SendPackages();
  865. }
  866. }
  867. }
  868. if (serverConnection_)
  869. {
  870. // Send the client update
  871. serverConnection_->SendClientUpdate();
  872. serverConnection_->SendRemoteEvents();
  873. }
  874. // Notify that the update was sent
  875. SendEvent(E_NETWORKUPDATESENT);
  876. }
  877. }
  878. void Network::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
  879. {
  880. using namespace BeginFrame;
  881. Update(eventData[P_TIMESTEP].GetFloat());
  882. }
  883. void Network::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
  884. {
  885. using namespace RenderUpdate;
  886. PostUpdate(eventData[P_TIMESTEP].GetFloat());
  887. }
  888. void Network::OnServerConnected(const SLNet::AddressOrGUID& address)
  889. {
  890. serverConnection_->SetConnectPending(false);
  891. serverConnection_->SetAddressOrGUID(address);
  892. URHO3D_LOGINFO("Connected to server!");
  893. // Send the identity map now
  894. VectorBuffer msg;
  895. msg.WriteVariantMap(serverConnection_->GetIdentity());
  896. serverConnection_->SendMessage(MSG_IDENTITY, true, true, msg);
  897. SendEvent(E_SERVERCONNECTED);
  898. }
  899. void Network::OnServerDisconnected(const SLNet::AddressOrGUID& address)
  900. {
  901. if (natPunchServerAddress_ && *natPunchServerAddress_ == address.systemAddress) {
  902. SendEvent(E_NATMASTERDISCONNECTED);
  903. return;
  904. }
  905. // Differentiate between failed connection, and disconnection
  906. bool failedConnect = serverConnection_ && serverConnection_->IsConnectPending();
  907. serverConnection_.Reset();
  908. if (!failedConnect)
  909. {
  910. URHO3D_LOGINFO("Disconnected from server");
  911. SendEvent(E_SERVERDISCONNECTED);
  912. }
  913. else
  914. {
  915. URHO3D_LOGERROR("Failed to connect to server");
  916. SendEvent(E_CONNECTFAILED);
  917. }
  918. }
  919. void Network::ConfigureNetworkSimulator()
  920. {
  921. if (serverConnection_)
  922. serverConnection_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
  923. for (HashMap<SLNet::AddressOrGUID, SharedPtr<Connection> >::Iterator i = clientConnections_.Begin();
  924. i != clientConnections_.End(); ++i)
  925. i->second_->ConfigureNetworkSimulator(simulatedLatency_, simulatedPacketLoss_);
  926. }
  927. void RegisterNetworkLibrary(Context* context)
  928. {
  929. NetworkPriority::RegisterObject(context);
  930. }
  931. }