Client.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  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 "Client.h"
  25. #include "Connection.h"
  26. #include "FileSystem.h"
  27. #include "Log.h"
  28. #include "Network.h"
  29. #include "NetworkEvents.h"
  30. #include "PackageFile.h"
  31. #include "ProcessUtils.h"
  32. #include "Profiler.h"
  33. #include "Protocol.h"
  34. #include "ProtocolEvents.h"
  35. #include "ResourceCache.h"
  36. #include "Scene.h"
  37. #include "SceneEvents.h"
  38. #include "StringUtils.h"
  39. #include "DebugNew.h"
  40. static const Controls noControls;
  41. static const int MIN_FILE_FRAGMENT_COUNT = 16;
  42. static const int MAX_FILE_FRAGMENT_COUNT = 1024;
  43. static const int FILE_FRAGMENT_COUNT_DELTA = 8;
  44. OBJECTTYPESTATIC(Client);
  45. Client::Client(Context* context) :
  46. Object(context),
  47. netFps_(30),
  48. timeAcc_(0.0f),
  49. frameNumber_(1)
  50. {
  51. SubscribeToEvent(E_PEERDISCONNECTED, HANDLER(Client, HandlePeerDisconnected));
  52. SubscribeToEvent(E_FILETRANSFERCOMPLETED, HANDLER(Client, HandleFileTransferCompleted));
  53. SubscribeToEvent(E_FILETRANSFERFAILED, HANDLER(Client, HandleFileTransferFailed));
  54. SubscribeToEvent(E_ASYNCLOADFINISHED, HANDLER(Client, HandleAsyncLoadFinished));
  55. }
  56. Client::~Client()
  57. {
  58. }
  59. void Client::SetScene(Scene* scene)
  60. {
  61. scene_ = scene;
  62. }
  63. void Client::SetDownloadDirectory(const String& path)
  64. {
  65. downloadDirectory_ = AddTrailingSlash(path);
  66. }
  67. bool Client::Connect(const String& address, unsigned short port, const VariantMap& loginData)
  68. {
  69. if (!scene_)
  70. return false;
  71. // Make sure any previous async loading is stopped
  72. scene_->StopAsyncLoading();
  73. Disconnect();
  74. Peer* peer = GetSubsystem<Network>()->Connect(address, port);
  75. if (!peer)
  76. return false;
  77. serverConnection_ = new Connection(context_, peer);
  78. frameNumber_ = 1;
  79. pendingLoginData_ = loginData;
  80. return true;
  81. }
  82. void Client::Disconnect()
  83. {
  84. if (serverConnection_)
  85. {
  86. serverConnection_->Disconnect();
  87. serverConnection_.Reset();
  88. }
  89. // Stop async loading if was in progress
  90. if (!scene_)
  91. scene_->StopAsyncLoading();
  92. pendingDownloads_.Clear();
  93. fileTransfers_.Clear();
  94. sceneInfo_ = SceneInfo();
  95. }
  96. void Client::SetControls(const Controls& controls)
  97. {
  98. if (serverConnection_)
  99. serverConnection_->SetControls(controls);
  100. }
  101. void Client::SetPosition(const Vector3& position)
  102. {
  103. if (serverConnection_)
  104. serverConnection_->SetPosition(position);
  105. }
  106. void Client::Update(float timeStep)
  107. {
  108. PROFILE(UpdateClient);
  109. // Process connection (assume that Engine has updated Network, so we do not do that here)
  110. if (serverConnection_)
  111. {
  112. VectorBuffer packet;
  113. // Process reliable packets first, then unreliable
  114. while (serverConnection_->ReceiveReliable(packet))
  115. HandleReliablePacket(packet);
  116. while (serverConnection_->ReceiveUnreliable(packet))
  117. HandleServerUpdate(packet);
  118. // Update own simulation of scene if connected
  119. if (serverConnection_->GetScene() == scene_)
  120. scene_->Update(timeStep);
  121. }
  122. // Send update if enough time passed
  123. float netPeriod = 1.0f / netFps_;
  124. timeAcc_ += timeStep;
  125. if (timeAcc_ >= netPeriod)
  126. {
  127. // If multiple updates have accumulated because of a slow frame, send just one
  128. while (timeAcc_ >= netPeriod)
  129. timeAcc_ -= netPeriod;
  130. ++frameNumber_;
  131. // We have a policy that framenumber 0 means "frame never received", so loop back to 1
  132. if (!frameNumber_)
  133. ++frameNumber_;
  134. SendClientUpdate();
  135. }
  136. }
  137. bool Client::IsConnected() const
  138. {
  139. return (serverConnection_) && (serverConnection_->IsConnected()) && (serverConnection_->HasChallenge());
  140. }
  141. bool Client::IsJoinPending() const
  142. {
  143. return ((IsConnected()) && (serverConnection_->GetJoinState() == JS_PREPARESCENE));
  144. }
  145. bool Client::IsJoined() const
  146. {
  147. return ((IsConnected()) && (serverConnection_->GetJoinState() > JS_PREPARESCENE));
  148. }
  149. const Controls& Client::GetControls() const
  150. {
  151. if (!serverConnection_)
  152. return noControls;
  153. return serverConnection_->GetControls();
  154. }
  155. const Vector3& Client::GetPosition() const
  156. {
  157. if (!serverConnection_)
  158. return Vector3::ZERO;
  159. return serverConnection_->GetPosition();
  160. }
  161. String Client::GetFileTransferStatus() const
  162. {
  163. String ret;
  164. for (Map<StringHash, FileTransfer>::ConstIterator i = fileTransfers_.Begin(); i != fileTransfers_.End(); ++i)
  165. {
  166. String line = i->second_.fileName_ + " " + ToString(i->second_.bytesReceived_) + "/" + ToString(i->second_.size_)
  167. + " (" + ToString((int)(((float)i->second_.bytesReceived_ / (float)i->second_.size_) * 100.0f + 0.5f)) + "%)\n";
  168. ret += line;
  169. }
  170. return ret;
  171. }
  172. void Client::HandlePeerDisconnected(StringHash eventType, VariantMap& eventData)
  173. {
  174. using namespace PeerDisconnected;
  175. Peer* peerPtr = static_cast<Peer*>(eventData[P_PEER].GetPtr());
  176. if (peerPtr->GetType() != PEER_SERVER)
  177. return;
  178. if (serverConnection_)
  179. {
  180. if (serverConnection_->GetPeer() == peerPtr)
  181. {
  182. serverConnection_->LeftScene();
  183. serverConnection_.Reset();
  184. pendingDownloads_.Clear();
  185. fileTransfers_.Clear();
  186. sceneInfo_ = SceneInfo();
  187. }
  188. }
  189. }
  190. void Client::HandleFileTransferCompleted(StringHash eventType, VariantMap& eventData)
  191. {
  192. using namespace FileTransferCompleted;
  193. String fileName = eventData[P_FILENAME].GetString();
  194. if (pendingDownloads_.Find(fileName) != pendingDownloads_.End())
  195. {
  196. pendingDownloads_.Erase(fileName);
  197. // Add the package to the resource cache
  198. SharedPtr<PackageFile> package(new PackageFile(context_));
  199. if (!package->Open(eventData[P_FULLPATH].GetString()))
  200. {
  201. JoinFailed("Could not open downloaded package file " + fileName);
  202. return;
  203. }
  204. // Add the package as first in case it overrides something in the default files
  205. GetSubsystem<ResourceCache>()->AddPackageFile(package, true);
  206. // If this was the last required download, can now join scene
  207. if ((pendingDownloads_.Empty()) && (IsJoinPending()))
  208. SetupScene();
  209. }
  210. }
  211. void Client::HandleFileTransferFailed(StringHash eventType, VariantMap& eventData)
  212. {
  213. using namespace FileTransferFailed;
  214. String fileName = eventData[P_FILENAME].GetString();
  215. if (pendingDownloads_.Find(fileName) != pendingDownloads_.End())
  216. JoinFailed("Failed to transfer file " + fileName);
  217. }
  218. void Client::HandleAsyncLoadFinished(StringHash eventType, VariantMap& eventData)
  219. {
  220. if ((!scene_) || (!serverConnection_))
  221. return;
  222. using namespace AsyncLoadFinished;
  223. // If it is the scene used for networking, send join packet now
  224. if ((eventData[P_SCENE].GetPtr() == (void*)scene_) && (serverConnection_->GetJoinState() == JS_LOADSCENE))
  225. SendJoinScene();
  226. }
  227. void Client::HandleReliablePacket(VectorBuffer& packet)
  228. {
  229. unsigned char msgID = 0;
  230. msgID = packet.ReadUByte();
  231. switch (msgID)
  232. {
  233. case MSG_CHALLENGE:
  234. HandleChallenge(packet);
  235. break;
  236. case MSG_SCENEINFO:
  237. HandleSceneInfo(packet);
  238. break;
  239. case MSG_TRANSFERDATA:
  240. HandleTransferData(packet);
  241. break;
  242. case MSG_TRANSFERFAILED:
  243. HandleTransferFailed(packet);
  244. break;
  245. case MSG_JOINREPLY:
  246. HandleJoinReply(packet);
  247. break;
  248. case MSG_FULLUPDATE:
  249. HandleFullUpdate(packet);
  250. break;
  251. default:
  252. LOGERROR("Unknown message ID " + ToString((int)msgID) + " received from server");
  253. break;
  254. }
  255. }
  256. void Client::HandleChallenge(VectorBuffer& packet)
  257. {
  258. serverConnection_->SetChallenge(packet.ReadUInt());
  259. // Send login packet as a response
  260. VectorBuffer replyPacket;
  261. replyPacket.WriteUByte(MSG_LOGIN);
  262. replyPacket.WriteVariantMap(pendingLoginData_);
  263. serverConnection_->SendReliable(replyPacket);
  264. }
  265. void Client::HandleSceneInfo(VectorBuffer& packet)
  266. {
  267. if (!scene_)
  268. return;
  269. // Stop all previous loading, associate the scene with the connection
  270. scene_->StopAsyncLoading();
  271. serverConnection_->SetScene(scene_);
  272. // Read scene name, number of users and update rate
  273. String sceneName = packet.ReadString();
  274. sceneInfo_.name_ = sceneName;
  275. sceneInfo_.numUsers_ = packet.ReadVLE();
  276. sceneInfo_.netFps_ = packet.ReadInt();
  277. // Read source file name & required packages
  278. sceneInfo_.fileName_ = packet.ReadString();
  279. unsigned numPackages = packet.ReadVLE();
  280. sceneInfo_.requiredPackages_.Clear();
  281. for (unsigned i = 0; i < numPackages; ++i)
  282. {
  283. PackageInfo package;
  284. package.name_ = packet.ReadString();
  285. package.size_ = packet.ReadUInt();
  286. package.checksum_ = packet.ReadUInt();
  287. sceneInfo_.requiredPackages_.Push(package);
  288. }
  289. // Check need for downloads: if none, can join immediately
  290. if (!CheckPackages())
  291. SetupScene();
  292. }
  293. void Client::HandleTransferData(VectorBuffer& packet)
  294. {
  295. StringHash nameHash = packet.ReadStringHash();
  296. Map<StringHash, FileTransfer>::Iterator i = fileTransfers_.Find(nameHash);
  297. if (i == fileTransfers_.End())
  298. {
  299. LOGDEBUG("Received fragment for nonexisting file transfer " + ToString(nameHash));
  300. return;
  301. }
  302. FileTransfer& transfer = i->second_;
  303. unsigned index = packet.ReadVLE();
  304. if (transfer.fragmentsReceived_ != index)
  305. {
  306. LOGERROR("Received unexpected fragment for file " + ToString(nameHash) + ", stopping transfer");
  307. using namespace FileTransferFailed;
  308. VariantMap eventData;
  309. eventData[P_FILENAME] = transfer.fileName_;
  310. eventData[P_REASON] = "Unexpected fragment";
  311. SendEvent(E_FILETRANSFERFAILED, eventData);
  312. fileTransfers_.Erase(i);
  313. return;
  314. }
  315. transfer.fragmentsReceived_ = index + 1; // We receive fragments in order
  316. unsigned dataSize = packet.GetSize() - packet.GetPosition();
  317. transfer.file_->Write(packet.GetData() + packet.GetPosition(), dataSize);
  318. transfer.bytesReceived_ += dataSize;
  319. if (transfer.fragmentsReceived_ == transfer.numFragments_)
  320. {
  321. if (transfer.bytesReceived_ != transfer.size_)
  322. {
  323. LOGERROR("Transfer of file " + transfer.fileName_ + " finished, expected " + ToString(transfer.size_) +
  324. " bytes but got " + ToString(transfer.bytesReceived_));
  325. using namespace FileTransferFailed;
  326. VariantMap eventData;
  327. eventData[P_FILENAME] = transfer.fileName_;
  328. eventData[P_REASON] = "Unexpected file size";
  329. SendEvent(E_FILETRANSFERFAILED, eventData);
  330. }
  331. else
  332. {
  333. float totalTime = transfer.receiveTimer_.GetMSec(true) * 0.001f;
  334. LOGINFO("Transfer of file " + transfer.fileName_ + " completed in " +
  335. ToString(totalTime) + " seconds, speed " + ToString(transfer.size_ / totalTime) + " bytes/sec");
  336. using namespace FileTransferCompleted;
  337. VariantMap eventData;
  338. eventData[P_FILENAME] = transfer.fileName_;
  339. eventData[P_FULLPATH] = transfer.file_->GetName();
  340. // Others might try to use the file as a response to the event, so close it first
  341. transfer.file_.Reset();
  342. SendEvent(E_FILETRANSFERCOMPLETED, eventData);
  343. }
  344. fileTransfers_.Erase(i);
  345. return;
  346. }
  347. // If current batch was finished, fire off the next
  348. if (transfer.fragmentsReceived_ == transfer.batchStart_ + transfer.batchSize_)
  349. {
  350. transfer.batchStart_ = transfer.fragmentsReceived_;
  351. float batchTime = transfer.batchTimer_.GetMSec(true) * 0.001f;
  352. float newDataRate = transfer.batchSize_ * FILE_FRAGMENT_SIZE / batchTime;
  353. LOGDEBUG("Received " + ToString(transfer.batchSize_) + " fragments in " + ToString(batchTime) + " seconds");
  354. // If this was the first batch, can not yet estimate speed, so go up in batch size
  355. if (!transfer.lastBatchSize_)
  356. {
  357. transfer.lastBatchSize_ = transfer.batchSize_;
  358. transfer.lastDataRate_ = newDataRate;
  359. transfer.batchSize_ += FILE_FRAGMENT_COUNT_DELTA;
  360. }
  361. else
  362. {
  363. bool goUp = true;
  364. // Go down in batch size if last batch was smaller and had better data rate
  365. if ((transfer.lastBatchSize_ < transfer.batchSize_) && (transfer.lastDataRate_ > newDataRate))
  366. goUp = false;
  367. transfer.lastBatchSize_ = transfer.batchSize_;
  368. transfer.lastDataRate_ = newDataRate;
  369. if (goUp)
  370. transfer.batchSize_ += FILE_FRAGMENT_COUNT_DELTA;
  371. else
  372. transfer.batchSize_ -= FILE_FRAGMENT_COUNT_DELTA;
  373. transfer.batchSize_ = Clamp((int)transfer.batchSize_, MIN_FILE_FRAGMENT_COUNT, MAX_FILE_FRAGMENT_COUNT);
  374. }
  375. VectorBuffer packet;
  376. packet.WriteUByte(MSG_REQUESTFILE);
  377. packet.WriteStringHash(i->first_);
  378. packet.WriteVLE(transfer.batchStart_);
  379. packet.WriteVLE(transfer.batchSize_);
  380. serverConnection_->SendReliable(packet);
  381. }
  382. }
  383. void Client::HandleTransferFailed(VectorBuffer& packet)
  384. {
  385. StringHash nameHash = packet.ReadStringHash();
  386. String reason = packet.ReadString();
  387. Map<StringHash, FileTransfer>::Iterator i = fileTransfers_.Find(nameHash);
  388. if (i == fileTransfers_.End())
  389. {
  390. LOGDEBUG("Received fail for nonexisting file transfer " + ToString(nameHash));
  391. return;
  392. }
  393. String errorMsg = "Transfer of file " + ToString(nameHash) + " failed: " + reason;
  394. LOGINFO(errorMsg);
  395. using namespace FileTransferFailed;
  396. VariantMap eventData;
  397. eventData[P_FILENAME] = i->second_.fileName_;
  398. eventData[P_REASON] = reason;
  399. SendEvent(E_FILETRANSFERFAILED, eventData);
  400. fileTransfers_.Erase(i);
  401. }
  402. void Client::HandleJoinReply(VectorBuffer& packet)
  403. {
  404. if (!scene_)
  405. return;
  406. bool success = packet.ReadBool();
  407. if (success)
  408. {
  409. serverConnection_->JoinedScene();
  410. LOGINFO("Joined scene " + scene_->GetName());
  411. SendEvent(E_JOINEDSCENE);
  412. }
  413. else
  414. {
  415. String reason = packet.ReadString();
  416. serverConnection_->LeftScene();
  417. pendingDownloads_.Clear();
  418. fileTransfers_.Clear();
  419. JoinFailed(reason);
  420. }
  421. }
  422. void Client::HandleFullUpdate(VectorBuffer& packet)
  423. {
  424. HandleServerUpdate(packet, true);
  425. }
  426. void Client::HandleServerUpdate(VectorBuffer& packet, bool initial)
  427. {
  428. if (!IsJoined())
  429. return;
  430. // Read frame numbers
  431. unsigned short lastFrameNumber = packet.ReadUShort();
  432. unsigned short lastFrameAck = packet.ReadUShort();
  433. if (!initial)
  434. {
  435. // Check that this packet is not older than the last received (overlap may occur when we transition
  436. // between a reliable full update and unreliable delta updates)
  437. if (!CheckFrameNumber(lastFrameNumber, serverConnection_->GetFrameNumber()))
  438. return;
  439. //LOGDEBUG("Delta: " + ToString(packet.GetSize()));
  440. }
  441. else
  442. {
  443. // If initial/full update, remove all old non-local nodes
  444. scene_->ClearNonLocal();
  445. LOGDEBUG("Initial scene: " + ToString(packet.GetSize()) + " bytes");
  446. }
  447. serverConnection_->SetFrameNumbers(lastFrameNumber, lastFrameAck);
  448. serverConnection_->UpdateRoundTripTime(netFps_, frameNumber_);
  449. unsigned short previousEventFrameNumber = serverConnection_->GetEventFrameNumber();
  450. Set<unsigned> updatedNodes;
  451. Set<unsigned> updatedComponents;
  452. // Read the actual scene update messages
  453. while (!packet.IsEof())
  454. {
  455. unsigned char msgID = packet.ReadUByte();
  456. switch (msgID & 0x0f)
  457. {
  458. case MSG_REMOTEEVENT:
  459. {
  460. RemoteEvent newEvent;
  461. newEvent.Read(packet, false);
  462. if (serverConnection_->CheckRemoteEventFrame(newEvent, previousEventFrameNumber))
  463. newEvent.Dispatch(serverConnection_, scene_);
  464. }
  465. break;
  466. case MSG_REMOTENODEEVENT:
  467. {
  468. RemoteEvent newEvent;
  469. newEvent.Read(packet, true);
  470. if (serverConnection_->CheckRemoteEventFrame(newEvent, previousEventFrameNumber))
  471. newEvent.Dispatch(serverConnection_, scene_);
  472. }
  473. break;
  474. default:
  475. LOGWARNING("Unknown message ID " + ToString((int)msgID) + " received from server");
  476. packet.Seek(packet.GetSize()); // Break loop
  477. break;
  478. }
  479. }
  480. // Perform post network update for nodes & components
  481. // If initial update, send back ack
  482. if (initial)
  483. {
  484. VectorBuffer replyPacket;
  485. replyPacket.WriteUByte(MSG_FULLUPDATEACK);
  486. replyPacket.WriteUShort(frameNumber_);
  487. replyPacket.WriteUShort(serverConnection_->GetFrameNumber());
  488. serverConnection_->SendReliable(replyPacket);
  489. serverConnection_->SetJoinState(JS_SENDDELTAS);
  490. }
  491. // Remove acked controls
  492. serverConnection_->PurgeAckedControls();
  493. // Send notification of the server update
  494. using namespace ServerUpdate;
  495. VariantMap eventData;
  496. eventData[P_SCENE] = (void*)scene_.GetPtr();
  497. SendEvent(E_SERVERUPDATE, eventData);
  498. }
  499. unsigned Client::CheckPackages()
  500. {
  501. pendingDownloads_.Clear();
  502. // To avoid resource version conflicts and to keep the amount of open packages reasonable, remove all existing
  503. // downloaded packages from the resource cache first
  504. Vector<String> downloadedPackages;
  505. Vector<SharedPtr<PackageFile> > registeredPackages = GetSubsystem<ResourceCache>()->GetPackageFiles();
  506. GetSubsystem<FileSystem>()->ScanDir(downloadedPackages, downloadDirectory_, "*.pak", SCAN_FILES, false);
  507. for (Vector<SharedPtr<PackageFile> >::Iterator i = registeredPackages.Begin(); i != registeredPackages.End();)
  508. {
  509. if ((*i)->GetName().Find(downloadDirectory_) != String::NPOS)
  510. {
  511. GetSubsystem<ResourceCache>()->RemovePackageFile(*i);
  512. i = registeredPackages.Erase(i);
  513. }
  514. else
  515. ++i;
  516. }
  517. for (unsigned i = 0; i < sceneInfo_.requiredPackages_.Size(); ++i)
  518. {
  519. const PackageInfo& required = sceneInfo_.requiredPackages_[i];
  520. String requiredName = GetFileName(required.name_);
  521. bool found = false;
  522. // Check both already registered packages, and existing downloads
  523. for (unsigned j = 0; j < registeredPackages.Size(); ++j)
  524. {
  525. PackageFile* package = registeredPackages[i];
  526. String name = GetFileName(package->GetName());
  527. if ((name.Find(requiredName) != String::NPOS) && (package->GetTotalSize() == required.size_) &&
  528. (package->GetChecksum() == required.checksum_))
  529. {
  530. found = true;
  531. break;
  532. }
  533. }
  534. if (!found)
  535. {
  536. for (unsigned j = 0; j < downloadedPackages.Size(); ++j)
  537. {
  538. // Downloaded packages are encoded as filename_checksum.pak, so check if the filename contains the required name
  539. String name = GetFileName(downloadedPackages[i]);
  540. if (name.Find(requiredName) != String::NPOS)
  541. {
  542. SharedPtr<PackageFile> file(new PackageFile(context_));
  543. file->Open(downloadDirectory_ + downloadedPackages[i]);
  544. if ((file->GetTotalSize() == required.size_) && (file->GetChecksum() == required.checksum_))
  545. {
  546. // Add the package as first in case it overrides something in the default files
  547. GetSubsystem<ResourceCache>()->AddPackageFile(file, true);
  548. found = true;
  549. break;
  550. }
  551. }
  552. }
  553. }
  554. if (!found)
  555. {
  556. // If not found, initiate the download
  557. if (!RequestFile(required.name_, required.size_, required.checksum_))
  558. {
  559. JoinFailed("Failed to initiate transfer for file " + required.name_);
  560. return M_MAX_UNSIGNED; // Return nonzero to prevent immediate join attempt
  561. }
  562. pendingDownloads_.Insert(required.name_);
  563. }
  564. }
  565. return pendingDownloads_.Size();
  566. }
  567. bool Client::RequestFile(const String& fileName, unsigned size, unsigned checksum)
  568. {
  569. StringHash nameHash(fileName);
  570. if (fileTransfers_.Find(nameHash) != fileTransfers_.End())
  571. return true; // Already initiated
  572. FileTransfer newTransfer;
  573. // Append checksum to download name, so that we can have several versions of a package
  574. String destName = GetFileName(fileName) + "_" + ToStringHex(checksum) + GetExtension(fileName);
  575. newTransfer.file_ = new File(context_, downloadDirectory_ + destName, FILE_WRITE);
  576. if (!newTransfer.file_->IsOpen())
  577. return false;
  578. newTransfer.fileName_ = fileName;
  579. newTransfer.size_ = size;
  580. newTransfer.checksum_ = checksum;
  581. newTransfer.numFragments_ = (size - 1) / FILE_FRAGMENT_SIZE + 1;
  582. newTransfer.batchTimer_.Reset();
  583. newTransfer.receiveTimer_.Reset();
  584. newTransfer.batchSize_ = MIN_FILE_FRAGMENT_COUNT;
  585. VectorBuffer packet;
  586. packet.WriteUByte(MSG_REQUESTFILE);
  587. packet.WriteStringHash(nameHash);
  588. packet.WriteVLE(newTransfer.batchStart_);
  589. packet.WriteVLE(newTransfer.batchSize_);
  590. serverConnection_->SendReliable(packet);
  591. fileTransfers_[nameHash] = newTransfer;
  592. LOGINFO("Started transfer of file " + fileName + ", " + ToString(size) + " bytes");
  593. return true;
  594. }
  595. void Client::SetupScene()
  596. {
  597. netFps_ = sceneInfo_.netFps_;
  598. timeAcc_ = 0.0f;
  599. // Setup the scene
  600. // If no filename, just empty it
  601. if (sceneInfo_.fileName_.Empty())
  602. {
  603. scene_->SetName(sceneInfo_.name_);
  604. scene_->Clear();
  605. SendJoinScene();
  606. }
  607. else
  608. {
  609. SharedPtr<File> sceneFile = GetSubsystem<ResourceCache>()->GetFile(sceneInfo_.fileName_);
  610. // Support either binary or XML format scene
  611. if (GetExtension(sceneInfo_.fileName_) == ".xml")
  612. scene_->LoadAsyncXML(sceneFile);
  613. else
  614. scene_->LoadAsync(sceneFile);
  615. // Check if scene started loading successfully
  616. if (scene_->IsAsyncLoading())
  617. serverConnection_->SetJoinState(JS_LOADSCENE);
  618. else
  619. JoinFailed("Failed to load scene " + sceneInfo_.fileName_);
  620. }
  621. }
  622. void Client::SendJoinScene()
  623. {
  624. if ((!scene_) || (!serverConnection_))
  625. return;
  626. VectorBuffer packet;
  627. packet.WriteUByte(MSG_JOINSCENE);
  628. packet.WriteUInt(scene_->GetChecksum());
  629. serverConnection_->SendReliable(packet);
  630. }
  631. void Client::JoinFailed(const String& reason)
  632. {
  633. LOGINFO("Failed to join scene, reason: " + reason);
  634. using namespace JoinSceneFailed;
  635. VariantMap eventData;
  636. eventData[P_REASON] = reason;
  637. SendEvent(E_JOINSCENEFAILED);
  638. }
  639. void Client::SendClientUpdate()
  640. {
  641. if (!IsJoined())
  642. {
  643. // If we are not connected but remote events have been queued, clear them
  644. serverConnection_->ClearRemoteEvents();
  645. return;
  646. }
  647. // Request updated controls from the application
  648. using namespace ControlsUpdate;
  649. VariantMap eventData;
  650. eventData[P_SCENE] = (void*)scene_.GetPtr();
  651. SendEvent(E_CONTROLSUPDATE, eventData);
  652. // Purge acked and expired remote events
  653. serverConnection_->PurgeAckedRemoteEvents(frameNumber_);
  654. VectorBuffer packet;
  655. packet.WriteUShort(frameNumber_);
  656. packet.WriteUShort(serverConnection_->GetFrameNumber());
  657. // Write controls and position
  658. const Controls& controls = serverConnection_->GetControls();
  659. packet.WriteUByte(MSG_CONTROLS);
  660. packet.WriteUInt(controls.buttons_);
  661. packet.WriteFloat(controls.yaw_);
  662. packet.WriteFloat(controls.pitch_);
  663. packet.WriteVariantMap(controls.extraData_);
  664. packet.WriteVector3(serverConnection_->GetPosition());
  665. // Remember the controls if prediction & replay is needed
  666. serverConnection_->AddUnackedControls(frameNumber_, controls);
  667. // Append unacked remote events
  668. const Vector<RemoteEvent>& unackedEvents = serverConnection_->GetUnackedRemoteEvents();
  669. for (Vector<RemoteEvent>::ConstIterator i = unackedEvents.Begin(); i != unackedEvents.End(); ++i)
  670. {
  671. packet.WriteUByte(i->nodeID_ ? MSG_REMOTENODEEVENT : MSG_REMOTEEVENT);
  672. i->Write(packet);
  673. }
  674. serverConnection_->SendUnreliable(packet);
  675. }
  676. void Client::ReadNetUpdateBlock(Deserializer& source, unsigned char msgID, Set<unsigned>& updatedNodes, Set<unsigned>& updatedComponents)
  677. {
  678. /*
  679. unsigned id = source.ReadUShort();
  680. Node* node = scene_->GetNodeByID(id);
  681. switch (msgID & 0x0f)
  682. {
  683. case MSG_CREATEENTITY:
  684. {
  685. // Node may already exist if server sends the create many times. But data may have changed
  686. String name = source.ReadString();
  687. if (!node)
  688. node = scene_->createNode(id, name);
  689. unsigned char netFlags = source.ReadUByte();
  690. node->setNetFlags(netFlags);
  691. if (netFlags & NET_OWNER)
  692. node->setOwner(serverConnection_);
  693. else
  694. node->setOwner(0);
  695. node->setGroupFlags(source.ReadVLE());
  696. node->setProperties(source.ReadVariantMap(), true);
  697. Set<Component*> extraComponents;
  698. extraComponents.Clear();
  699. const Vector<SharedPtr<Component> >& components = node->GetComponents();
  700. for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
  701. extraComponents.Insert(*i);
  702. unsigned nucomponents_ = source.ReadVLE();
  703. for (unsigned i = 0; i < nucomponents_; ++i)
  704. {
  705. ShortStringHash type = source.ReadShortStringHash();
  706. String name = source.ReadString();
  707. // We might apply the same update multiple times, so check if the component already exists
  708. Component* component = node->GetComponent(type, name);
  709. bool newComponent = false;
  710. if (!component)
  711. {
  712. component = node->createComponent(type, name);
  713. newComponent = true;
  714. }
  715. component->setNetFlags(source.ReadUByte());
  716. component->readNetUpdate(source, GetSubsystem<ResourceCache>(), info);
  717. // If component is new, finish interpolation immediately
  718. if (newComponent)
  719. component->interpolate(true);
  720. extraComponents.Erase(component);
  721. }
  722. // Now check if the node has extra components it should not, and remove them
  723. for (Set<Component*>::Iterator i = extraComponents.Begin(); i != extraComponents.End(); ++i)
  724. node->removeComponent(*i);
  725. updatedNodes.Insert(id);
  726. }
  727. break;
  728. case MSG_REMOVEENTITY:
  729. if (node)
  730. scene_->removeNode(id);
  731. break;
  732. case MSG_UPDATEENTITY:
  733. {
  734. // Node should exist, but if it does not, create it now to not desync the stream
  735. if (!node)
  736. {
  737. LOGERROR("Update to nonexisting node " + ToString(id));
  738. node = scene_->createNode(id);
  739. }
  740. if (msgID & UPD_PROPERTIES)
  741. {
  742. unsigned numProperties = source.ReadVLE();
  743. for (unsigned i = 0; i < numProperties; ++i)
  744. {
  745. ShortStringHash key = source.ReadShortStringHash();
  746. Variant value = source.ReadVariant();
  747. node->setProperty(key, value, true);
  748. }
  749. }
  750. if (msgID & UPD_NEWCOMPONENTS)
  751. {
  752. unsigned nucomponents_ = source.ReadVLE();
  753. for (unsigned i = 0; i < nucomponents_; ++i)
  754. {
  755. ShortStringHash type = source.ReadShortStringHash();
  756. String name = source.ReadString();
  757. // We might apply the same update multiple times, so check if the component already exists
  758. Component* component = node->GetComponent(type, name);
  759. bool newComponent = false;
  760. if (!component)
  761. {
  762. component = node->createComponent(type, name);
  763. newComponent = true;
  764. }
  765. component->setNetFlags(source.ReadUByte());
  766. component->readNetUpdate(source, GetSubsystem<ResourceCache>(), info);
  767. // If component is new, finish interpolation immediately
  768. if (newComponent)
  769. component->interpolate(true);
  770. }
  771. }
  772. if (msgID & UPD_REMOVECOMPONENTS)
  773. {
  774. unsigned nucomponents_ = source.ReadVLE();
  775. for (unsigned i = 0; i < nucomponents_; ++i)
  776. {
  777. Component* component = node->GetComponent(source.ReadShortStringHash().mData);
  778. if (component)
  779. node->removeComponent(component);
  780. }
  781. }
  782. if (msgID & UPD_UPDATECOMPONENTS)
  783. {
  784. unsigned nucomponents_ = source.ReadVLE();
  785. for (unsigned i = 0; i < nucomponents_; ++i)
  786. {
  787. ShortStringHash combinedHash = source.ReadShortStringHash();
  788. Component* component = node->GetComponent(combinedHash.mData);
  789. if (component)
  790. component->readNetUpdate(source, GetSubsystem<ResourceCache>(), info);
  791. else
  792. {
  793. // Component should exist, but if it does not, create it now to not desync the stream
  794. // Note that we only have the combined hash to go on with
  795. LOGERROR("Update to nonexisting component " + ToString(combinedHash) + " in node " +
  796. node->GetName());
  797. component = node->createComponent(combinedHash);
  798. component->readNetUpdate(source, GetSubsystem<ResourceCache>(), info);
  799. component->interpolate(true);
  800. }
  801. }
  802. }
  803. updatedNodes.Insert(id);
  804. }
  805. break;
  806. }
  807. */
  808. }