Connection.cpp 45 KB

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