2
0

SimulationManager.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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 "SimulationManager.h"
  9. #include "SimulationInterfaces/SimulationMangerRequestBus.h"
  10. #include <AzCore/Component/ComponentApplicationBus.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <AzCore/Settings/SettingsRegistry.h>
  13. #include <AzFramework/Components/ConsoleBus.h>
  14. #include <AzFramework/Physics/PhysicsSystem.h>
  15. #include <DebugDraw/DebugDrawBus.h>
  16. #include <SimulationInterfaces/SimulationFeaturesAggregatorRequestBus.h>
  17. #include <SimulationInterfaces/SimulationInterfacesTypeIds.h>
  18. #include <simulation_interfaces/msg/simulator_features.hpp>
  19. namespace SimulationInterfaces
  20. {
  21. namespace
  22. {
  23. const AZStd::unordered_map<SimulationState, AZStd::string> SimulationStateToString = {
  24. { simulation_interfaces::msg::SimulationState::STATE_PAUSED, "STATE_PAUSED" },
  25. { simulation_interfaces::msg::SimulationState::STATE_PLAYING, "STATE_PLAYING" },
  26. { simulation_interfaces::msg::SimulationState::STATE_QUITTING, "STATE_QUITTING" },
  27. { simulation_interfaces::msg::SimulationState::STATE_STOPPED, "STATE_STOPPED" }
  28. };
  29. constexpr AZStd::string_view PrintStateName = "/SimulationInterfaces/PrintStateNameInGui";
  30. constexpr AZStd::string_view StartInStoppedStateKey = "/SimulationInterfaces/StartInStoppedState";
  31. AZStd::string GetStateName(SimulationState state)
  32. {
  33. auto it = SimulationStateToString.find(state);
  34. if (it != SimulationStateToString.end())
  35. {
  36. return it->second;
  37. }
  38. return AZStd::string::format("Unknown state: %d", aznumeric_cast<int>(state));
  39. }
  40. bool StartInStoppedState()
  41. {
  42. AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
  43. AZ_Assert(settingsRegistry, "Settings Registry is not available");
  44. bool output = true;
  45. settingsRegistry->Get(output, StartInStoppedStateKey);
  46. return output;
  47. }
  48. bool PrintStateNameInGui()
  49. {
  50. AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
  51. AZ_Assert(settingsRegistry, "Settings Registry is not available");
  52. bool output = true;
  53. settingsRegistry->Get(output, PrintStateName);
  54. return output;
  55. }
  56. } // namespace
  57. AZ_COMPONENT_IMPL(SimulationManager, "SimulationManager", SimulationManagerTypeId);
  58. void SimulationManager::Reflect(AZ::ReflectContext* context)
  59. {
  60. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  61. {
  62. serializeContext->Class<SimulationManager, AZ::Component>()->Version(0);
  63. }
  64. }
  65. void SimulationManager::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  66. {
  67. provided.push_back(AZ_CRC_CE("SimulationManagerService"));
  68. }
  69. void SimulationManager::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  70. {
  71. incompatible.push_back(AZ_CRC_CE("SimulationManagerService"));
  72. }
  73. void SimulationManager::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
  74. {
  75. required.push_back(AZ_CRC_CE("PhysicsService"));
  76. required.push_back(AZ_CRC_CE("SimulationFeaturesAggregator"));
  77. }
  78. void SimulationManager::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
  79. {
  80. dependent.push_back(AZ_CRC_CE("SimulationFeaturesAggregator"));
  81. dependent.push_back(AZ_CRC_CE("DebugDrawTextService"));
  82. }
  83. SimulationManager::SimulationManager()
  84. {
  85. if (SimulationManagerRequestBusInterface::Get() == nullptr)
  86. {
  87. SimulationManagerRequestBusInterface::Register(this);
  88. }
  89. }
  90. SimulationManager::~SimulationManager()
  91. {
  92. if (SimulationManagerRequestBusInterface::Get() == this)
  93. {
  94. SimulationManagerRequestBusInterface::Unregister(this);
  95. }
  96. }
  97. void SimulationManager::InitializeSimulationState()
  98. {
  99. // if start in stopped state, pause simulation. Default state for simulation by the standard is STOPPED and
  100. // SetSimulationState has logic to prevent transition to the same state.
  101. if (StartInStoppedState())
  102. {
  103. m_simulationState = simulation_interfaces::msg::SimulationState::STATE_STOPPED;
  104. SetSimulationPaused(true);
  105. }
  106. else
  107. {
  108. SetSimulationState(simulation_interfaces::msg::SimulationState::STATE_PLAYING);
  109. }
  110. }
  111. void SimulationManager::Activate()
  112. {
  113. AzFramework::LevelSystemLifecycleNotificationBus::Handler::BusDisconnect();
  114. SimulationManagerRequestBus::Handler::BusConnect();
  115. SimulationFeaturesAggregatorRequestBus::Broadcast(
  116. &SimulationFeaturesAggregatorRequests::AddSimulationFeatures,
  117. AZStd::unordered_set<SimulationFeatureType>{ simulation_interfaces::msg::SimulatorFeatures::SIMULATION_RESET,
  118. simulation_interfaces::msg::SimulatorFeatures::SIMULATION_RESET_TIME,
  119. simulation_interfaces::msg::SimulatorFeatures::SIMULATION_RESET_STATE,
  120. simulation_interfaces::msg::SimulatorFeatures::SIMULATION_RESET_SPAWNED,
  121. simulation_interfaces::msg::SimulatorFeatures::SIMULATION_STATE_PAUSE,
  122. simulation_interfaces::msg::SimulatorFeatures::STEP_SIMULATION_SINGLE,
  123. simulation_interfaces::msg::SimulatorFeatures::STEP_SIMULATION_MULTIPLE,
  124. simulation_interfaces::msg::SimulatorFeatures::STEP_SIMULATION_ACTION,
  125. simulation_interfaces::msg::SimulatorFeatures::SIMULATION_STATE_SETTING,
  126. simulation_interfaces::msg::SimulatorFeatures::SIMULATION_STATE_GETTING });
  127. if (PrintStateNameInGui())
  128. {
  129. AZ::TickBus::Handler::BusConnect();
  130. }
  131. AZ::SystemTickBus::QueueFunction(
  132. [this]()
  133. {
  134. InitializeSimulationState();
  135. });
  136. }
  137. void SimulationManager::Deactivate()
  138. {
  139. AZ::TickBus::Handler::BusDisconnect();
  140. SimulationManagerRequestBus::Handler::BusDisconnect();
  141. }
  142. bool SimulationManager::IsSimulationPaused() const
  143. {
  144. return m_isSimulationPaused;
  145. }
  146. bool SimulationManager::IsSimulationStepsActive() const
  147. {
  148. return m_simulationFinishEvent.IsConnected();
  149. }
  150. void SimulationManager::CancelStepSimulation()
  151. {
  152. if (m_simulationFinishEvent.IsConnected())
  153. {
  154. m_simulationFinishEvent.Disconnect();
  155. SetSimulationPaused(true);
  156. m_numberOfPhysicsSteps = 0;
  157. }
  158. }
  159. void SimulationManager::SetSimulationPaused(bool paused)
  160. {
  161. // get az physics system
  162. auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
  163. AZ_Assert(physicsSystem, "Physics system is not available");
  164. const auto& sceneHandlers = physicsSystem->GetAllScenes();
  165. [[maybe_unused]] auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  166. AZ_Assert(sceneInterface, "Physics scene interface is not available");
  167. for (auto& scene : sceneHandlers)
  168. {
  169. AZ_Assert(scene, "Physics scene is not available");
  170. scene->SetEnabled(!paused);
  171. m_isSimulationPaused = paused;
  172. }
  173. }
  174. void SimulationManager::StepSimulation(AZ::u64 steps)
  175. {
  176. if (steps == 0)
  177. {
  178. return;
  179. }
  180. m_numberOfPhysicsSteps = steps;
  181. // install handler
  182. m_simulationFinishEvent = AzPhysics::SceneEvents::OnSceneSimulationFinishHandler(
  183. [this](AzPhysics::SceneHandle sceneHandle, float)
  184. {
  185. m_numberOfPhysicsSteps--;
  186. AZ_Printf("SimulationManager", "Physics simulation step finished. Remaining steps: %d", m_numberOfPhysicsSteps);
  187. SimulationManagerNotificationsBus::Broadcast(
  188. &SimulationManagerNotifications::OnSimulationStepFinish, m_numberOfPhysicsSteps);
  189. if (m_numberOfPhysicsSteps <= 0)
  190. {
  191. SetSimulationPaused(true);
  192. // remove handler
  193. m_simulationFinishEvent.Disconnect();
  194. }
  195. });
  196. // get default scene
  197. [[maybe_unused]] auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
  198. AZ_Assert(physicsSystem, "Physics system is not available");
  199. auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  200. AZ_Assert(sceneInterface, "Physics scene interface is not available");
  201. AzPhysics::SceneHandle defaultScene = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
  202. auto scene = sceneInterface->GetScene(defaultScene);
  203. AZ_Assert(scene, "Default physics scene is not available");
  204. // install handler
  205. scene->RegisterSceneSimulationFinishHandler(m_simulationFinishEvent);
  206. SetSimulationPaused(false);
  207. }
  208. void SimulationManager::ReloadLevel(SimulationManagerRequests::ReloadLevelCallback completionCallback)
  209. {
  210. AzFramework::LevelSystemLifecycleNotificationBus::Handler::BusConnect();
  211. m_reloadLevelCallback = completionCallback;
  212. // We need to delete all entities before reloading the level
  213. DeletionCompletedCb deleteAllCompletion = [](const AZ::Outcome<void, FailedResult>& result)
  214. {
  215. AZ_Trace("SimulationManager", "Delete all entities completed: %s, reload level", result.IsSuccess() ? "true" : "false");
  216. const char* levelName = AZ::Interface<AzFramework::ILevelSystemLifecycle>::Get()->GetCurrentLevelName();
  217. AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, "UnloadLevel");
  218. AZStd::string command = AZStd::string::format("LoadLevel %s", levelName);
  219. AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, command.c_str());
  220. };
  221. // delete spawned entities
  222. SimulationEntityManagerRequestBus::Broadcast(&SimulationEntityManagerRequests::DeleteAllEntities, deleteAllCompletion);
  223. }
  224. void SimulationManager::OnLoadingComplete(const char* levelName)
  225. {
  226. AZ_Printf("SimulationManager", "Level loading started: %s", levelName);
  227. if (m_reloadLevelCallback)
  228. {
  229. m_reloadLevelCallback();
  230. m_reloadLevelCallback = nullptr;
  231. }
  232. // reset of the simulation, assign the same state as at the beginning
  233. InitializeSimulationState();
  234. AzFramework::LevelSystemLifecycleNotificationBus::Handler::BusDisconnect();
  235. }
  236. SimulationState SimulationManager::GetSimulationState() const
  237. {
  238. return m_simulationState;
  239. }
  240. AZ::Outcome<void, FailedResult> SimulationManager::SetSimulationState(SimulationState stateToSet)
  241. {
  242. // check if simulation is in desire state
  243. if (m_simulationState == stateToSet)
  244. {
  245. return AZ::Failure(FailedResult(
  246. simulation_interfaces::srv::SetSimulationState::Response::ALREADY_IN_TARGET_STATE,
  247. "Simulation is already in requested state, transition unecessary"));
  248. }
  249. if (IsTransitionForbiddenInEditor(stateToSet))
  250. {
  251. const auto stateToSetName = GetStateName(stateToSet);
  252. const auto currentStateName = GetStateName(m_simulationState);
  253. return AZ::Failure(FailedResult(
  254. simulation_interfaces::srv::SetSimulationState::Response::INCORRECT_TRANSITION,
  255. AZStd::string::format(
  256. "Requested transition (%s -> %s) is forbidden in the Editor. It is available in GameLauncher.",
  257. currentStateName.c_str(),
  258. stateToSetName.c_str())));
  259. }
  260. if (IsTransitionForbidden(stateToSet))
  261. {
  262. const auto stateToSetName = GetStateName(stateToSet);
  263. const auto currentStateName = GetStateName(m_simulationState);
  264. return AZ::Failure(FailedResult(
  265. simulation_interfaces::srv::SetSimulationState::Response::INCORRECT_TRANSITION,
  266. AZStd::string::format("Requested transition (%s -> %s) is forbidden", currentStateName.c_str(), stateToSetName.c_str())));
  267. }
  268. switch (stateToSet)
  269. {
  270. case simulation_interfaces::msg::SimulationState::STATE_STOPPED:
  271. {
  272. SimulationManagerRequests::ReloadLevelCallback cb = []()
  273. {
  274. SimulationInterfaces::SimulationManagerRequestBus::Broadcast(
  275. &SimulationInterfaces::SimulationManagerRequests::SetSimulationPaused, true);
  276. };
  277. ReloadLevel(cb);
  278. break;
  279. }
  280. case simulation_interfaces::msg::SimulationState::STATE_PLAYING:
  281. {
  282. SetSimulationPaused(false);
  283. break;
  284. }
  285. case simulation_interfaces::msg::SimulationState::STATE_PAUSED:
  286. {
  287. SetSimulationPaused(true);
  288. break;
  289. }
  290. case simulation_interfaces::msg::SimulationState::STATE_QUITTING:
  291. {
  292. // stop simulation -> kill the simulator.
  293. SetSimulationPaused(true);
  294. // queue to allow status of this method to be returned, then start quitting
  295. AZ::SystemTickBus::QueueFunction(
  296. []()
  297. {
  298. AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, "quit");
  299. });
  300. break;
  301. }
  302. default:
  303. {
  304. return AZ::Failure(FailedResult(
  305. simulation_interfaces::srv::SetSimulationState::Response::INCORRECT_TRANSITION, "Requested state doesn't exists"));
  306. break;
  307. }
  308. }
  309. m_simulationState = stateToSet;
  310. return AZ::Success();
  311. }
  312. bool SimulationManager::IsTransitionForbiddenInEditor(SimulationState requestedState)
  313. {
  314. // in the Editor we cannot reload level, so going to STOPPED state is forbidden, we cannot quit the editor so going to QUITTING
  315. // state is forbidden
  316. AZ::ApplicationTypeQuery appType;
  317. AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
  318. if (appType.IsValid() && !appType.IsGame())
  319. {
  320. if (requestedState == simulation_interfaces::msg::SimulationState::STATE_STOPPED ||
  321. requestedState == simulation_interfaces::msg::SimulationState::STATE_QUITTING)
  322. {
  323. return true;
  324. }
  325. }
  326. return false;
  327. }
  328. bool SimulationManager::IsTransitionForbidden(SimulationState requestedState)
  329. {
  330. AZStd::pair<SimulationState, SimulationState> desireTransition{ m_simulationState, requestedState };
  331. auto it = AZStd::find(m_forbiddenStatesTransitions.begin(), m_forbiddenStatesTransitions.end(), desireTransition);
  332. return it != m_forbiddenStatesTransitions.end();
  333. }
  334. void SimulationManager::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  335. {
  336. DebugDraw::DebugDrawRequestBus::Broadcast(
  337. &DebugDraw::DebugDrawRequests::DrawTextOnScreen,
  338. AZStd::string::format("Simulation state: %s", GetStateName(m_simulationState).c_str()),
  339. AZ::Color(1.0f, 1.0f, 1.0f, 1.0f),
  340. 0.f);
  341. }
  342. } // namespace SimulationInterfaces