SimulationEntitiesManager.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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. AZStd::vector<AZStd::string> SimulationEntitiesManager::GetEntities(const EntityFilters& filter)
  234. {
  235. const bool reFilter = !filter.m_filter.empty();
  236. const bool shapeCastFilter = filter.m_bounds_shape != nullptr;
  237. AZStd::vector<AZStd::string> entities;
  238. if (!shapeCastFilter)
  239. {
  240. // get all entities from the map
  241. entities.reserve(m_entityIdToSimulatedEntityMap.size());
  242. AZStd::transform(
  243. m_entityIdToSimulatedEntityMap.begin(),
  244. m_entityIdToSimulatedEntityMap.end(),
  245. AZStd::back_inserter(entities),
  246. [](const auto& pair)
  247. {
  248. return pair.second;
  249. });
  250. }
  251. else
  252. {
  253. auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  254. AZ_Assert(sceneInterface, "Physics scene interface is not available.");
  255. if (m_physicsScenesHandle == AzPhysics::InvalidSceneHandle)
  256. {
  257. return entities;
  258. }
  259. AzPhysics::OverlapRequest request;
  260. request.m_shapeConfiguration = filter.m_bounds_shape;
  261. request.m_pose = filter.m_bounds_pose;
  262. request.m_maxResults = AZStd::numeric_limits<AZ::u32>::max();
  263. AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(m_physicsScenesHandle, &request);
  264. for (const auto& hit : result.m_hits)
  265. {
  266. const AZ::EntityId entityId = hit.m_entityId;
  267. auto findIt = m_entityIdToSimulatedEntityMap.find(entityId);
  268. if (findIt != m_entityIdToSimulatedEntityMap.end())
  269. {
  270. entities.push_back(findIt->second);
  271. }
  272. }
  273. }
  274. if (reFilter)
  275. {
  276. const AZStd::vector<AZStd::string> prefilteredEntities = AZStd::move(entities);
  277. entities.clear();
  278. const AZStd::regex regex(filter.m_filter);
  279. if (regex.Valid())
  280. {
  281. AZStd::ranges::copy_if(
  282. prefilteredEntities,
  283. AZStd::back_inserter(entities),
  284. [&regex](const AZStd::string& entityName)
  285. {
  286. return AZStd::regex_search(entityName, regex);
  287. });
  288. }
  289. }
  290. return entities;
  291. }
  292. EntityState SimulationEntitiesManager::GetEntityState(const AZStd::string& name)
  293. {
  294. const auto findIt = m_simulatedEntityToEntityIdMap.find(name);
  295. AZ_Error("SimulationInterfaces", findIt != m_simulatedEntityToEntityIdMap.end(), "Entity %s not found", name.c_str());
  296. if (findIt != m_simulatedEntityToEntityIdMap.end())
  297. {
  298. EntityState entityState{};
  299. const AZ::EntityId entityId = findIt->second;
  300. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  301. AZ::TransformBus::EventResult(entityState.m_pose, entityId, &AZ::TransformBus::Events::GetWorldTM);
  302. AZ::Vector3 linearVelocity = AZ::Vector3::CreateZero();
  303. Physics::RigidBodyRequestBus::EventResult(linearVelocity, entityId, &Physics::RigidBodyRequests::GetLinearVelocity);
  304. AZ::Vector3 angularVelocity = AZ::Vector3::CreateZero();
  305. Physics::RigidBodyRequestBus::EventResult(angularVelocity, entityId, &Physics::RigidBodyRequests::GetAngularVelocity);
  306. // transform linear and angular velocities to entity frame
  307. AZ::Transform entityTransformInv = entityState.m_pose.GetInverse();
  308. entityState.m_twist_linear = entityTransformInv.TransformVector(linearVelocity);
  309. entityState.m_twist_angular = entityTransformInv.TransformVector(angularVelocity);
  310. return entityState;
  311. }
  312. return {};
  313. }
  314. bool SimulationEntitiesManager::SetEntityState(const AZStd::string& name, const EntityState& state)
  315. {
  316. const auto findIt = m_simulatedEntityToEntityIdMap.find(name);
  317. if (findIt != m_simulatedEntityToEntityIdMap.end())
  318. {
  319. const AZ::EntityId entityId = findIt->second;
  320. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  321. // get entity and all descendants
  322. AZStd::vector<AZ::EntityId> entityAndDescendants;
  323. AZ::TransformBus::EventResult(entityAndDescendants, entityId, &AZ::TransformBus::Events::GetEntityAndAllDescendants);
  324. if (state.m_pose.IsOrthogonal())
  325. {
  326. // disable simulation for all entities
  327. AZStd::map<AZ::EntityId, AZ::Transform> entityTransforms;
  328. for (const auto& descendant : entityAndDescendants)
  329. {
  330. // get name
  331. AZStd::string entityName = "Unknown";
  332. AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, descendant);
  333. AZ_Printf("SimulationInterfaces", "Disable physics for entity %s\n", entityName.c_str());
  334. Physics::RigidBodyRequestBus::Event(descendant, &Physics::RigidBodyRequests::DisablePhysics);
  335. }
  336. AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalTM, state.m_pose);
  337. for (const auto& descendant : entityAndDescendants)
  338. {
  339. Physics::RigidBodyRequestBus::Event(descendant, &Physics::RigidBodyRequests::EnablePhysics);
  340. Physics::RigidBodyRequestBus::Event(
  341. descendant, &Physics::RigidBodyRequests::SetAngularVelocity, AZ::Vector3::CreateZero());
  342. Physics::RigidBodyRequestBus::Event(
  343. descendant, &Physics::RigidBodyRequests::SetLinearVelocity, AZ::Vector3::CreateZero());
  344. }
  345. }
  346. if (!state.m_twist_linear.IsZero(AZ::Constants::FloatEpsilon) || !state.m_twist_angular.IsZero(AZ::Constants::FloatEpsilon))
  347. {
  348. // get rigid body
  349. AzPhysics::RigidBody* rigidBody = nullptr;
  350. Physics::RigidBodyRequestBus::EventResult(rigidBody, entityId, &Physics::RigidBodyRequests::GetRigidBody);
  351. if (rigidBody != nullptr)
  352. {
  353. SetRigidBodyVelocities(rigidBody, state);
  354. }
  355. }
  356. }
  357. return false;
  358. }
  359. bool SimulationEntitiesManager::DeleteEntity(const AZStd::string& name)
  360. {
  361. const auto findIt = m_simulatedEntityToEntityIdMap.find(name);
  362. if (findIt == m_simulatedEntityToEntityIdMap.end())
  363. {
  364. return false;
  365. }
  366. const AZ::EntityId entityId = findIt->second;
  367. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  368. // get entity
  369. AZ::Entity* entity = nullptr;
  370. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
  371. AZ_Assert(entity, "Entity is not available.");
  372. // check if entity is spawned by this component
  373. const auto ticketId = entity->GetEntitySpawnTicketId();
  374. if (m_spawnedTickets.find(ticketId) != m_spawnedTickets.end())
  375. {
  376. // remove the ticket
  377. m_spawnedTickets.erase(ticketId);
  378. }
  379. else
  380. {
  381. AZ_Warning("SimulationInterfaces", false, "Entity %s was not spawned by this component, wont delete it", name.c_str());
  382. return false;
  383. }
  384. #ifdef POTENTIALY_UNSAFE
  385. if (findIt != m_simulatedEntityToEntityIdMap.end())
  386. {
  387. const AZ::EntityId entityId = findIt->second;
  388. AZ_Assert(entityId.IsValid(), "EntityId is not valid");
  389. // get all descendants
  390. AZStd::vector<AZ::EntityId> entityAndDescendants;
  391. AZ::TransformBus::EventResult(entityAndDescendants, entityId, &AZ::TransformBus::Events::GetEntityAndAllDescendants);
  392. for (const auto& descendant : entityAndDescendants)
  393. {
  394. // I am not sure if this is the safe way to delete an entity
  395. AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, descendant);
  396. }
  397. return true;
  398. }
  399. #endif
  400. return false;
  401. }
  402. AZStd::unordered_map<AZStd::string, EntityState> SimulationEntitiesManager::GetEntitiesStates(const EntityFilters& filter)
  403. {
  404. AZStd::unordered_map<AZStd::string, EntityState> entitiesStates;
  405. const auto& entities = GetEntities(filter);
  406. for (const auto& entity : entities)
  407. {
  408. entitiesStates.emplace(AZStd::make_pair(entity, GetEntityState(entity)));
  409. }
  410. return entitiesStates;
  411. }
  412. AZStd::vector<Spawnable> SimulationEntitiesManager::GetSpawnables()
  413. {
  414. AZStd::vector<Spawnable> spawnables;
  415. const auto enumCallback = [&spawnables](const AZ::Data::AssetId assetId, const AZ::Data::AssetInfo& assetInfo)
  416. {
  417. bool isSpawnable = false;
  418. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  419. isSpawnable, &AZ::Data::AssetCatalogRequests::DoesAssetIdMatchWildcardPattern, assetId, "*.spawnable");
  420. if (isSpawnable)
  421. {
  422. Spawnable spawnable;
  423. spawnable.m_uri = Utils::RelPathToUri(assetInfo.m_relativePath);
  424. spawnables.push_back(spawnable);
  425. }
  426. };
  427. AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::EnumerateAssets, nullptr, enumCallback, nullptr);
  428. return spawnables;
  429. }
  430. void SimulationEntitiesManager::SpawnEntity(
  431. const AZStd::string& name,
  432. const AZStd::string& uri,
  433. const AZStd::string& entityNamespace,
  434. const AZ::Transform& initialPose,
  435. SpawnCompletedCb completedCb)
  436. {
  437. // get rel path from uri
  438. const AZStd::string relPath = Utils::UriToRelPath(uri);
  439. // create spawnnable
  440. AZ::Data::AssetId assetId;
  441. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  442. assetId,
  443. &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  444. relPath.c_str(),
  445. azrtti_typeid<AZ::Data::AssetData>(),
  446. false);
  447. AZ_Warning("SimulationInterfaces", assetId.IsValid(), "AssetId is not valid, relative path %s", relPath.c_str());
  448. auto spawner = AZ::Interface<AzFramework::SpawnableEntitiesDefinition>::Get();
  449. AZ_Assert(spawner, "SpawnableEntitiesDefinition is not available.");
  450. AZ::Data::Asset<AzFramework::Spawnable> spawnableAsset =
  451. AZ::Data::AssetManager::Instance().GetAsset<AzFramework::Spawnable>(assetId, AZ::Data::AssetLoadBehavior::NoLoad);
  452. if (!spawnableAsset)
  453. {
  454. completedCb(AZ::Failure("Failed to get spawnable asset - incorrect uri"));
  455. return;
  456. }
  457. auto ticket = AzFramework::EntitySpawnTicket(spawnableAsset);
  458. AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
  459. optionalArgs.m_preInsertionCallback = [initialPose, entityNamespace, name](auto id, auto view)
  460. {
  461. if (view.empty())
  462. {
  463. return;
  464. }
  465. const AZ::Entity* root = *view.begin();
  466. // change names for all entites
  467. for (auto* entity : view)
  468. {
  469. AZStd::string entityName = AZStd::string::format("%s_%s", name.c_str(), entity->GetName().c_str());
  470. entity->SetName(entityName);
  471. }
  472. auto* transformInterface = root->FindComponent<AzFramework::TransformComponent>();
  473. if (transformInterface)
  474. {
  475. transformInterface->SetWorldTM(initialPose);
  476. }
  477. if (!entityNamespace.empty())
  478. {
  479. // TODO: Mpelka set ROS 2 namespace here
  480. AZ_Error("SimulationInterfaces", false, "ROS 2 namespace is not implemented yet in spawning");
  481. }
  482. };
  483. optionalArgs.m_completionCallback =
  484. [this](AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view)
  485. {
  486. // at this point the entities are spawned and should be registered in simulation interface and callback should be called
  487. // if that is not a case, it means that the AZFrameworrk::Pshysics::OnSimulationBodyAdded event was not called.
  488. // That means the prefab has no physics component or the physics component is not enabled - we need to call the callback here
  489. // and return the error.
  490. auto spawnData = m_spawnCompletedCallbacks.find(ticketId);
  491. if (spawnData != m_spawnCompletedCallbacks.end())
  492. {
  493. // call and remove the callback
  494. spawnData->second.m_completedCb(AZ::Failure(
  495. "Entity was not registered in simulation interface - no physics component or physics component is not enabled."));
  496. m_spawnCompletedCallbacks.erase(spawnData);
  497. }
  498. };
  499. spawner->SpawnAllEntities(ticket, optionalArgs);
  500. auto ticketId = ticket.GetId();
  501. AZ_Printf("SimulationInterfaces", "Spawning uri %s with ticket id %d\n", uri.c_str(), ticketId);
  502. SpawnCompletedCbData data;
  503. data.m_userProposedName = name;
  504. data.m_completedCb = completedCb;
  505. m_spawnCompletedCallbacks[ticketId] = data;
  506. m_spawnedTickets[ticketId] = ticket;
  507. }
  508. AZStd::string SimulationEntitiesManager::GetSimulatedEntityName(AZ::EntityId entityId, const AZStd::string& proposedName) const
  509. {
  510. // Get O3DE entity name
  511. AZStd::string entityName = proposedName;
  512. if (entityName.empty())
  513. {
  514. AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationRequests::GetEntityName, entityId);
  515. }
  516. // Generate unique simulated entity name
  517. AZStd::string simulatedEntityName = entityName;
  518. // check if name is unique
  519. auto otherEntityIt = m_simulatedEntityToEntityIdMap.find(simulatedEntityName);
  520. if (otherEntityIt != m_simulatedEntityToEntityIdMap.end())
  521. {
  522. // name is not unique, add entityId to name
  523. simulatedEntityName = AZStd::string::format("%s_%s", entityName.c_str(), entityId.ToString().c_str());
  524. }
  525. return simulatedEntityName;
  526. }
  527. } // namespace SimulationInterfaces