Connection.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Component.h"
  25. #include "Connection.h"
  26. #include "File.h"
  27. #include "FileSystem.h"
  28. #include "Log.h"
  29. #include "MemoryBuffer.h"
  30. #include "Network.h"
  31. #include "NetworkEvents.h"
  32. #include "NetworkPriority.h"
  33. #include "PackageFile.h"
  34. #include "Profiler.h"
  35. #include "Protocol.h"
  36. #include "ResourceCache.h"
  37. #include "Scene.h"
  38. #include "SceneEvents.h"
  39. #include "StringUtils.h"
  40. #include <kNet.h>
  41. #include "DebugNew.h"
  42. static const int STATS_INTERVAL_MSEC = 2000;
  43. static const String noName;
  44. PackageDownload::PackageDownload() :
  45. totalFragments_(0),
  46. checksum_(0),
  47. initiated_(false)
  48. {
  49. }
  50. PackageUpload::PackageUpload()
  51. {
  52. }
  53. OBJECTTYPESTATIC(Connection);
  54. Connection::Connection(Context* context, bool isClient, kNet::SharedPtr<kNet::MessageConnection> connection) :
  55. Object(context),
  56. connection_(connection),
  57. position_(Vector3::ZERO),
  58. frameNumber_(0),
  59. isClient_(isClient),
  60. connectPending_(false),
  61. sceneLoaded_(false),
  62. logStatistics_(false)
  63. {
  64. }
  65. Connection::~Connection()
  66. {
  67. // Reset scene (remove possible owner references), as this connection is about to be destroyed
  68. SetScene(0);
  69. }
  70. void Connection::SendMessage(int msgID, bool reliable, bool inOrder, const VectorBuffer& msg, unsigned priority, unsigned contentID)
  71. {
  72. SendMessage(msgID, reliable, inOrder, msg.GetData(), msg.GetSize(), priority, contentID);
  73. }
  74. void Connection::SendMessage(int msgID, bool reliable, bool inOrder, const unsigned char* data, unsigned numBytes,
  75. unsigned priority, unsigned contentID)
  76. {
  77. // Make sure not to use kNet internal message ID's
  78. if (msgID <= 0x4 || msgID >= 0x3ffffffe)
  79. {
  80. LOGERROR("Can not send message with reserved ID");
  81. return;
  82. }
  83. connection_->SendMessage(msgID, reliable, inOrder, priority, contentID, (const char*)data, numBytes);
  84. }
  85. void Connection::SendRemoteEvent(StringHash eventType, bool inOrder, const VariantMap& eventData)
  86. {
  87. if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
  88. {
  89. LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
  90. return;
  91. }
  92. RemoteEvent queuedEvent;
  93. queuedEvent.receiverID_ = 0;
  94. queuedEvent.eventType_ = eventType;
  95. queuedEvent.eventData_ = eventData;
  96. queuedEvent.inOrder_ = inOrder;
  97. remoteEvents_.Push(queuedEvent);
  98. }
  99. void Connection::SendRemoteEvent(Node* receiver, StringHash eventType, bool inOrder, const VariantMap& eventData)
  100. {
  101. if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
  102. {
  103. LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
  104. return;
  105. }
  106. if (!receiver)
  107. {
  108. LOGERROR("Null node for remote node event");
  109. return;
  110. }
  111. if (receiver->GetScene() != scene_)
  112. {
  113. LOGERROR("Node is not in the connection's scene, can not send remote node event");
  114. return;
  115. }
  116. if (receiver->GetID() >= FIRST_LOCAL_ID)
  117. {
  118. LOGERROR("Node has a local ID, can not send remote node event");
  119. return;
  120. }
  121. RemoteEvent queuedEvent;
  122. queuedEvent.receiverID_ = receiver->GetID();
  123. queuedEvent.eventType_ = eventType;
  124. queuedEvent.eventData_ = eventData;
  125. queuedEvent.inOrder_ = inOrder;
  126. remoteEvents_.Push(queuedEvent);
  127. }
  128. void Connection::SetScene(Scene* newScene)
  129. {
  130. if (scene_)
  131. {
  132. // Disable smoothing in case scene is no longer used for networking
  133. if (!isClient_)
  134. scene_->SetSmoothed(false);
  135. // Reset the owner reference from the previous scene's nodes
  136. scene_->ResetOwner(this);
  137. }
  138. scene_ = newScene;
  139. sceneLoaded_ = false;
  140. UnsubscribeFromEvent(E_ASYNCLOADFINISHED);
  141. if (!scene_)
  142. return;
  143. if (isClient_)
  144. {
  145. sceneState_.Clear();
  146. // When scene is assigned on the server, instruct the client to load it. This may require downloading packages
  147. const Vector<SharedPtr<PackageFile> >& packages = scene_->GetRequiredPackageFiles();
  148. unsigned numPackages = packages.Size();
  149. msg_.Clear();
  150. msg_.WriteString(scene_->GetFileName());
  151. msg_.WriteVLE(numPackages);
  152. for (unsigned i = 0; i < numPackages; ++i)
  153. {
  154. PackageFile* package = packages[i];
  155. msg_.WriteString(GetFileNameAndExtension(package->GetName()));
  156. msg_.WriteUInt(package->GetTotalSize());
  157. msg_.WriteUInt(package->GetChecksum());
  158. }
  159. SendMessage(MSG_LOADSCENE, true, true, msg_, NET_HIGH_PRIORITY);
  160. }
  161. else
  162. {
  163. // Enable motion smoothing on the client network scene
  164. scene_->SetSmoothed(true);
  165. // Make sure there is no existing async loading
  166. scene_->StopAsyncLoading();
  167. SubscribeToEvent(scene_, E_ASYNCLOADFINISHED, HANDLER(Connection, HandleAsyncLoadFinished));
  168. }
  169. }
  170. void Connection::SetIdentity(const VariantMap& identity)
  171. {
  172. identity_ = identity;
  173. }
  174. void Connection::SetControls(const Controls& newControls)
  175. {
  176. controls_ = newControls;
  177. }
  178. void Connection::SetPosition(const Vector3& position)
  179. {
  180. position_ = position;
  181. }
  182. void Connection::SetConnectPending(bool connectPending)
  183. {
  184. connectPending_ = connectPending;
  185. }
  186. void Connection::SetLogStatistics(bool enable)
  187. {
  188. logStatistics_ = enable;
  189. }
  190. void Connection::Disconnect(int waitMSec)
  191. {
  192. connection_->Disconnect(waitMSec);
  193. }
  194. void Connection::SendServerUpdate()
  195. {
  196. if (!scene_ || !sceneLoaded_)
  197. return;
  198. PROFILE(SendServerUpdate);
  199. const Map<unsigned, Node*>& nodes = scene_->GetAllNodes();
  200. // Check for new or changed nodes
  201. // Start from the root node (scene) so that the scene-wide components get sent first
  202. processedNodes_.Clear();
  203. ProcessNode(scene_);
  204. // Then go through the rest of the nodes
  205. for (Map<unsigned, Node*>::ConstIterator i = nodes.Begin(); i != nodes.End() && i->first_ < FIRST_LOCAL_ID; ++i)
  206. ProcessNode(i->second_);
  207. // Check for removed nodes
  208. for (Map<unsigned, NodeReplicationState>::Iterator i = sceneState_.Begin(); i != sceneState_.End();)
  209. {
  210. Map<unsigned, NodeReplicationState>::Iterator current = i++;
  211. if (current->second_.frameNumber_ != frameNumber_)
  212. {
  213. msg_.Clear();
  214. msg_.WriteNetID(current->first_);
  215. // Note: we will send MSG_REMOVENODE redundantly for each node in the hierarchy, even if removing the root node
  216. // would be enough. However, this may be better due to the client not possibly having updated parenting information
  217. // at the time of receiving this message
  218. SendMessage(MSG_REMOVENODE, true, true, msg_, NET_HIGH_PRIORITY);
  219. sceneState_.Erase(current);
  220. }
  221. }
  222. ++frameNumber_;
  223. }
  224. void Connection::SendClientUpdate()
  225. {
  226. if (!scene_ || !sceneLoaded_)
  227. return;
  228. msg_.Clear();
  229. msg_.WriteUInt(controls_.buttons_);
  230. msg_.WriteFloat(controls_.yaw_);
  231. msg_.WriteFloat(controls_.pitch_);
  232. msg_.WriteVariantMap(controls_.extraData_);
  233. msg_.WriteVector3(position_);
  234. SendMessage(MSG_CONTROLS, false, false, msg_, NET_HIGH_PRIORITY, CONTROLS_CONTENT_ID);
  235. }
  236. void Connection::SendRemoteEvents()
  237. {
  238. if (logStatistics_ && statsTimer_.GetMSec(false) > STATS_INTERVAL_MSEC)
  239. {
  240. statsTimer_.Reset();
  241. char statsBuffer[256];
  242. sprintf(statsBuffer, "RTT %.3f ms Pkt in %d Pkt out %d Data in %.3f KB/s Data out %.3f KB/s", connection_->RoundTripTime(), (int)connection_->PacketsInPerSec(),
  243. (int)connection_->PacketsOutPerSec(), connection_->BytesInPerSec() / 1000.0f, connection_->BytesOutPerSec() / 1000.0f);
  244. LOGINFO(statsBuffer);
  245. }
  246. if (remoteEvents_.Empty())
  247. return;
  248. PROFILE(SendRemoteEvents);
  249. for (Vector<RemoteEvent>::ConstIterator i = remoteEvents_.Begin(); i != remoteEvents_.End(); ++i)
  250. {
  251. msg_.Clear();
  252. if (!i->receiverID_)
  253. {
  254. msg_.WriteStringHash(i->eventType_);
  255. msg_.WriteVariantMap(i->eventData_);
  256. SendMessage(MSG_REMOTEEVENT, true, i->inOrder_, msg_, NET_HIGH_PRIORITY);
  257. }
  258. else
  259. {
  260. msg_.WriteNetID(i->receiverID_);
  261. msg_.WriteStringHash(i->eventType_);
  262. msg_.WriteVariantMap(i->eventData_);
  263. SendMessage(MSG_REMOTENODEEVENT, true, i->inOrder_, msg_, NET_HIGH_PRIORITY);
  264. }
  265. }
  266. remoteEvents_.Clear();
  267. }
  268. void Connection::SendPackages()
  269. {
  270. while (!uploads_.Empty() && connection_->NumOutboundMessagesPending() < 1000)
  271. {
  272. unsigned char buffer[PACKAGE_FRAGMENT_SIZE];
  273. for (Map<StringHash, PackageUpload>::Iterator i = uploads_.Begin(); i != uploads_.End();)
  274. {
  275. Map<StringHash, PackageUpload>::Iterator current = i++;
  276. PackageUpload& upload = current->second_;
  277. unsigned fragmentSize = Min((int)(upload.file_->GetSize() - upload.file_->GetPosition()), (int)PACKAGE_FRAGMENT_SIZE);
  278. upload.file_->Read(buffer, fragmentSize);
  279. msg_.Clear();
  280. msg_.WriteStringHash(current->first_);
  281. msg_.WriteUInt(upload.fragment_++);
  282. msg_.Write(buffer, fragmentSize);
  283. SendMessage(MSG_PACKAGEDATA, true, false, msg_, NET_LOW_PRIORITY);
  284. // Check if upload finished
  285. if (upload.fragment_ == upload.totalFragments_)
  286. uploads_.Erase(current);
  287. }
  288. }
  289. }
  290. void Connection::ProcessPendingLatestData()
  291. {
  292. if (!scene_ || !sceneLoaded_)
  293. return;
  294. // Iterate through pending node data and see if we can find the nodes now
  295. for (HashMap<unsigned, PODVector<unsigned char> >::Iterator i = nodeLatestData_.Begin(); i != nodeLatestData_.End();)
  296. {
  297. HashMap<unsigned, PODVector<unsigned char> >::Iterator current = i++;
  298. Node* node = scene_->GetNode(current->first_);
  299. if (node)
  300. {
  301. MemoryBuffer msg(current->second_);
  302. msg.ReadNetID(); // Skip the node ID
  303. node->ReadLatestDataUpdate(msg);
  304. nodeLatestData_.Erase(current);
  305. }
  306. }
  307. // Iterate through pending component data and see if we can find the components now
  308. for (HashMap<unsigned, PODVector<unsigned char> >::Iterator i = componentLatestData_.Begin(); i != componentLatestData_.End();)
  309. {
  310. HashMap<unsigned, PODVector<unsigned char> >::Iterator current = i++;
  311. Component* component = scene_->GetComponent(current->first_);
  312. if (component)
  313. {
  314. MemoryBuffer msg(current->second_);
  315. msg.ReadNetID(); // Skip the component ID
  316. component->ReadLatestDataUpdate(msg);
  317. component->FinishUpdate();
  318. componentLatestData_.Erase(current);
  319. }
  320. }
  321. }
  322. void Connection::ProcessLoadScene(int msgID, MemoryBuffer& msg)
  323. {
  324. if (IsClient())
  325. {
  326. LOGWARNING("Received unexpected LoadScene message from client " + ToString());
  327. return;
  328. }
  329. if (!scene_)
  330. {
  331. LOGERROR("Can not handle LoadScene message without an assigned scene");
  332. return;
  333. }
  334. // Store the scene file name we need to eventually load
  335. sceneFileName_ = msg.ReadString();
  336. // Clear previous scene content, pending latest data, and package downloads if any
  337. scene_->Clear();
  338. nodeLatestData_.Clear();
  339. componentLatestData_.Clear();
  340. downloads_.Clear();
  341. // In case we have joined other scenes in this session, remove first all downloaded package files from the resource system
  342. // to prevent resource conflicts
  343. const String& packageCacheDir = GetSubsystem<Network>()->GetPackageCacheDir();
  344. ResourceCache* cache = GetSubsystem<ResourceCache>();
  345. Vector<SharedPtr<PackageFile> > packages = cache->GetPackageFiles();
  346. for (unsigned i = 0; i < packages.Size(); ++i)
  347. {
  348. PackageFile* package = packages[i];
  349. if (!package->GetName().Find(packageCacheDir))
  350. cache->RemovePackageFile(package, true);
  351. }
  352. // Now check which packages we have in the resource cache or in the download cache, and which we need to download
  353. unsigned numPackages = msg.ReadVLE();
  354. packages = cache->GetPackageFiles(); // Refresh resource cache's package list after possible removals
  355. Vector<String> downloadedPackages;
  356. if (!packageCacheDir.Empty())
  357. GetSubsystem<FileSystem>()->ScanDir(downloadedPackages, packageCacheDir, "*.*", SCAN_FILES, false);
  358. for (unsigned i = 0; i < numPackages; ++i)
  359. {
  360. String name = msg.ReadString();
  361. unsigned fileSize = msg.ReadUInt();
  362. unsigned checksum = msg.ReadUInt();
  363. String checksumString = ToStringHex(checksum);
  364. bool found = false;
  365. // Check first the resource cache
  366. for (unsigned j = 0; j < packages.Size(); ++j)
  367. {
  368. PackageFile* package = packages[j];
  369. if (!GetFileNameAndExtension(package->GetName()).Compare(name, false) && package->GetTotalSize() == fileSize &&
  370. package->GetChecksum() == checksum)
  371. {
  372. found = true;
  373. break;
  374. }
  375. }
  376. // Then the download cache
  377. for (unsigned j = 0; j < downloadedPackages.Size(); ++j)
  378. {
  379. const String& fileName = downloadedPackages[j];
  380. if (!fileName.Find(checksumString) && !fileName.Substring(9).Compare(name, false))
  381. {
  382. // Name matches. Check filesize and actual checksum to be sure
  383. SharedPtr<PackageFile> newPackage(new PackageFile(context_, packageCacheDir + fileName));
  384. if (newPackage->GetTotalSize() == fileSize && newPackage->GetChecksum() == checksum)
  385. {
  386. // Add the package to the resource system now, as we will need it to load the scene
  387. cache->AddPackageFile(newPackage, true);
  388. found = true;
  389. break;
  390. }
  391. }
  392. }
  393. // Package not found, need to request a download
  394. if (!found)
  395. {
  396. if (!packageCacheDir.Empty())
  397. RequestPackage(name, fileSize, checksum);
  398. else
  399. {
  400. LOGERROR("Can not download required packages, as package cache directory is not set");
  401. OnSceneLoadFailed();
  402. return;
  403. }
  404. }
  405. }
  406. // If no downloads were queued, can load the scene directly
  407. if (downloads_.Empty())
  408. OnPackagesReady();
  409. }
  410. void Connection::ProcessSceneChecksumError(int msgID, MemoryBuffer& msg)
  411. {
  412. if (IsClient())
  413. {
  414. LOGWARNING("Received unexpected SceneChecksumError message from client " + ToString());
  415. return;
  416. }
  417. OnSceneLoadFailed();
  418. }
  419. void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
  420. {
  421. if (IsClient())
  422. {
  423. LOGWARNING("Received unexpected SceneUpdate message from client " + ToString());
  424. return;
  425. }
  426. if (!scene_)
  427. return;
  428. switch (msgID)
  429. {
  430. case MSG_CREATENODE:
  431. {
  432. unsigned nodeID = msg.ReadNetID();
  433. // In case of the root node (scene), it should already exist. Do not create in that case
  434. Node* node = scene_->GetNode(nodeID);
  435. if (!node)
  436. {
  437. // Add initially to the root level. May be moved as we receive the parent attribute
  438. node = scene_->CreateChild(nodeID, REPLICATED);
  439. }
  440. // Enable motion smoothing on the node
  441. node->SetSmoothed(true);
  442. // Read initial attributes, then snap the motion smoothing immediately to the end
  443. node->ReadDeltaUpdate(msg, deltaUpdateBits_);
  444. node->UpdateSmoothing(1.0f, 0.0f);
  445. // Read initial user variables
  446. unsigned numVars = msg.ReadVLE();
  447. VariantMap& vars = node->GetVars();
  448. while (numVars)
  449. {
  450. --numVars;
  451. ShortStringHash key = msg.ReadShortStringHash();
  452. vars[key] = msg.ReadVariant();
  453. }
  454. // Read components
  455. unsigned numComponents = msg.ReadVLE();
  456. while (numComponents)
  457. {
  458. --numComponents;
  459. ShortStringHash type = msg.ReadShortStringHash();
  460. unsigned componentID = msg.ReadNetID();
  461. // Check if the component by this ID and type already exists in this node
  462. Component* component = scene_->GetComponent(componentID);
  463. if (!component || component->GetType() != type || component->GetNode() != node)
  464. {
  465. if (component)
  466. component->Remove();
  467. component = node->CreateComponent(type, componentID, REPLICATED);
  468. }
  469. // If was unable to create the component, would desync the message and therefore have to abort
  470. if (!component)
  471. {
  472. LOGERROR("CreateNode message parsing aborted due to unknown component");
  473. return;
  474. }
  475. // Read initial attributes, then perform finalization
  476. component->ReadDeltaUpdate(msg, deltaUpdateBits_);
  477. component->FinishUpdate();
  478. }
  479. }
  480. break;
  481. case MSG_NODEDELTAUPDATE:
  482. {
  483. unsigned nodeID = msg.ReadNetID();
  484. Node* node = scene_->GetNode(nodeID);
  485. if (node)
  486. {
  487. node->ReadDeltaUpdate(msg, deltaUpdateBits_);
  488. unsigned changedVars = msg.ReadVLE();
  489. VariantMap& vars = node->GetVars();
  490. while (changedVars)
  491. {
  492. --changedVars;
  493. ShortStringHash key = msg.ReadShortStringHash();
  494. vars[key] = msg.ReadVariant();
  495. }
  496. }
  497. else
  498. LOGWARNING("NodeDeltaUpdate message received for missing node " + String(nodeID));
  499. }
  500. break;
  501. case MSG_NODELATESTDATA:
  502. {
  503. unsigned nodeID = msg.ReadNetID();
  504. Node* node = scene_->GetNode(nodeID);
  505. if (node)
  506. node->ReadLatestDataUpdate(msg);
  507. else
  508. {
  509. // Latest data messages may be received out-of-order relative to node creation, so cache if necessary
  510. PODVector<unsigned char>& data = nodeLatestData_[nodeID];
  511. data.Resize(msg.GetSize());
  512. memcpy(&data[0], msg.GetData(), msg.GetSize());
  513. }
  514. }
  515. break;
  516. case MSG_REMOVENODE:
  517. {
  518. unsigned nodeID = msg.ReadNetID();
  519. Node* node = scene_->GetNode(nodeID);
  520. if (node)
  521. node->Remove();
  522. nodeLatestData_.Erase(nodeID);
  523. }
  524. break;
  525. case MSG_CREATECOMPONENT:
  526. {
  527. unsigned nodeID = msg.ReadNetID();
  528. Node* node = scene_->GetNode(nodeID);
  529. if (node)
  530. {
  531. ShortStringHash type = msg.ReadShortStringHash();
  532. unsigned componentID = msg.ReadNetID();
  533. // Check if the component by this ID and type already exists in this node
  534. Component* component = scene_->GetComponent(componentID);
  535. if (!component || component->GetType() != type || component->GetNode() != node)
  536. {
  537. if (component)
  538. component->Remove();
  539. component = node->CreateComponent(type, componentID, REPLICATED);
  540. }
  541. // If was unable to create the component, would desync the message and therefore have to abort
  542. if (!component)
  543. {
  544. LOGERROR("CreateComponent message parsing aborted due to unknown component");
  545. return;
  546. }
  547. // Read initial attributes, then perform finalization
  548. component->ReadDeltaUpdate(msg, deltaUpdateBits_);
  549. component->FinishUpdate();
  550. }
  551. else
  552. LOGWARNING("CreateComponent message received for missing node " + String(nodeID));
  553. }
  554. break;
  555. case MSG_COMPONENTDELTAUPDATE:
  556. {
  557. unsigned componentID = msg.ReadNetID();
  558. Component* component = scene_->GetComponent(componentID);
  559. if (component)
  560. {
  561. component->ReadDeltaUpdate(msg, deltaUpdateBits_);
  562. component->FinishUpdate();
  563. }
  564. else
  565. LOGWARNING("ComponentDeltaUpdate message received for missing component " + String(componentID));
  566. }
  567. break;
  568. case MSG_COMPONENTLATESTDATA:
  569. {
  570. unsigned componentID = msg.ReadNetID();
  571. Component* component = scene_->GetComponent(componentID);
  572. if (component)
  573. {
  574. component->ReadLatestDataUpdate(msg);
  575. component->FinishUpdate();
  576. }
  577. else
  578. {
  579. // Latest data messages may be received out-of-order relative to component creation, so cache if necessary
  580. PODVector<unsigned char>& data = componentLatestData_[componentID];
  581. data.Resize(msg.GetSize());
  582. memcpy(&data[0], msg.GetData(), msg.GetSize());
  583. }
  584. }
  585. break;
  586. case MSG_REMOVECOMPONENT:
  587. {
  588. unsigned componentID = msg.ReadNetID();
  589. Component* component = scene_->GetComponent(componentID);
  590. if (component)
  591. component->Remove();
  592. componentLatestData_.Erase(componentID);
  593. }
  594. break;
  595. }
  596. }
  597. void Connection::ProcessPackageDownload(int msgID, MemoryBuffer& msg)
  598. {
  599. switch (msgID)
  600. {
  601. case MSG_REQUESTPACKAGE:
  602. if (!IsClient())
  603. {
  604. LOGWARNING("Received unexpected RequestPackage message from server");
  605. return;
  606. }
  607. else
  608. {
  609. String name = msg.ReadString();
  610. if (!scene_)
  611. {
  612. LOGWARNING("Received a RequestPackage message without an assigned scene from client " + ToString());
  613. return;
  614. }
  615. // The package must be one of those required by the scene
  616. const Vector<SharedPtr<PackageFile> >& packages = scene_->GetRequiredPackageFiles();
  617. for (unsigned i = 0; i < packages.Size(); ++i)
  618. {
  619. PackageFile* package = packages[i];
  620. String packageFullName = package->GetName();
  621. if (!GetFileNameAndExtension(packageFullName).Compare(name, false))
  622. {
  623. StringHash nameHash(name);
  624. // Do not restart upload if already exists
  625. if (uploads_.Contains(nameHash))
  626. {
  627. LOGWARNING("Received a request for package " + name + " already in transfer");
  628. return;
  629. }
  630. // Try to open the file now
  631. SharedPtr<File> file(new File(context_, packageFullName));
  632. if (!file->IsOpen())
  633. {
  634. LOGERROR("Failed to transmit package file " + name);
  635. SendPackageError(name);
  636. return;
  637. }
  638. LOGINFO("Transmitting package file " + name + " to client " + ToString());
  639. uploads_[nameHash].file_ = file;
  640. uploads_[nameHash].fragment_ = 0;
  641. uploads_[nameHash].totalFragments_ = (file->GetSize() + PACKAGE_FRAGMENT_SIZE - 1) / PACKAGE_FRAGMENT_SIZE;
  642. return;
  643. }
  644. }
  645. LOGERROR("Client requested an unexpected package file " + name);
  646. // Send the name hash only to indicate a failed download
  647. SendPackageError(name);
  648. return;
  649. }
  650. break;
  651. case MSG_PACKAGEDATA:
  652. if (IsClient())
  653. {
  654. LOGWARNING("Received unexpected PackageData message from client");
  655. return;
  656. }
  657. else
  658. {
  659. StringHash nameHash = msg.ReadStringHash();
  660. Map<StringHash, PackageDownload>::Iterator i = downloads_.Find(nameHash);
  661. // In case of being unable to create the package file into the cache, we will still receive all data from the server.
  662. // Simply disregard it
  663. if (i == downloads_.End())
  664. return;
  665. PackageDownload& download = i->second_;
  666. // If no further data, this is an error reply
  667. if (msg.IsEof())
  668. {
  669. OnPackageDownloadFailed(download.name_);
  670. return;
  671. }
  672. // If file has not yet been opened, try to open now. Prepend the checksum to the filename to allow multiple versions
  673. if (!download.file_)
  674. {
  675. download.file_ = new File(context_, GetSubsystem<Network>()->GetPackageCacheDir() + ToStringHex(download.checksum_) + "_" + download.name_, FILE_WRITE);
  676. if (!download.file_->IsOpen())
  677. {
  678. OnPackageDownloadFailed(download.name_);
  679. return;
  680. }
  681. }
  682. // Write the fragment data to the proper index
  683. unsigned char buffer[PACKAGE_FRAGMENT_SIZE];
  684. unsigned index = msg.ReadUInt();
  685. unsigned fragmentSize = msg.GetSize() - msg.GetPosition();
  686. msg.Read(buffer, fragmentSize);
  687. download.file_->Seek(index * PACKAGE_FRAGMENT_SIZE);
  688. download.file_->Write(buffer, fragmentSize);
  689. download.receivedFragments_.Insert(index);
  690. // Check if all fragments received
  691. if (download.receivedFragments_.Size() == download.totalFragments_)
  692. {
  693. LOGINFO("Package " + download.name_ + " downloaded successfully");
  694. // Instantiate the package and add to the resource system, as we will need it to load the scene
  695. download.file_->Close();
  696. SharedPtr<PackageFile> newPackage(new PackageFile(context_, download.file_->GetName()));
  697. GetSubsystem<ResourceCache>()->AddPackageFile(newPackage, true);
  698. // Then start the next download if there are more
  699. downloads_.Erase(i);
  700. if (downloads_.Empty())
  701. OnPackagesReady();
  702. else
  703. {
  704. PackageDownload& nextDownload = downloads_.Begin()->second_;
  705. LOGINFO("Requesting package " + nextDownload.name_ + " from server");
  706. msg_.Clear();
  707. msg_.WriteString(nextDownload.name_);
  708. SendMessage(MSG_REQUESTPACKAGE, true, true, msg_, NET_HIGH_PRIORITY);
  709. nextDownload.initiated_ = true;
  710. }
  711. }
  712. }
  713. break;
  714. }
  715. }
  716. void Connection::ProcessIdentity(int msgID, MemoryBuffer& msg)
  717. {
  718. if (!IsClient())
  719. {
  720. LOGWARNING("Received unexpected Identity message from server");
  721. return;
  722. }
  723. identity_ = msg.ReadVariantMap();
  724. using namespace ClientIdentity;
  725. VariantMap eventData = identity_;
  726. eventData[P_CONNECTION] = (void*)this;
  727. eventData[P_ALLOW] = true;
  728. SendEvent(E_CLIENTIDENTITY, eventData);
  729. // If connection was denied as a response to the identity event, disconnect now
  730. if (!eventData[P_ALLOW].GetBool())
  731. Disconnect();
  732. }
  733. void Connection::ProcessControls(int msgID, MemoryBuffer& msg)
  734. {
  735. if (!IsClient())
  736. {
  737. LOGWARNING("Received unexpected Controls message from server");
  738. return;
  739. }
  740. Controls newControls;
  741. newControls.buttons_ = msg.ReadUInt();
  742. newControls.yaw_ = msg.ReadFloat();
  743. newControls.pitch_ = msg.ReadFloat();
  744. newControls.extraData_ = msg.ReadVariantMap();
  745. SetControls(newControls);
  746. SetPosition(msg.ReadVector3());
  747. }
  748. void Connection::ProcessSceneLoaded(int msgID, MemoryBuffer& msg)
  749. {
  750. if (!IsClient())
  751. {
  752. LOGWARNING("Received unexpected SceneLoaded message from server");
  753. return;
  754. }
  755. if (!scene_)
  756. {
  757. LOGWARNING("Received a SceneLoaded message without an assigned scene from client " + ToString());
  758. return;
  759. }
  760. unsigned checksum = msg.ReadUInt();
  761. if (checksum != scene_->GetChecksum())
  762. {
  763. msg_.Clear();
  764. SendMessage(MSG_SCENECHECKSUMERROR, true, true, msg_, NET_HIGH_PRIORITY);
  765. OnSceneLoadFailed();
  766. }
  767. else
  768. {
  769. sceneLoaded_ = true;
  770. using namespace ClientSceneLoaded;
  771. VariantMap eventData;
  772. eventData[P_CONNECTION] = (void*)this;
  773. SendEvent(E_CLIENTSCENELOADED, eventData);
  774. }
  775. }
  776. void Connection::ProcessRemoteEvent(int msgID, MemoryBuffer& msg)
  777. {
  778. if (msgID == MSG_REMOTEEVENT)
  779. {
  780. StringHash eventType = msg.ReadStringHash();
  781. if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
  782. {
  783. LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
  784. return;
  785. }
  786. VariantMap eventData = msg.ReadVariantMap();
  787. SendEvent(eventType, eventData);
  788. }
  789. else
  790. {
  791. if (!scene_)
  792. {
  793. LOGERROR("Can not receive remote node event without an assigned scene");
  794. return;
  795. }
  796. unsigned nodeID = msg.ReadNetID();
  797. StringHash eventType = msg.ReadStringHash();
  798. if (!GetSubsystem<Network>()->CheckRemoteEvent(eventType))
  799. {
  800. LOGWARNING("Discarding not allowed remote event " + eventType.ToString());
  801. return;
  802. }
  803. VariantMap eventData = msg.ReadVariantMap();
  804. Node* receiver = scene_->GetNode(nodeID);
  805. if (!receiver)
  806. {
  807. LOGWARNING("Missing receiver for remote node event, discarding");
  808. return;
  809. }
  810. SendEvent(receiver, eventType, eventData);
  811. }
  812. }
  813. kNet::MessageConnection* Connection::GetMessageConnection() const
  814. {
  815. return const_cast<kNet::MessageConnection*>(connection_.ptr());
  816. }
  817. Scene* Connection::GetScene() const
  818. {
  819. return scene_;
  820. }
  821. bool Connection::IsConnected() const
  822. {
  823. return connection_->GetConnectionState() == kNet::ConnectionOK;
  824. }
  825. String Connection::GetAddress() const
  826. {
  827. const unsigned char* ip = connection_->RemoteEndPoint().ip;
  828. char str[256];
  829. sprintf(str, "%d.%d.%d.%d", (unsigned)ip[0], (unsigned)ip[1], (unsigned)ip[2], (unsigned)ip[3]);
  830. return String(str);
  831. }
  832. unsigned short Connection::GetPort() const
  833. {
  834. return connection_->RemoteEndPoint().port;
  835. }
  836. String Connection::ToString() const
  837. {
  838. return GetAddress() + ":" + String(GetPort());
  839. }
  840. unsigned Connection::GetNumDownloads() const
  841. {
  842. return downloads_.Size();
  843. }
  844. const String& Connection::GetDownloadName() const
  845. {
  846. for (Map<StringHash, PackageDownload>::ConstIterator i = downloads_.Begin(); i != downloads_.End(); ++i)
  847. {
  848. if (i->second_.initiated_)
  849. return i->second_.name_;
  850. }
  851. return noName;
  852. }
  853. float Connection::GetDownloadProgress() const
  854. {
  855. for (Map<StringHash, PackageDownload>::ConstIterator i = downloads_.Begin(); i != downloads_.End(); ++i)
  856. {
  857. if (i->second_.initiated_)
  858. return (float)i->second_.receivedFragments_.Size() / (float)i->second_.totalFragments_;
  859. }
  860. return 1.0f;
  861. }
  862. void Connection::HandleAsyncLoadFinished(StringHash eventType, VariantMap& eventData)
  863. {
  864. sceneLoaded_ = true;
  865. msg_.Clear();
  866. msg_.WriteUInt(scene_->GetChecksum());
  867. SendMessage(MSG_SCENELOADED, true, true, msg_, NET_HIGH_PRIORITY);
  868. }
  869. void Connection::ProcessNode(Node* node)
  870. {
  871. if (!node || processedNodes_.Contains(node))
  872. return;
  873. processedNodes_.Insert(node);
  874. // Process depended upon nodes first
  875. PODVector<Node*> dependencyNodes;
  876. node->GetDependencyNodes(dependencyNodes);
  877. for (PODVector<Node*>::ConstIterator i = dependencyNodes.Begin(); i != dependencyNodes.End(); ++i)
  878. ProcessNode(*i);
  879. // Check if the client's replication state already has this node
  880. if (sceneState_.Find(node->GetID()) != sceneState_.End())
  881. ProcessExistingNode(node);
  882. else
  883. ProcessNewNode(node);
  884. }
  885. void Connection::ProcessNewNode(Node* node)
  886. {
  887. msg_.Clear();
  888. msg_.WriteNetID(node->GetID());
  889. NodeReplicationState& nodeState = sceneState_[node->GetID()];
  890. nodeState.priorityAcc_ = 0.0f;
  891. nodeState.frameNumber_ = frameNumber_;
  892. // Write node's attributes
  893. node->WriteInitialDeltaUpdate(msg_, deltaUpdateBits_, nodeState.attributes_);
  894. // Write node's user variables
  895. const VariantMap& vars = node->GetVars();
  896. msg_.WriteVLE(vars.Size());
  897. for (VariantMap::ConstIterator i = vars.Begin(); i != vars.End(); ++i)
  898. {
  899. msg_.WriteShortStringHash(i->first_);
  900. msg_.WriteVariant(i->second_);
  901. nodeState.vars_[i->first_] = i->second_;
  902. }
  903. // Write node's components
  904. msg_.WriteVLE(node->GetNumNetworkComponents());
  905. const Vector<SharedPtr<Component> >& components = node->GetComponents();
  906. for (unsigned i = 0; i < components.Size(); ++i)
  907. {
  908. Component* component = components[i];
  909. // Check if component is not to be replicated
  910. if (component->GetID() >= FIRST_LOCAL_ID)
  911. continue;
  912. ComponentReplicationState& componentState = nodeState.components_[component->GetID()];
  913. componentState.frameNumber_ = frameNumber_;
  914. componentState.type_ = component->GetType();
  915. msg_.WriteShortStringHash(component->GetType());
  916. msg_.WriteNetID(component->GetID());
  917. component->WriteInitialDeltaUpdate(msg_, deltaUpdateBits_, componentState.attributes_);
  918. }
  919. SendMessage(MSG_CREATENODE, true, true, msg_, NET_HIGH_PRIORITY);
  920. }
  921. void Connection::ProcessExistingNode(Node* node)
  922. {
  923. NodeReplicationState& nodeState = sceneState_[node->GetID()];
  924. nodeState.frameNumber_ = frameNumber_;
  925. // Check from the interest management priority component, if exists, whether should update
  926. NetworkPriority* priority = node->GetComponent<NetworkPriority>();
  927. if (priority && (!priority->GetAlwaysUpdateOwner() || node->GetOwner() != this))
  928. {
  929. float distance = (node->GetWorldPosition() - position_).LengthFast();
  930. if (!priority->CheckUpdate(distance, nodeState.priorityAcc_))
  931. return;
  932. }
  933. // Check if attributes have changed
  934. bool deltaUpdate, latestData;
  935. node->PrepareUpdates(deltaUpdateBits_, classCurrentState_[node->GetType()], nodeState.attributes_, deltaUpdate, latestData);
  936. // Check if user variables have changed. Note: variable removal is not supported
  937. changedVars_.Clear();
  938. const VariantMap& vars = node->GetVars();
  939. for (VariantMap::ConstIterator i = vars.Begin(); i != vars.End(); ++i)
  940. {
  941. VariantMap::Iterator j = nodeState.vars_.Find(i->first_);
  942. if (j == nodeState.vars_.End() || i->second_ != j->second_)
  943. {
  944. nodeState.vars_[i->first_] = i->second_;
  945. changedVars_.Insert(i->first_);
  946. deltaUpdate = true;
  947. }
  948. }
  949. // Send deltaupdate message if necessary
  950. if (deltaUpdate)
  951. {
  952. msg_.Clear();
  953. msg_.WriteNetID(node->GetID());
  954. node->WriteDeltaUpdate(msg_, deltaUpdateBits_, nodeState.attributes_);
  955. // Write changed variables
  956. msg_.WriteVLE(changedVars_.Size());
  957. for (HashSet<ShortStringHash>::ConstIterator i = changedVars_.Begin(); i != changedVars_.End(); ++i)
  958. {
  959. VariantMap::ConstIterator j = vars.Find(*i);
  960. msg_.WriteShortStringHash(j->first_);
  961. msg_.WriteVariant(j->second_);
  962. }
  963. SendMessage(MSG_NODEDELTAUPDATE, true, true, msg_, NET_HIGH_PRIORITY);
  964. }
  965. // Send latestdata message if necessary
  966. if (latestData)
  967. {
  968. // If at least one latest data attribute changes, send all of them
  969. msg_.Clear();
  970. msg_.WriteNetID(node->GetID());
  971. node->WriteLatestDataUpdate(msg_, nodeState.attributes_);
  972. SendMessage(MSG_NODELATESTDATA, true, false, msg_, NET_HIGH_PRIORITY, node->GetID());
  973. }
  974. // Check for new or changed components
  975. const Vector<SharedPtr<Component> >& components = node->GetComponents();
  976. for (unsigned i = 0; i < components.Size(); ++i)
  977. {
  978. Component* component = components[i];
  979. // Check if component is not to be replicated
  980. if (component->GetID() >= FIRST_LOCAL_ID)
  981. continue;
  982. Map<unsigned, ComponentReplicationState>::Iterator j = nodeState.components_.Find(component->GetID());
  983. if (j == nodeState.components_.End())
  984. {
  985. // New component
  986. ComponentReplicationState& componentState = nodeState.components_[component->GetID()];
  987. componentState.frameNumber_ = frameNumber_;
  988. componentState.type_ = component->GetType();
  989. msg_.Clear();
  990. msg_.WriteNetID(node->GetID());
  991. msg_.WriteShortStringHash(component->GetType());
  992. msg_.WriteNetID(component->GetID());
  993. component->WriteInitialDeltaUpdate(msg_, deltaUpdateBits_, componentState.attributes_);
  994. SendMessage(MSG_CREATECOMPONENT, true, true, msg_, NET_HIGH_PRIORITY);
  995. }
  996. else
  997. {
  998. // Existing component
  999. ComponentReplicationState& componentState = j->second_;
  1000. componentState.frameNumber_ = frameNumber_;
  1001. component->PrepareUpdates(deltaUpdateBits_, classCurrentState_[component->GetType()], componentState.attributes_,
  1002. deltaUpdate, latestData);
  1003. // Send deltaupdate message if necessary
  1004. if (deltaUpdate)
  1005. {
  1006. msg_.Clear();
  1007. msg_.WriteNetID(component->GetID());
  1008. component->WriteDeltaUpdate(msg_, deltaUpdateBits_, componentState.attributes_);
  1009. SendMessage(MSG_COMPONENTDELTAUPDATE, true, true, msg_, NET_HIGH_PRIORITY);
  1010. }
  1011. // Send latestdata message if necessary
  1012. if (latestData)
  1013. {
  1014. // If at least one latest data attribute changes, send all of them
  1015. msg_.Clear();
  1016. msg_.WriteNetID(component->GetID());
  1017. component->WriteLatestDataUpdate(msg_, componentState.attributes_);
  1018. SendMessage(MSG_COMPONENTLATESTDATA, true, false, msg_, NET_HIGH_PRIORITY, component->GetID());
  1019. }
  1020. }
  1021. }
  1022. // Check for removed components
  1023. for (Map<unsigned, ComponentReplicationState>::Iterator i = nodeState.components_.Begin(); i != nodeState.components_.End();)
  1024. {
  1025. Map<unsigned, ComponentReplicationState>::Iterator current = i++;
  1026. if (current->second_.frameNumber_ != frameNumber_)
  1027. {
  1028. msg_.Clear();
  1029. msg_.WriteNetID(current->first_);
  1030. SendMessage(MSG_REMOVECOMPONENT, true, true, msg_, NET_HIGH_PRIORITY);
  1031. nodeState.components_.Erase(current);
  1032. }
  1033. }
  1034. }
  1035. void Connection::RequestPackage(const String& name, unsigned fileSize, unsigned checksum)
  1036. {
  1037. StringHash nameHash(name);
  1038. if (downloads_.Contains(nameHash))
  1039. return; // Download already exists
  1040. PackageDownload& download = downloads_[nameHash];
  1041. download.name_ = name;
  1042. download.totalFragments_ = (fileSize + PACKAGE_FRAGMENT_SIZE - 1) / PACKAGE_FRAGMENT_SIZE;
  1043. download.checksum_ = checksum;
  1044. // Start download now only if no existing downloads, else wait for the existing ones to finish
  1045. if (downloads_.Size() == 1)
  1046. {
  1047. LOGINFO("Requesting package " + name + " from server");
  1048. msg_.Clear();
  1049. msg_.WriteString(name);
  1050. SendMessage(MSG_REQUESTPACKAGE, true, true, msg_, NET_HIGH_PRIORITY);
  1051. download.initiated_ = true;
  1052. }
  1053. }
  1054. void Connection::SendPackageError(const String& name)
  1055. {
  1056. msg_.Clear();
  1057. msg_.WriteStringHash(StringHash(name));
  1058. SendMessage(MSG_PACKAGEDATA, true, false, msg_, NET_HIGH_PRIORITY);
  1059. }
  1060. void Connection::OnSceneLoadFailed()
  1061. {
  1062. sceneLoaded_ = false;
  1063. using namespace NetworkSceneLoadFailed;
  1064. VariantMap eventData;
  1065. eventData[P_CONNECTION] = (void*)this;
  1066. SendEvent(E_NETWORKSCENELOADFAILED, eventData);
  1067. }
  1068. void Connection::OnPackageDownloadFailed(const String& name)
  1069. {
  1070. LOGERROR("Download of package " + name + " failed");
  1071. // As one package failed, we can not join the scene in any case. Clear the downloads
  1072. downloads_.Clear();
  1073. OnSceneLoadFailed();
  1074. }
  1075. void Connection::OnPackagesReady()
  1076. {
  1077. if (!scene_)
  1078. return;
  1079. if (sceneFileName_.Empty())
  1080. {
  1081. scene_->Clear();
  1082. sceneLoaded_ = true;
  1083. // If filename is empty, can send the scene loaded reply immediately
  1084. msg_.Clear();
  1085. msg_.WriteUInt(scene_->GetChecksum());
  1086. SendMessage(MSG_SCENELOADED, true, true, msg_, NET_HIGH_PRIORITY);
  1087. }
  1088. else
  1089. {
  1090. // Otherwise start the async loading process
  1091. String extension = GetExtension(sceneFileName_);
  1092. SharedPtr<File> file(new File(context_, sceneFileName_));
  1093. bool success;
  1094. if (extension == ".xml")
  1095. success = scene_->LoadAsyncXML(file);
  1096. else
  1097. success = scene_->LoadAsync(file);
  1098. if (!success)
  1099. OnSceneLoadFailed();
  1100. }
  1101. }