RemoteToolsSystemComponent.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <RemoteToolsSystemComponent.h>
  9. #include <AzCore/Component/ComponentApplicationBus.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzCore/Serialization/EditContextConstants.inl>
  13. #include <AzCore/Serialization/ObjectStream.h>
  14. #include <AzNetworking/Framework/INetworking.h>
  15. #include <AzNetworking/Utilities/CidrAddress.h>
  16. #include <Source/AutoGen/RemoteTools.AutoPackets.h>
  17. #include <Source/AutoGen/RemoteTools.AutoPacketDispatcher.h>
  18. namespace RemoteTools
  19. {
  20. static constexpr const char* RemoteServerAddress = "127.0.0.1";
  21. // id for the local application
  22. static constexpr AZ::u32 SelfNetworkId = 0xFFFFFFFF;
  23. AZ_CVAR(uint16_t, remote_outbox_interval, 50, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The interval to process outbound messages.");
  24. AZ_CVAR(uint16_t, remote_join_interval, 1000, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The interval to attempt automatic connecitons.");
  25. void RemoteToolsSystemComponent::Reflect(AZ::ReflectContext* context)
  26. {
  27. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  28. {
  29. serialize->Class<RemoteToolsSystemComponent, AZ::Component>()
  30. ->Version(0)
  31. ;
  32. if (AZ::EditContext* ec = serialize->GetEditContext())
  33. {
  34. ec->Class<RemoteToolsSystemComponent>("RemoteTools", "[Description of functionality provided by this System Component]")
  35. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  36. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  37. ;
  38. }
  39. }
  40. }
  41. void RemoteToolsSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  42. {
  43. provided.push_back(AZ_CRC_CE("RemoteToolsService"));
  44. }
  45. void RemoteToolsSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  46. {
  47. incompatible.push_back(AZ_CRC_CE("RemoteToolsService"));
  48. }
  49. void RemoteToolsSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
  50. {
  51. ;
  52. }
  53. void RemoteToolsSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
  54. {
  55. ;
  56. }
  57. RemoteToolsSystemComponent::RemoteToolsSystemComponent()
  58. {
  59. #if defined(ENABLE_REMOTE_TOOLS)
  60. if (AzFramework::RemoteToolsInterface::Get() == nullptr)
  61. {
  62. AzFramework::RemoteToolsInterface::Register(this);
  63. }
  64. #endif
  65. }
  66. RemoteToolsSystemComponent::~RemoteToolsSystemComponent()
  67. {
  68. #if defined(ENABLE_REMOTE_TOOLS)
  69. if (AzFramework::RemoteToolsInterface::Get() == this)
  70. {
  71. AzFramework::RemoteToolsInterface::Unregister(this);
  72. }
  73. #endif
  74. }
  75. void RemoteToolsSystemComponent::Init()
  76. {
  77. }
  78. void RemoteToolsSystemComponent::Activate()
  79. {
  80. m_joinThread = AZStd::make_unique<RemoteToolsJoinThread>(remote_join_interval, this);
  81. AZ::SystemTickBus::Handler::BusConnect();
  82. }
  83. void RemoteToolsSystemComponent::Deactivate()
  84. {
  85. AZ::SystemTickBus::Handler::BusDisconnect();
  86. m_joinThread = nullptr;
  87. if (AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get())
  88. {
  89. for (auto registryIt = m_entryRegistry.begin(); registryIt != m_entryRegistry.end(); ++registryIt)
  90. {
  91. networking->DestroyNetworkInterface(registryIt->second.m_name);
  92. }
  93. }
  94. m_entryRegistry.clear();
  95. }
  96. void RemoteToolsSystemComponent::OnSystemTick()
  97. {
  98. if (!m_messageTypesToClearForNextTick.empty())
  99. {
  100. for (const AZ::Crc32& key : m_messageTypesToClearForNextTick)
  101. {
  102. ClearReceivedMessages(key);
  103. }
  104. m_messageTypesToClearForNextTick.clear();
  105. }
  106. // Join thread can stop itself, check if it needs to join
  107. if (m_joinThread && !m_joinThread->IsRunning())
  108. {
  109. m_joinThread->Join();
  110. }
  111. }
  112. void RemoteToolsSystemComponent::RegisterToolingServiceClient(AZ::Crc32 key, AZ::Name name, uint16_t port)
  113. {
  114. if (!m_entryRegistry.contains(key))
  115. {
  116. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  117. }
  118. m_entryRegistry[key].m_isHost = false;
  119. m_entryRegistry[key].m_name = name;
  120. m_entryRegistry[key].m_ip = AzNetworking::IpAddress(RemoteServerAddress, port, AzNetworking::ProtocolType::Tcp);
  121. if (AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get())
  122. {
  123. AzNetworking::INetworkInterface* netInterface = networking->CreateNetworkInterface(
  124. name, AzNetworking::ProtocolType::Tcp, AzNetworking::TrustZone::ExternalClientToServer, *this);
  125. netInterface->SetTimeoutMs(AZ::TimeMs(0));
  126. }
  127. if (m_joinThread && !m_joinThread->IsRunning())
  128. {
  129. m_joinThread->Join();
  130. m_joinThread->Start();
  131. }
  132. }
  133. void RemoteToolsSystemComponent::RegisterToolingServiceHost(AZ::Crc32 key, AZ::Name name, uint16_t port)
  134. {
  135. if (!m_entryRegistry.contains(key))
  136. {
  137. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  138. }
  139. m_entryRegistry[key].m_isHost = true;
  140. m_entryRegistry[key].m_name = name;
  141. AzFramework::RemoteToolsEndpointContainer::pair_iter_bool ret = m_entryRegistry[key].m_availableTargets.insert_key(key);
  142. AzFramework::RemoteToolsEndpointInfo& ti = ret.first->second;
  143. ti.SetInfo("Self", key, SelfNetworkId);
  144. if (AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get())
  145. {
  146. AzNetworking::INetworkInterface* netInterface = networking->CreateNetworkInterface(
  147. name, AzNetworking::ProtocolType::Tcp, AzNetworking::TrustZone::ExternalClientToServer, *this);
  148. netInterface->SetTimeoutMs(AZ::TimeMs(0));
  149. netInterface->Listen(port);
  150. }
  151. }
  152. const AzFramework::ReceivedRemoteToolsMessages* RemoteToolsSystemComponent::GetReceivedMessages(AZ::Crc32 key) const
  153. {
  154. if (m_inbox.contains(key))
  155. {
  156. return &m_inbox.at(key);
  157. }
  158. return nullptr;
  159. }
  160. void RemoteToolsSystemComponent::ClearReceivedMessages(AZ::Crc32 key)
  161. {
  162. if (m_inbox.contains(key))
  163. {
  164. m_inbox.at(key).clear();
  165. }
  166. }
  167. void RemoteToolsSystemComponent::ClearReceivedMessagesForNextTick(AZ::Crc32 key)
  168. {
  169. m_messageTypesToClearForNextTick.insert(key);
  170. }
  171. void RemoteToolsSystemComponent::RegisterRemoteToolsEndpointJoinedHandler(
  172. AZ::Crc32 key, AzFramework::RemoteToolsEndpointStatusEvent::Handler& handler)
  173. {
  174. if (!m_entryRegistry.contains(key))
  175. {
  176. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  177. }
  178. handler.Connect(m_entryRegistry[key].m_endpointJoinedEvent);
  179. }
  180. void RemoteToolsSystemComponent::RegisterRemoteToolsEndpointLeftHandler(
  181. AZ::Crc32 key, AzFramework::RemoteToolsEndpointStatusEvent::Handler& handler)
  182. {
  183. if (!m_entryRegistry.contains(key))
  184. {
  185. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  186. }
  187. handler.Connect(m_entryRegistry[key].m_endpointLeftEvent);
  188. }
  189. void RemoteToolsSystemComponent::RegisterRemoteToolsEndpointConnectedHandler(
  190. AZ::Crc32 key, AzFramework::RemoteToolsEndpointConnectedEvent::Handler& handler)
  191. {
  192. if (!m_entryRegistry.contains(key))
  193. {
  194. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  195. }
  196. handler.Connect(m_entryRegistry[key].m_endpointConnectedEvent);
  197. }
  198. void RemoteToolsSystemComponent::RegisterRemoteToolsEndpointChangedHandler(
  199. AZ::Crc32 key, AzFramework::RemoteToolsEndpointChangedEvent::Handler& handler)
  200. {
  201. if (!m_entryRegistry.contains(key))
  202. {
  203. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  204. }
  205. handler.Connect(m_entryRegistry[key].m_endpointChangedEvent);
  206. }
  207. void RemoteToolsSystemComponent::EnumTargetInfos(AZ::Crc32 key, AzFramework::RemoteToolsEndpointContainer& infos)
  208. {
  209. if (m_entryRegistry.contains(key))
  210. {
  211. infos = m_entryRegistry[key].m_availableTargets;
  212. }
  213. else
  214. {
  215. infos = AzFramework::RemoteToolsEndpointContainer();
  216. }
  217. }
  218. void RemoteToolsSystemComponent::SetDesiredEndpoint(AZ::Crc32 key, AZ::u32 desiredTargetID)
  219. {
  220. AZ_TracePrintf("RemoteToolsSystemComponent", "Set Target - %u", desiredTargetID);
  221. if (m_entryRegistry.contains(key))
  222. {
  223. RemoteToolsRegistryEntry& entry = m_entryRegistry[key];
  224. if (desiredTargetID != entry.m_lastTarget.GetPersistentId())
  225. {
  226. AzFramework::RemoteToolsEndpointInfo ti = GetEndpointInfo(key, desiredTargetID);
  227. AZ::u32 oldTargetID = entry.m_lastTarget.GetPersistentId();
  228. entry.m_lastTarget = ti;
  229. entry.m_tmpInboundBuffer.clear();
  230. entry.m_tmpInboundBufferPos = 0;
  231. m_entryRegistry[key].m_endpointChangedEvent.Signal(desiredTargetID, oldTargetID);
  232. if (ti.IsValid() && ti.IsOnline())
  233. {
  234. m_entryRegistry[key].m_endpointConnectedEvent.Signal(true);
  235. }
  236. else
  237. {
  238. m_entryRegistry[key].m_endpointConnectedEvent.Signal(false);
  239. }
  240. }
  241. }
  242. }
  243. void RemoteToolsSystemComponent::SetDesiredEndpointInfo(AZ::Crc32 key, const AzFramework::RemoteToolsEndpointInfo& targetInfo)
  244. {
  245. SetDesiredEndpoint(key, targetInfo.GetPersistentId());
  246. }
  247. AzFramework::RemoteToolsEndpointInfo RemoteToolsSystemComponent::GetDesiredEndpoint(AZ::Crc32 key)
  248. {
  249. if (m_entryRegistry.contains(key))
  250. {
  251. return m_entryRegistry[key].m_lastTarget;
  252. }
  253. return AzFramework::RemoteToolsEndpointInfo(); // return an invalid target info.
  254. }
  255. AzFramework::RemoteToolsEndpointInfo RemoteToolsSystemComponent::GetEndpointInfo(AZ::Crc32 key, AZ::u32 desiredTargetID)
  256. {
  257. if (m_entryRegistry.contains(key))
  258. {
  259. AzFramework::RemoteToolsEndpointContainer container = m_entryRegistry[key].m_availableTargets;
  260. AzFramework::RemoteToolsEndpointContainer::const_iterator finder = container.find(desiredTargetID);
  261. if (finder != container.end())
  262. {
  263. return finder->second;
  264. }
  265. }
  266. return AzFramework::RemoteToolsEndpointInfo(); // return an invalid target info.
  267. }
  268. bool RemoteToolsSystemComponent::IsEndpointOnline(AZ::Crc32 key, AZ::u32 desiredTargetID)
  269. {
  270. if (m_entryRegistry.contains(key))
  271. {
  272. AzFramework::RemoteToolsEndpointContainer container = m_entryRegistry[key].m_availableTargets;
  273. AzFramework::RemoteToolsEndpointContainer::const_iterator finder = container.find(desiredTargetID);
  274. if (finder != container.end())
  275. {
  276. return finder->second.IsOnline();
  277. }
  278. }
  279. return false;
  280. }
  281. void RemoteToolsSystemComponent::SendRemoteToolsMessage(
  282. const AzFramework::RemoteToolsEndpointInfo& target, const AzFramework::RemoteToolsMessage& msg)
  283. {
  284. AZ::SerializeContext* serializeContext = nullptr;
  285. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  286. AZStd::vector<char, AZ::OSStdAllocator> msgBuffer;
  287. AZ::IO::ByteContainerStream<AZStd::vector<char, AZ::OSStdAllocator>> outMsg(&msgBuffer);
  288. AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&outMsg, *serializeContext, AZ::ObjectStream::ST_BINARY);
  289. objStream->WriteClass(&msg);
  290. if (!objStream->Finalize())
  291. {
  292. AZ_Assert(false, "ObjectStream failed to serialize outbound TmMsg!");
  293. }
  294. const size_t customBlobSize = msg.GetCustomBlobSize();
  295. if (customBlobSize > 0)
  296. {
  297. outMsg.Write(customBlobSize, msg.GetCustomBlob().data());
  298. }
  299. // Messages targeted at our own application are also serialized/deserialized then moved onto the inbox
  300. const size_t totalSize = msgBuffer.size();
  301. if (target.IsSelf())
  302. {
  303. AZStd::vector<AZStd::byte> buffer;
  304. buffer.reserve(static_cast<uint32_t>(totalSize));
  305. memcpy(buffer.begin(), msgBuffer.data(), totalSize);
  306. AzFramework::RemoteToolsMessage* result = DeserializeMessage(target.GetPersistentId(), buffer, static_cast<uint32_t>(totalSize));
  307. m_inboxMutex.lock();
  308. if (!m_inbox[target.GetPersistentId()].full())
  309. {
  310. m_inbox[target.GetPersistentId()].push_back(result);
  311. }
  312. else
  313. {
  314. // As no network latency and not bound to framerate with local messages, possible to overflow the inbox size
  315. AZ_Error("RemoteTool", false, "Inbox is full, a local message got skipped on %d channel", target.GetPersistentId());
  316. delete result;
  317. }
  318. m_inboxMutex.unlock();
  319. return;
  320. }
  321. AzNetworking::INetworkInterface* networkInterface =
  322. AZ::Interface<AzNetworking::INetworking>::Get()->RetrieveNetworkInterface(
  323. AZ::Name(m_entryRegistry[target.GetPersistentId()].m_name));
  324. auto connectionId = static_cast<AzNetworking::ConnectionId>(target.GetNetworkId());
  325. const uint8_t* outBuffer = reinterpret_cast<const uint8_t*>(msgBuffer.data());
  326. size_t outSize = totalSize;
  327. while (outSize > 0 && networkInterface != nullptr)
  328. {
  329. // Fragment the message into RemoteToolsMessageBuffer packet sized chunks and send
  330. size_t bufferSize = AZStd::min(outSize, aznumeric_cast<size_t>(RemoteToolsBufferSize));
  331. RemoteToolsPackets::RemoteToolsMessage tmPacket;
  332. tmPacket.SetPersistentId(target.GetPersistentId());
  333. tmPacket.SetSize(aznumeric_cast<uint32_t>(totalSize));
  334. RemoteToolsMessageBuffer encodingBuffer;
  335. encodingBuffer.CopyValues(outBuffer + (totalSize - outSize), bufferSize);
  336. tmPacket.SetMessageBuffer(encodingBuffer);
  337. if (!networkInterface->SendReliablePacket(connectionId, tmPacket))
  338. {
  339. AZ_Error("RemoteToolsSystemComponent", false, "SendReliablePacket failed with remaining bytes %zu of %zu.\n", outSize, totalSize);
  340. break;
  341. }
  342. outSize -= bufferSize;
  343. }
  344. }
  345. void RemoteToolsSystemComponent::OnMessageParsed(
  346. AzFramework::RemoteToolsMessage** ppMsg, void* classPtr, const AZ::Uuid& classId, const AZ::SerializeContext* sc)
  347. {
  348. // Check that classPtr is a RemoteToolsMessage
  349. AZ_Assert(*ppMsg == nullptr, "ppMsg is already set! are we deserializing multiple messages in one call?");
  350. *ppMsg = sc->Cast<AzFramework::RemoteToolsMessage*>(classPtr, classId);
  351. AZ_Assert(*ppMsg, "Failed to downcast msg pointer to a TmMsg. Is RTTI and reflection set up properly?");
  352. }
  353. bool RemoteToolsSystemComponent::HandleRequest(
  354. AzNetworking::IConnection* connection,
  355. [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
  356. const RemoteToolsPackets::RemoteToolsConnect& packet)
  357. {
  358. AZ::Crc32 key = packet.GetPersistentId();
  359. if (m_entryRegistry.contains(key))
  360. {
  361. const uint32_t persistentId = packet.GetPersistentId();
  362. AzFramework::RemoteToolsEndpointContainer::pair_iter_bool ret =
  363. m_entryRegistry[key].m_availableTargets.insert_key(persistentId);
  364. AzFramework::RemoteToolsEndpointInfo& ti = ret.first->second;
  365. ti.SetInfo(packet.GetDisplayName(), persistentId, static_cast<uint32_t>(connection->GetConnectionId()));
  366. m_entryRegistry[key].m_endpointJoinedEvent.Signal(ti);
  367. }
  368. return true;
  369. }
  370. bool RemoteToolsSystemComponent::HandleRequest(
  371. AzNetworking::IConnection* connection,
  372. [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
  373. [[maybe_unused]] const RemoteToolsPackets::RemoteToolsMessage& packet)
  374. {
  375. const AZ::Crc32 key = packet.GetPersistentId();
  376. // Receive
  377. if (connection->GetConnectionRole() == AzNetworking::ConnectionRole::Acceptor
  378. && static_cast<uint32_t>(connection->GetConnectionId()) != m_entryRegistry[key].m_lastTarget.GetNetworkId())
  379. {
  380. // Listener should route traffic based on selected target
  381. return true;
  382. }
  383. if (!m_entryRegistry.contains(key))
  384. {
  385. m_entryRegistry[key] = RemoteToolsRegistryEntry();
  386. }
  387. // If we're a client, set the host to our desired target
  388. if (connection->GetConnectionRole() == AzNetworking::ConnectionRole::Connector)
  389. {
  390. if (GetEndpointInfo(key, packet.GetPersistentId()).GetPersistentId() == 0)
  391. {
  392. AzFramework::RemoteToolsEndpointContainer::pair_iter_bool ret =
  393. m_entryRegistry[key].m_availableTargets.insert_key(packet.GetPersistentId());
  394. AzFramework::RemoteToolsEndpointInfo& ti = ret.first->second;
  395. ti.SetInfo("Host", packet.GetPersistentId(), static_cast<uint32_t>(connection->GetConnectionId()));
  396. m_entryRegistry[key].m_endpointJoinedEvent.Signal(ti);
  397. }
  398. if (GetDesiredEndpoint(key).GetPersistentId() != packet.GetPersistentId())
  399. {
  400. SetDesiredEndpoint(key, packet.GetPersistentId());
  401. }
  402. }
  403. const uint32_t totalBufferSize = packet.GetSize();
  404. // Messages can be larger than the size of a packet so reserve a buffer for the total message size
  405. if (m_entryRegistry[key].m_tmpInboundBufferPos == 0)
  406. {
  407. m_entryRegistry[key].m_tmpInboundBuffer.reserve(totalBufferSize);
  408. }
  409. // Read as much data as the packet can include and append it to the buffer
  410. const uint32_t readSize = AZStd::min(totalBufferSize - m_entryRegistry[key].m_tmpInboundBufferPos, RemoteToolsBufferSize);
  411. memcpy(
  412. m_entryRegistry[key].m_tmpInboundBuffer.begin() + m_entryRegistry[key].m_tmpInboundBufferPos,
  413. packet.GetMessageBuffer().GetBuffer(), readSize);
  414. m_entryRegistry[key].m_tmpInboundBufferPos += readSize;
  415. if (m_entryRegistry[key].m_tmpInboundBufferPos == totalBufferSize)
  416. {
  417. AzFramework::RemoteToolsMessage* msg = DeserializeMessage(key, m_entryRegistry[key].m_tmpInboundBuffer, totalBufferSize);
  418. m_entryRegistry[key].m_tmpInboundBuffer.clear();
  419. m_entryRegistry[key].m_tmpInboundBufferPos = 0;
  420. // Append to the inbox for handling
  421. if (msg)
  422. {
  423. m_inboxMutex.lock();
  424. m_inbox[msg->GetSenderTargetId()].push_back(msg);
  425. m_inboxMutex.unlock();
  426. }
  427. }
  428. return true;
  429. }
  430. AzNetworking::ConnectResult RemoteToolsSystemComponent::ValidateConnect(
  431. [[maybe_unused]] const AzNetworking::IpAddress& remoteAddress,
  432. [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
  433. [[maybe_unused]] AzNetworking::ISerializer& serializer)
  434. {
  435. return AzNetworking::ConnectResult::Accepted;
  436. }
  437. void RemoteToolsSystemComponent::OnConnect([[maybe_unused]] AzNetworking::IConnection* connection)
  438. {
  439. // Invoked when a tooling connection is established, handshake logic is handled via ToolingConnect message
  440. ;
  441. }
  442. AzNetworking::PacketDispatchResult RemoteToolsSystemComponent::OnPacketReceived(
  443. AzNetworking::IConnection* connection,
  444. [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
  445. [[maybe_unused]] AzNetworking::ISerializer& serializer)
  446. {
  447. return RemoteToolsPackets::DispatchPacket(connection, packetHeader, serializer, *this);
  448. }
  449. void RemoteToolsSystemComponent::OnPacketLost(
  450. [[maybe_unused]] AzNetworking::IConnection* connection, [[maybe_unused]] AzNetworking::PacketId packetId)
  451. {
  452. ;
  453. }
  454. void RemoteToolsSystemComponent::OnDisconnect(
  455. [[maybe_unused]] AzNetworking::IConnection* connection,
  456. [[maybe_unused]] AzNetworking::DisconnectReason reason,
  457. [[maybe_unused]] AzNetworking::TerminationEndpoint endpoint)
  458. {
  459. // If our desired target has left the network, flag it and notify listeners
  460. if (reason != AzNetworking::DisconnectReason::ConnectionRejected)
  461. {
  462. for (auto registryIt = m_entryRegistry.begin(); registryIt != m_entryRegistry.end(); ++registryIt)
  463. {
  464. AzFramework::RemoteToolsEndpointContainer& container = registryIt->second.m_availableTargets;
  465. for (auto endpointIt = container.begin(); endpointIt != container.end(); ++endpointIt)
  466. {
  467. if (endpointIt->second.GetNetworkId() == static_cast<AZ::u32>(connection->GetConnectionId()))
  468. {
  469. AzFramework::RemoteToolsEndpointInfo ti = endpointIt->second;
  470. registryIt->second.m_endpointLeftEvent.Signal(ti);
  471. container.extract(endpointIt);
  472. break;
  473. }
  474. }
  475. }
  476. }
  477. if (m_joinThread && !m_joinThread->IsRunning())
  478. {
  479. m_joinThread->Join();
  480. m_joinThread->Start();
  481. }
  482. }
  483. AzFramework::RemoteToolsMessage* RemoteToolsSystemComponent::DeserializeMessage(
  484. const AZ::Crc32& key, AZStd::vector<AZStd::byte>& buffer, const uint32_t& totalBufferSize)
  485. {
  486. AZ::SerializeContext* serializeContext = nullptr;
  487. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  488. // Deserialize the complete buffer
  489. AZ::IO::MemoryStream msgBuffer(buffer.data(), totalBufferSize, totalBufferSize);
  490. AzFramework::RemoteToolsMessage* msg = nullptr;
  491. AZ::ObjectStream::ClassReadyCB readyCB(AZStd::bind(
  492. &RemoteToolsSystemComponent::OnMessageParsed, this, &msg, AZStd::placeholders::_1, AZStd::placeholders::_2,
  493. AZStd::placeholders::_3));
  494. AZ::ObjectStream::LoadBlocking(
  495. &msgBuffer, *serializeContext, readyCB,
  496. AZ::ObjectStream::FilterDescriptor(nullptr, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES));
  497. if (msg)
  498. {
  499. if (msg->GetCustomBlobSize() > 0)
  500. {
  501. void* blob = azmalloc(msg->GetCustomBlobSize(), 1, AZ::OSAllocator);
  502. msgBuffer.Read(msg->GetCustomBlobSize(), blob);
  503. msg->AddCustomBlob(blob, msg->GetCustomBlobSize(), true);
  504. }
  505. msg->SetSenderTargetId(key);
  506. }
  507. return msg;
  508. }
  509. } // namespace RemoteTools