SimulationEntitiesManager.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  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 "SimulationEntitiesManager.h"
  9. #include <SimulationInterfaces/SimulationInterfacesTypeIds.h>
  10. #include "CommonUtilities.h"
  11. #include "ConsoleCommands.inl"
  12. #include <AzCore/Asset/AssetManager.h>
  13. #include <AzCore/Asset/AssetManagerBus.h>
  14. #include <AzCore/Component/ComponentApplicationBus.h>
  15. #include <AzCore/Component/TransformBus.h>
  16. #include <AzCore/Console/IConsole.h>
  17. #include <AzCore/Serialization/SerializeContext.h>
  18. #include <AzCore/std/string/regex.h>
  19. #include <AzFramework/Components/TransformComponent.h>
  20. #include <AzFramework/Physics/PhysicsSystem.h>
  21. #include <AzFramework/Physics/RigidBodyBus.h>
  22. #include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
  23. #include <AzFramework/Spawnable/Spawnable.h>
  24. #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
  25. namespace SimulationInterfaces
  26. {
  27. void SetRigidBodyVelocities(AzPhysics::RigidBody* rigidBody, const EntityState& state)
  28. {
  29. if (!state.m_twist_angular.IsClose(AZ::Vector3::CreateZero(), AZ::Constants::FloatEpsilon))
  30. {
  31. // get transform
  32. AZ::Vector3 angularVelWorld = rigidBody->GetTransform().TransformVector(state.m_twist_angular);
  33. rigidBody->SetAngularVelocity(angularVelWorld);
  34. }
  35. if (!state.m_twist_linear.IsClose(AZ::Vector3::CreateZero(), AZ::Constants::FloatEpsilon))
  36. {
  37. // get transform
  38. AZ::Vector3 linearVelWorld = rigidBody->GetTransform().TransformVector(state.m_twist_linear);
  39. rigidBody->SetAngularVelocity(linearVelWorld);
  40. }
  41. }
  42. AZ_COMPONENT_IMPL(SimulationEntitiesManager, "SimulationEntitiesManager", SimulationEntitiesManagerTypeId);
  43. void SimulationEntitiesManager::Reflect(AZ::ReflectContext* context)
  44. {
  45. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  46. {
  47. serializeContext->Class<SimulationEntitiesManager, AZ::Component>()->Version(0);
  48. }
  49. }
  50. void SimulationEntitiesManager::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  51. {
  52. provided.push_back(AZ_CRC_CE("SimulationInterfacesService"));
  53. }
  54. void SimulationEntitiesManager::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  55. {
  56. incompatible.push_back(AZ_CRC_CE("SimulationInterfacesService"));
  57. }
  58. void SimulationEntitiesManager::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
  59. {
  60. required.push_back(AZ_CRC_CE("AssetCatalogService"));
  61. }
  62. void SimulationEntitiesManager::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
  63. {
  64. dependent.push_back(AZ_CRC_CE("PhysicsService"));
  65. }
  66. SimulationEntitiesManager::SimulationEntitiesManager()
  67. {
  68. if (SimulationEntityManagerInterface::Get() == nullptr)
  69. {
  70. SimulationEntityManagerInterface::Register(this);
  71. }
  72. }
  73. SimulationEntitiesManager::~SimulationEntitiesManager()
  74. {
  75. if (SimulationEntityManagerInterface::Get() == this)
  76. {
  77. SimulationEntityManagerInterface::Unregister(this);
  78. }
  79. }
  80. void SimulationEntitiesManager::Init()
  81. {
  82. }
  83. AzPhysics::Scene* GetSceneHelper(AzPhysics::SceneHandle sceneHandle)
  84. {
  85. AzPhysics::SystemInterface* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
  86. AZ_Assert(physicsSystem, "Physics system is not available.");
  87. AzPhysics::Scene* scene = physicsSystem->GetScene(sceneHandle);
  88. return scene;
  89. }
  90. void SimulationEntitiesManager::Activate()
  91. {
  92. m_simulationBodyAddedHandler = AzPhysics::SceneEvents::OnSimulationBodyAdded::Handler(
  93. [this](AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle)
  94. {
  95. auto* scene = GetSceneHelper(sceneHandle);
  96. if (scene == nullptr)
  97. {
  98. return;
  99. }
  100. auto* body = scene->GetSimulatedBodyFromHandle(bodyHandle);
  101. AZ_Assert(body, "Simulated body is not available.");
  102. auto* rigidBody = azdynamic_cast<AzPhysics::RigidBody*>(body);
  103. if (rigidBody != nullptr)
  104. {
  105. [[maybe_unused]] auto shapeCount = rigidBody->GetShapeCount();
  106. AZ_Warning(
  107. "SimulationInterfaces",
  108. shapeCount > 0,
  109. "Entity %s has no collider shapes, it won't be available by bound search",
  110. rigidBody->GetEntityId().ToString().c_str());
  111. }
  112. const AZ::EntityId entityId = body->GetEntityId();
  113. AZ::Entity* entity = nullptr;
  114. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
  115. AZ_Assert(entity, "Entity is not available.");
  116. // check if entity is not spawned by this component
  117. const auto ticketId = entity->GetEntitySpawnTicketId();
  118. AZStd::string proposedName{};
  119. // check if ticket is in the unregistered list
  120. auto spawnData = m_spawnCompletedCallbacks.find(ticketId);
  121. if (spawnData != m_spawnCompletedCallbacks.end())
  122. {
  123. proposedName = spawnData->second.m_userProposedName;
  124. }
  125. const AZStd::string registeredName = this->AddSimulatedEntity(entityId, proposedName);
  126. // call the callback
  127. if (spawnData != m_spawnCompletedCallbacks.end())
  128. {
  129. // call and remove the callback
  130. spawnData->second.m_completedCb(AZ::Success(registeredName));
  131. m_spawnCompletedCallbacks.erase(spawnData);
  132. }
  133. });
  134. m_simulationBodyRemovedHandler = AzPhysics::SceneEvents::OnSimulationBodyRemoved::Handler(
  135. [this](AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle)
  136. {
  137. auto* scene = GetSceneHelper(sceneHandle);
  138. if (scene == nullptr)
  139. {
  140. return;
  141. }
  142. const auto* body = scene->GetSimulatedBodyFromHandle(bodyHandle);
  143. AZ_Assert(body, "Simulated body is not available.");
  144. const AZ::EntityId entityId = body->GetEntityId();
  145. // remove simulated entity
  146. this->RemoveSimulatedEntity(entityId);
  147. });
  148. m_sceneAddedHandler = AzPhysics::SystemEvents::OnSceneAddedEvent::Handler(
  149. [this](AzPhysics::SceneHandle sceneHandle)
  150. {
  151. AZ_Warning("SimulationInterfaces", m_physicsScenesHandle == AzPhysics::InvalidSceneHandle, "Hmm, we already have a scene");
  152. auto* scene = GetSceneHelper(sceneHandle);
  153. AZ_Assert(scene, "Scene is not available.");
  154. if (scene == nullptr)
  155. {
  156. return;
  157. }
  158. scene->RegisterSimulationBodyAddedHandler(m_simulationBodyAddedHandler);
  159. scene->RegisterSimulationBodyRemovedHandler(m_simulationBodyRemovedHandler);
  160. AZ_Printf("SimulationInterfaces", "Registered simulation body added handler\n");
  161. m_physicsScenesHandle = sceneHandle;
  162. });
  163. m_sceneRemovedHandler = AzPhysics::SystemEvents::OnSceneRemovedEvent::Handler(
  164. [this](AzPhysics::SceneHandle sceneHandle)
  165. {
  166. if (m_physicsScenesHandle == sceneHandle)
  167. {
  168. m_entityIdToSimulatedEntityMap.clear();
  169. m_simulatedEntityToEntityIdMap.clear();
  170. m_simulationBodyAddedHandler.Disconnect();
  171. m_simulationBodyRemovedHandler.Disconnect();
  172. m_physicsScenesHandle = AzPhysics::InvalidSceneHandle;
  173. }
  174. });
  175. AzPhysics::SystemInterface* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
  176. if (physicsSystem)
  177. {
  178. physicsSystem->RegisterSceneAddedEvent(m_sceneAddedHandler);
  179. physicsSystem->RegisterSceneRemovedEvent(m_sceneRemovedHandler);
  180. SimulationEntityManagerRequestBus::Handler::BusConnect();
  181. }
  182. }
  183. void SimulationEntitiesManager::Deactivate()
  184. {
  185. SimulationEntityManagerRequestBus::Handler::BusDisconnect();
  186. if (m_simulationBodyAddedHandler.IsConnected())
  187. {
  188. m_simulationBodyAddedHandler.Disconnect();
  189. }
  190. if (m_simulationBodyRemovedHandler.IsConnected())
  191. {
  192. m_simulationBodyRemovedHandler.Disconnect();
  193. }
  194. m_physicsScenesHandle = AzPhysics::InvalidSceneHandle;
  195. if (m_sceneAddedHandler.IsConnected())
  196. {
  197. m_sceneAddedHandler.Disconnect();
  198. }
  199. if (m_sceneAddedHandler.IsConnected())
  200. {
  201. m_sceneAddedHandler.Disconnect();
  202. }
  203. }
  204. AZStd::string SimulationEntitiesManager::AddSimulatedEntity(AZ::EntityId entityId, const AZStd::string& userProposedName)
  205. {
  206. if (!entityId.IsValid())
  207. {
  208. return "";
  209. }
  210. // check if entity is already registered
  211. auto findIt = m_entityIdToSimulatedEntityMap.find(entityId);
  212. if (findIt != m_entityIdToSimulatedEntityMap.end())
  213. {
  214. return findIt->second;
  215. }
  216. // register entity under unique name
  217. AZStd::string simulatedEntityName = GetSimulatedEntityName(entityId, userProposedName);
  218. m_simulatedEntityToEntityIdMap[simulatedEntityName] = entityId;
  219. m_entityIdToSimulatedEntityMap[entityId] = simulatedEntityName;
  220. AZ_Printf("SimulationInterfaces", "Registered entity %s\n", simulatedEntityName.c_str());
  221. return simulatedEntityName;
  222. }
  223. void SimulationEntitiesManager::RemoveSimulatedEntity(AZ::EntityId entityId)
  224. {
  225. auto findIt = m_entityIdToSimulatedEntityMap.find(entityId);
  226. if (findIt != m_entityIdToSimulatedEntityMap.end())
  227. {
  228. const auto& simulatedEntityName = findIt->second;
  229. m_entityIdToSimulatedEntityMap.erase(findIt);
  230. m_simulatedEntityToEntityIdMap.erase(simulatedEntityName);
  231. }
  232. }
  233. AZ::Outcome<EntityNameList, FailedResult> SimulationEntitiesManager::GetEntities(const EntityFilters& filter)
  234. {
  235. if (!filter.m_tags_filter.m_tags.empty())
  236. {
  237. AZ_Warning("SimulationInterfaces", false, "Tags filter is not implemented yet");
  238. return AZ::Failure(FailedResult(ErrorCode::RESULT_FEATURE_UNSUPPORTED, "Tags filter is not implemented yet"));
  239. }
  240. const bool reFilter = !filter.m_filter.empty();
  241. const bool shapeCastFilter = filter.m_bounds_shape != nullptr;
  242. AZStd::vector<AZStd::string> entities;
  243. if (!shapeCastFilter)
  244. {
  245. // get all entities from the map
  246. entities.reserve(m_entityIdToSimulatedEntityMap.size());
  247. AZStd::transform(
  248. m_entityIdToSimulatedEntityMap.begin(),
  249. m_entityIdToSimulatedEntityMap.end(),
  250. AZStd::back_inserter(entities),
  251. [](const auto& pair)
  252. {
  253. return pair.second;
  254. });
  255. }
  256. else
  257. {
  258. auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  259. AZ_Assert(sceneInterface, "Physics scene interface is not available.");
  260. if (m_physicsScenesHandle == AzPhysics::InvalidSceneHandle)
  261. {
  262. return AZ::Failure(FailedResult(ErrorCode::RESULT_OPERATION_FAILED, "Physics scene interface is not available."));
  263. }
  264. AzPhysics::OverlapRequest request;
  265. request.m_shapeConfiguration = filter.m_bounds_shape;
  266. request.m_pose = filter.m_bounds_pose;
  267. request.m_maxResults = AZStd::numeric_limits<AZ::u32>::max();
  268. AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(m_physicsScenesHandle, &request);
  269. for (const auto& hit : result.m_hits)
  270. {
  271. const AZ::EntityId entityId = hit.m_entityId;
  272. auto findIt = m_entityIdToSimulatedEntityMap.find(entityId);
  273. if (findIt != m_entityIdToSimulatedEntityMap.end())
  274. {
  275. entities.push_back(findIt->second);
  276. }
  277. }
  278. }
  279. if (reFilter)
  280. {
  281. const AZStd::vector<AZStd::string> prefilteredEntities = AZStd::move(entities);
  282. entities.clear();
  283. const AZStd::regex regex(filter.m_filter);
  284. if (!regex.Valid())
  285. {
  286. AZ_Warning("SimulationInterfaces", false, "Invalid regex filter");
  287. return AZ::Failure(FailedResult(ErrorCode::RESULT_NOT_FOUND, "Invalid regex filter"));
  288. }
  289. AZStd::ranges::copy_if(
  290. prefilteredEntities,
  291. AZStd::back_inserter(entities),
  292. [&regex](const AZStd::string& entityName)
  293. {
  294. return AZStd::regex_search(entityName, regex);
  295. });
  296. }
  297. return AZ::Success(entities);
  298. }
  299. AZ::Outcome<EntityState, FailedResult> SimulationEntitiesManager::GetEntityState(const AZStd::string& name)
  300. {
  301. const auto findIt = m_simulatedEntityToEntityIdMap.find(name);
  302. if (findIt == m_simulatedEntityToEntityIdMap.end())
  303. {
  304. AZ_Warning("SimulationInterfaces", findIt != m_simulatedEntityToEntityIdMap.end(), "Entity %s not found", name.c_str());
  305. return AZ::Failure(FailedResult(ErrorCode::RESULT_NOT_FOUND, "Entity not found"));
  306. }
  307. EntityState entityState{};
  308. const AZ::EntityId entityId = findIt->second;
  309. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  310. AZ::TransformBus::EventResult(entityState.m_pose, entityId, &AZ::TransformBus::Events::GetWorldTM);
  311. AZ::Vector3 linearVelocity = AZ::Vector3::CreateZero();
  312. Physics::RigidBodyRequestBus::EventResult(linearVelocity, entityId, &Physics::RigidBodyRequests::GetLinearVelocity);
  313. AZ::Vector3 angularVelocity = AZ::Vector3::CreateZero();
  314. Physics::RigidBodyRequestBus::EventResult(angularVelocity, entityId, &Physics::RigidBodyRequests::GetAngularVelocity);
  315. // transform linear and angular velocities to entity frame
  316. const AZ::Transform entityTransformInv = entityState.m_pose.GetInverse();
  317. entityState.m_twist_linear = entityTransformInv.TransformVector(linearVelocity);
  318. entityState.m_twist_angular = entityTransformInv.TransformVector(angularVelocity);
  319. return AZ::Success(entityState);
  320. }
  321. AZ::Outcome<MultipleEntitiesStates, FailedResult> SimulationEntitiesManager::GetEntitiesStates(const EntityFilters& filter)
  322. {
  323. if (!filter.m_tags_filter.m_tags.empty())
  324. {
  325. AZ_Warning("SimulationInterfaces", false, "Tags filter is not implemented yet");
  326. return AZ::Failure(FailedResult(ErrorCode::RESULT_FEATURE_UNSUPPORTED, "Tags filter is not implemented yet"));
  327. }
  328. MultipleEntitiesStates entitiesStates;
  329. const auto& entities = GetEntities(filter);
  330. if (!entities.IsSuccess())
  331. {
  332. return AZ::Failure(entities.GetError());
  333. }
  334. for (const auto& entity : entities.GetValue())
  335. {
  336. auto state = GetEntityState(entity);
  337. if (!state.IsSuccess())
  338. {
  339. return AZ::Failure(state.GetError());
  340. }
  341. entitiesStates.emplace(AZStd::make_pair(entity, state.GetValue()));
  342. }
  343. return entitiesStates;
  344. }
  345. AZ::Outcome<void, FailedResult> SimulationEntitiesManager::SetEntityState(const AZStd::string& name, const EntityState& state)
  346. {
  347. const auto findIt = m_simulatedEntityToEntityIdMap.find(name);
  348. if (findIt == m_simulatedEntityToEntityIdMap.end())
  349. {
  350. AZ_Warning("SimulationInterfaces", false, "Entity %s not found", name.c_str());
  351. return AZ::Failure(FailedResult(ErrorCode::RESULT_NOT_FOUND, "Entity not found"));
  352. }
  353. const AZ::EntityId entityId = findIt->second;
  354. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  355. // get entity and all descendants
  356. AZStd::vector<AZ::EntityId> entityAndDescendants;
  357. AZ::TransformBus::EventResult(entityAndDescendants, entityId, &AZ::TransformBus::Events::GetEntityAndAllDescendants);
  358. if (state.m_pose.IsOrthogonal())
  359. {
  360. // disable simulation for all entities
  361. AZStd::map<AZ::EntityId, AZ::Transform> entityTransforms;
  362. for (const auto& descendant : entityAndDescendants)
  363. {
  364. // get name
  365. AZStd::string entityName = "Unknown";
  366. AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, descendant);
  367. AZ_Printf("SimulationInterfaces", "Disable physics for entity %s\n", entityName.c_str());
  368. Physics::RigidBodyRequestBus::Event(descendant, &Physics::RigidBodyRequests::DisablePhysics);
  369. }
  370. AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalTM, state.m_pose);
  371. for (const auto& descendant : entityAndDescendants)
  372. {
  373. Physics::RigidBodyRequestBus::Event(descendant, &Physics::RigidBodyRequests::EnablePhysics);
  374. Physics::RigidBodyRequestBus::Event(descendant, &Physics::RigidBodyRequests::SetAngularVelocity, AZ::Vector3::CreateZero());
  375. Physics::RigidBodyRequestBus::Event(descendant, &Physics::RigidBodyRequests::SetLinearVelocity, AZ::Vector3::CreateZero());
  376. }
  377. }
  378. if (!state.m_twist_linear.IsZero(AZ::Constants::FloatEpsilon) || !state.m_twist_angular.IsZero(AZ::Constants::FloatEpsilon))
  379. {
  380. // get rigid body
  381. AzPhysics::RigidBody* rigidBody = nullptr;
  382. Physics::RigidBodyRequestBus::EventResult(rigidBody, entityId, &Physics::RigidBodyRequests::GetRigidBody);
  383. if (rigidBody != nullptr)
  384. {
  385. SetRigidBodyVelocities(rigidBody, state);
  386. }
  387. }
  388. return AZ::Success();
  389. }
  390. void SimulationEntitiesManager::DeleteEntity(const AZStd::string& name, DeletionCompletedCb completedCb)
  391. {
  392. const auto findIt = m_simulatedEntityToEntityIdMap.find(name);
  393. if (findIt == m_simulatedEntityToEntityIdMap.end())
  394. {
  395. completedCb(AZ::Failure(FailedResult(ErrorCode::RESULT_NOT_FOUND, "Entity not found")));
  396. }
  397. const AZ::EntityId entityId = findIt->second;
  398. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  399. // get entity
  400. AZ::Entity* entity = nullptr;
  401. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
  402. AZ_Assert(entity, "Entity is not available.");
  403. // check if entity is spawned by this component
  404. const auto ticketId = entity->GetEntitySpawnTicketId();
  405. if (m_spawnedTickets.find(ticketId) != m_spawnedTickets.end())
  406. {
  407. // remove the ticket
  408. //m_spawnedTickets.erase(ticketId);
  409. /// get spawner
  410. auto spawner = AZ::Interface<AzFramework::SpawnableEntitiesDefinition>::Get();
  411. AZ_Assert(spawner, "SpawnableEntitiesDefinition is not available.");
  412. // get ticket
  413. auto ticket = m_spawnedTickets[ticketId];
  414. // remove ticket
  415. AzFramework::DespawnAllEntitiesOptionalArgs optionalArgs;
  416. optionalArgs.m_completionCallback = [this, completedCb](AzFramework::EntitySpawnTicket::Id ticketId)
  417. {
  418. m_spawnedTickets.erase(ticketId);
  419. completedCb(AZ::Success());
  420. };
  421. spawner->DespawnAllEntities(ticket, optionalArgs);
  422. }
  423. else
  424. {
  425. const auto msg = AZStd::string::format("Entity %s was not spawned by this component, wont delete it", name.c_str());
  426. completedCb(AZ::Failure(FailedResult(ErrorCode::RESULT_OPERATION_FAILED, msg)));
  427. }
  428. #ifdef POTENTIALY_UNSAFE
  429. if (findIt != m_simulatedEntityToEntityIdMap.end())
  430. {
  431. const AZ::EntityId entityId = findIt->second;
  432. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  433. // get all descendants
  434. AZStd::vector<AZ::EntityId> entityAndDescendants;
  435. AZ::TransformBus::EventResult(entityAndDescendants, entityId, &AZ::TransformBus::Events::GetEntityAndAllDescendants);
  436. for (const auto& descendant : entityAndDescendants)
  437. {
  438. // I am not sure if this is the safe way to delete an entity
  439. AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, descendant);
  440. }
  441. return true;
  442. }
  443. #endif
  444. }
  445. AZ::Outcome<SpawnableList, FailedResult> SimulationEntitiesManager::GetSpawnables()
  446. {
  447. AZStd::vector<Spawnable> spawnables;
  448. const auto enumCallback = [&spawnables](const AZ::Data::AssetId assetId, const AZ::Data::AssetInfo& assetInfo)
  449. {
  450. bool isSpawnable = false;
  451. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  452. isSpawnable, &AZ::Data::AssetCatalogRequests::DoesAssetIdMatchWildcardPattern, assetId, "*.spawnable");
  453. if (isSpawnable)
  454. {
  455. Spawnable spawnable;
  456. spawnable.m_uri = Utils::RelPathToUri(assetInfo.m_relativePath);
  457. spawnables.push_back(spawnable);
  458. }
  459. };
  460. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::EnumerateAssets, nullptr, enumCallback, nullptr);
  461. return AZ::Success(spawnables);
  462. }
  463. void SimulationEntitiesManager::SpawnEntity(
  464. const AZStd::string& name,
  465. const AZStd::string& uri,
  466. const AZStd::string& entityNamespace,
  467. const AZ::Transform& initialPose,
  468. SpawnCompletedCb completedCb)
  469. {
  470. // get rel path from uri
  471. const AZStd::string relPath = Utils::UriToRelPath(uri);
  472. // create spawnnable
  473. AZ::Data::AssetId assetId;
  474. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  475. assetId,
  476. &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  477. relPath.c_str(),
  478. azrtti_typeid<AZ::Data::AssetData>(),
  479. false);
  480. AZ_Warning("SimulationInterfaces", assetId.IsValid(), "AssetId is not valid, relative path %s", relPath.c_str());
  481. auto spawner = AZ::Interface<AzFramework::SpawnableEntitiesDefinition>::Get();
  482. AZ_Assert(spawner, "SpawnableEntitiesDefinition is not available.");
  483. AZ::Data::Asset<AzFramework::Spawnable> spawnableAsset =
  484. AZ::Data::AssetManager::Instance().GetAsset<AzFramework::Spawnable>(assetId, AZ::Data::AssetLoadBehavior::NoLoad);
  485. if (!spawnableAsset)
  486. {
  487. const auto msg = AZStd::string::format("Spawnable asset %s not found", uri.c_str());
  488. completedCb(AZ::Failure(FailedResult(ErrorCode::RESULT_NOT_FOUND, msg)));
  489. return;
  490. }
  491. auto ticket = AzFramework::EntitySpawnTicket(spawnableAsset);
  492. AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
  493. optionalArgs.m_preInsertionCallback = [initialPose, entityNamespace, name](auto id, auto view)
  494. {
  495. if (view.empty())
  496. {
  497. return;
  498. }
  499. const AZ::Entity* root = *view.begin();
  500. // change names for all entites
  501. for (auto* entity : view)
  502. {
  503. AZStd::string entityName = AZStd::string::format("%s_%s", name.c_str(), entity->GetName().c_str());
  504. entity->SetName(entityName);
  505. }
  506. auto* transformInterface = root->FindComponent<AzFramework::TransformComponent>();
  507. if (transformInterface)
  508. {
  509. transformInterface->SetWorldTM(initialPose);
  510. }
  511. if (!entityNamespace.empty())
  512. {
  513. // TODO: Mpelka set ROS 2 namespace here
  514. AZ_Error("SimulationInterfaces", false, "ROS 2 namespace is not implemented yet in spawning");
  515. }
  516. };
  517. optionalArgs.m_completionCallback =
  518. [this, uri](AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view)
  519. {
  520. // at this point the entities are spawned and should be registered in simulation interface and callback should be called
  521. // if that is not a case, it means that the AZFramework::Physics::OnSimulationBodyAdded event was not called.
  522. // That means the prefab has no physics component or the physics component is not enabled - we need to call the callback here
  523. // and return the error.
  524. auto spawnData = m_spawnCompletedCallbacks.find(ticketId);
  525. if (spawnData != m_spawnCompletedCallbacks.end())
  526. {
  527. // call and remove the callback
  528. const auto msg = AZStd::string::format(
  529. "Entity %s (uri : %s) was not registered in simulation interface - "
  530. "no physics component or physics component is not enabled in source prefab.\n"
  531. "Entity will be in simulation, but not available in simulation interface.\n"
  532. "Please add some physics component (at least one static rigid body component) to the prefab.\n"
  533. "Technically, it is a memory leak.\n",
  534. spawnData->second.m_userProposedName.c_str(),
  535. uri.c_str());
  536. AZ_Error("SimulationInterfaces", false, msg.c_str());
  537. spawnData->second.m_completedCb(msg);
  538. m_spawnCompletedCallbacks.erase(spawnData);
  539. }
  540. };
  541. spawner->SpawnAllEntities(ticket, optionalArgs);
  542. auto ticketId = ticket.GetId();
  543. AZ_Printf("SimulationInterfaces", "Spawning uri %s with ticket id %d\n", uri.c_str(), ticketId);
  544. SpawnCompletedCbData data;
  545. data.m_userProposedName = name;
  546. data.m_completedCb = completedCb;
  547. m_spawnCompletedCallbacks[ticketId] = data;
  548. m_spawnedTickets[ticketId] = ticket;
  549. }
  550. AZStd::string SimulationEntitiesManager::GetSimulatedEntityName(AZ::EntityId entityId, const AZStd::string& proposedName) const
  551. {
  552. // Get O3DE entity name
  553. AZStd::string entityName = proposedName;
  554. if (entityName.empty())
  555. {
  556. AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, entityId);
  557. }
  558. // Generate unique simulated entity name
  559. AZStd::string simulatedEntityName = entityName;
  560. // check if name is unique
  561. auto otherEntityIt = m_simulatedEntityToEntityIdMap.find(simulatedEntityName);
  562. if (otherEntityIt != m_simulatedEntityToEntityIdMap.end())
  563. {
  564. // name is not unique, add entityId to name
  565. simulatedEntityName = AZStd::string::format("%s_%s", entityName.c_str(), entityId.ToString().c_str());
  566. }
  567. return simulatedEntityName;
  568. }
  569. } // namespace SimulationInterfaces