LevelManager.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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 "LevelManager.h"
  9. #include "SimulationInterfaces/SimulationMangerRequestBus.h"
  10. #include <AzCore/Asset/AssetCommon.h>
  11. #include <AzCore/Asset/AssetManagerBus.h>
  12. #include <AzCore/Component/ComponentApplicationBus.h>
  13. #include <AzCore/Outcome/Outcome.h>
  14. #include <AzCore/Serialization/SerializeContext.h>
  15. #include <AzCore/base.h>
  16. #include <AzCore/std/containers/vector.h>
  17. #include <AzCore/std/ranges/ranges_algorithm.h>
  18. #include <AzCore/std/string/conversions.h>
  19. #include <AzCore/std/string/string.h>
  20. #include <AzFramework/API/ApplicationAPI.h>
  21. #include <SimulationInterfaces/LevelManagerRequestBus.h>
  22. #include <SimulationInterfaces/Resource.h>
  23. #include <SimulationInterfaces/Result.h>
  24. #include <SimulationInterfaces/SimulationEntityManagerRequestBus.h>
  25. #include <SimulationInterfaces/SimulationFeaturesAggregatorRequestBus.h>
  26. #include <SimulationInterfaces/SimulationInterfacesTypeIds.h>
  27. #include <SimulationInterfaces/WorldResource.h>
  28. #include <simulation_interfaces/msg/detail/simulation_state__struct.hpp>
  29. #include <simulation_interfaces/srv/get_available_worlds.hpp>
  30. #include <simulation_interfaces/srv/get_current_world.hpp>
  31. #include <simulation_interfaces/srv/load_world.hpp>
  32. #include <simulation_interfaces/srv/unload_world.hpp>
  33. // ordering important
  34. // clang-format off
  35. #include <CryCommon/ILevelSystem.h>
  36. #include <CryCommon/ISystem.h>
  37. // clang-format on
  38. namespace SimulationInterfaces
  39. {
  40. namespace
  41. {
  42. ILevelSystem* GetLevelSystem()
  43. {
  44. ISystem* iSystem = GetISystem();
  45. return (iSystem != nullptr) ? iSystem->GetILevelSystem() : nullptr;
  46. }
  47. AZStd::string GetLevelNameFromAssetPath(const AZStd::string& assetPath)
  48. {
  49. AZ::IO::PathView levelPath{ assetPath };
  50. return levelPath.Stem().Native();
  51. }
  52. } // namespace
  53. AZ_COMPONENT_IMPL(LevelManager, "LevelManager", LevelManagerTypeId);
  54. void LevelManager::Reflect(AZ::ReflectContext* context)
  55. {
  56. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  57. {
  58. serializeContext->Class<LevelManager, AZ::Component>()->Version(0);
  59. }
  60. }
  61. void LevelManager::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  62. {
  63. provided.push_back(AZ_CRC_CE("LevelManagerService"));
  64. }
  65. void LevelManager::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  66. {
  67. incompatible.push_back(AZ_CRC_CE("LevelManagerService"));
  68. }
  69. void LevelManager::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
  70. {
  71. required.push_back(AZ_CRC_CE("AssetCatalogService"));
  72. required.push_back(AZ_CRC_CE("SimulationFeaturesAggregator"));
  73. }
  74. void LevelManager::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
  75. {
  76. dependent.push_back(AZ_CRC_CE("SimulationFeaturesAggregator"));
  77. }
  78. void LevelManager::Activate()
  79. {
  80. AZ::ApplicationTypeQuery appType;
  81. AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
  82. m_isAppEditor = (appType.IsValid() && appType.IsEditor());
  83. SimulationFeaturesAggregatorRequestBus::Broadcast(
  84. &SimulationFeaturesAggregatorRequests::AddSimulationFeatures,
  85. AZStd::unordered_set<SimulationFeatureType>{ simulation_interfaces::msg::SimulatorFeatures::AVAILABLE_WORLDS });
  86. // level loading and unloading is supported only in GameLauncher, remove features from Editor application
  87. if (!m_isAppEditor)
  88. {
  89. SimulationFeaturesAggregatorRequestBus::Broadcast(
  90. &SimulationFeaturesAggregatorRequests::AddSimulationFeatures,
  91. AZStd::unordered_set<SimulationFeatureType>{ simulation_interfaces::msg::SimulatorFeatures::WORLD_INFO_GETTING,
  92. simulation_interfaces::msg::SimulatorFeatures::WORLD_LOADING,
  93. simulation_interfaces::msg::SimulatorFeatures::WORLD_UNLOADING });
  94. }
  95. AzFramework::LevelSystemLifecycleNotificationBus::Handler::BusConnect();
  96. LevelManagerRequestBus::Handler::BusConnect();
  97. }
  98. void LevelManager::Deactivate()
  99. {
  100. LevelManagerRequestBus::Handler::BusDisconnect();
  101. AzFramework::LevelSystemLifecycleNotificationBus::Handler::BusDisconnect();
  102. }
  103. AZ::Outcome<WorldResourcesList, FailedResult> LevelManager::GetAvailableWorlds(const GetWorldsRequest& request)
  104. {
  105. m_actionRequestedFromSimInterfaces = true;
  106. WorldResourcesList availableWorlds;
  107. // request validation
  108. if (!request.additionalSources.empty())
  109. {
  110. constexpr const char* errorMsg = "Additional Sources are not implemented yet";
  111. AZ_Warning("SimulationInterfaces", false, errorMsg);
  112. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  113. }
  114. if (!request.filter.m_tags.empty())
  115. {
  116. constexpr const char* errorMsg = "Tags filter is not implemented yet";
  117. AZ_Warning("SimulationInterfaces", false, errorMsg);
  118. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  119. }
  120. if (!request.offlineOnly)
  121. {
  122. constexpr const char* errorMsg = "Online search is not implemented yet, only pure offline search is supported";
  123. AZ_Warning("SimulationInterfaces", false, errorMsg);
  124. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  125. }
  126. const auto allLevels = GetAllAvailableLevels();
  127. if (!allLevels.IsSuccess())
  128. {
  129. return AZ::Failure(allLevels.GetError());
  130. }
  131. for (const auto& levelPath : allLevels.GetValue())
  132. {
  133. availableWorlds.emplace_back(
  134. GetLevelNameFromAssetPath(levelPath), Resource{ levelPath, "" }, "", AZStd::vector<AZStd::string>{});
  135. }
  136. m_actionRequestedFromSimInterfaces = false;
  137. return AZ::Success(availableWorlds);
  138. }
  139. AZ::Outcome<WorldResource, FailedResult> LevelManager::GetCurrentWorld()
  140. {
  141. if (m_isAppEditor)
  142. {
  143. constexpr const char* errorMsg = "GetCurrentWorld is not supported in Editor";
  144. AZ_Warning("SimulationInterfaces", false, errorMsg);
  145. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  146. }
  147. m_actionRequestedFromSimInterfaces = true;
  148. WorldResource currentWorld;
  149. auto* levelInterface = AzFramework::LevelSystemLifecycleInterface::Get();
  150. if (levelInterface == nullptr)
  151. {
  152. constexpr const char* errorMsg = "Failed to get level interface";
  153. AZ_Warning("SimulationInterfaces", false, errorMsg);
  154. return AZ::Failure(FailedResult(simulation_interfaces::srv::GetAvailableWorlds::Response::DEFAULT_SOURCES_FAILED, errorMsg));
  155. }
  156. if (!levelInterface->IsLevelLoaded())
  157. {
  158. constexpr const char* errorMsg = "No level loaded";
  159. AZ_Warning("SimulationInterfaces", false, errorMsg);
  160. return AZ::Failure(FailedResult(simulation_interfaces::srv::GetCurrentWorld::Response::NO_WORLD_LOADED, errorMsg));
  161. }
  162. const auto* levelPath = levelInterface->GetCurrentLevelName();
  163. if (levelPath == nullptr)
  164. {
  165. constexpr const char* errorMsg = "Failed to get current level path";
  166. AZ_Warning("SimulationInterfaces", false, errorMsg);
  167. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_OPERATION_FAILED, errorMsg));
  168. }
  169. AZStd::string levelPathStr{ levelPath };
  170. AZStd::to_lower(levelPathStr.begin(), levelPathStr.end());
  171. auto levelName = GetLevelNameFromAssetPath(levelPathStr);
  172. currentWorld.m_worldResource.m_uri = levelPathStr;
  173. currentWorld.m_name = levelName;
  174. m_actionRequestedFromSimInterfaces = false;
  175. return AZ::Success(currentWorld);
  176. }
  177. AZ::Outcome<WorldResource, FailedResult> LevelManager::LoadWorld(const LoadWorldRequest& request)
  178. {
  179. if (m_isAppEditor)
  180. {
  181. constexpr const char* errorMsg = "LoadWorld is not supported in Editor";
  182. AZ_Warning("SimulationInterfaces", false, errorMsg);
  183. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  184. }
  185. m_actionRequestedFromSimInterfaces = true;
  186. WorldResource loadedWorld;
  187. if (request.levelResource.m_resourceString.empty() && request.levelResource.m_uri.empty())
  188. {
  189. constexpr const char* errorMsg = "uri and resource string in levelResource cannot be both empty";
  190. AZ_Warning("SimulationInterfaces", false, errorMsg);
  191. return AZ::Failure(FailedResult(simulation_interfaces::srv::LoadWorld::Response::NO_RESOURCE, errorMsg));
  192. }
  193. if (!request.levelResource.m_resourceString.empty() && !request.levelResource.m_uri.empty())
  194. {
  195. constexpr const char* errorMsg = "uri and resource string in levelResource cannot be both non-empty";
  196. AZ_Warning("SimulationInterfaces", false, errorMsg);
  197. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_OPERATION_FAILED, errorMsg));
  198. }
  199. if (!request.levelResource.m_resourceString.empty())
  200. {
  201. constexpr const char* errorMsg = "Loading world from resource string is not implemented yet";
  202. AZ_Warning("SimulationInterfaces", false, errorMsg);
  203. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  204. }
  205. const auto levelNamesResult = GetAllAvailableLevels();
  206. if (!levelNamesResult.IsSuccess())
  207. {
  208. return AZ::Failure(levelNamesResult.GetError());
  209. }
  210. const auto& levelsPaths = levelNamesResult.GetValue();
  211. if (!AZStd::ranges::contains(levelsPaths, request.levelResource.m_uri))
  212. {
  213. const AZStd::string errorMsg = AZStd::string::format("Requested world/level %s not found", request.levelResource.m_uri.c_str());
  214. AZ_Warning("SimulationInterfaces", false, errorMsg.c_str());
  215. return AZ::Failure(FailedResult(simulation_interfaces::srv::LoadWorld::Response::MISSING_ASSETS, errorMsg));
  216. }
  217. ILevelSystem* levelSystem = GetLevelSystem();
  218. if (levelSystem == nullptr)
  219. {
  220. constexpr const char* errorMsg = "Failed to start, level System not available";
  221. AZ_Warning("SimulationInterfaces", false, errorMsg);
  222. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_OPERATION_FAILED, errorMsg));
  223. }
  224. // unload level if needed
  225. if (GetCurrentWorld().IsSuccess())
  226. {
  227. levelSystem->UnloadLevel();
  228. }
  229. // notify state machine
  230. SimulationManagerRequestBus::Broadcast(
  231. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_LOADING_WORLD);
  232. if (!levelSystem->LoadLevel(request.levelResource.m_uri.c_str()))
  233. {
  234. constexpr const char* errorMsg = "Failed to load world";
  235. AZ_Warning("SimulationInterfaces", false, errorMsg);
  236. SimulationManagerRequestBus::Broadcast(
  237. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_NO_WORLD);
  238. return AZ::Failure(FailedResult(simulation_interfaces::srv::LoadWorld::Response::RESOURCE_PARSE_ERROR, errorMsg));
  239. }
  240. // notify state machine
  241. SimulationManagerRequestBus::Broadcast(
  242. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_STOPPED);
  243. // fill up response
  244. loadedWorld.m_worldResource = request.levelResource;
  245. m_actionRequestedFromSimInterfaces = false;
  246. return AZ::Success(loadedWorld);
  247. }
  248. AZ::Outcome<void, FailedResult> LevelManager::UnloadWorld()
  249. {
  250. if (m_isAppEditor)
  251. {
  252. constexpr const char* errorMsg = "UnloadWorld is not supported in Editor";
  253. AZ_Warning("SimulationInterfaces", false, errorMsg);
  254. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_FEATURE_UNSUPPORTED, errorMsg));
  255. }
  256. m_actionRequestedFromSimInterfaces = true;
  257. const auto currentLevel = GetCurrentWorld();
  258. if (!currentLevel.IsSuccess())
  259. {
  260. if (currentLevel.GetError().m_errorCode == simulation_interfaces::srv::GetCurrentWorld::Response::NO_WORLD_LOADED)
  261. {
  262. constexpr const char* errorMsg = "No level loaded";
  263. AZ_Warning("SimulationInterfaces", false, errorMsg);
  264. return AZ::Failure(FailedResult(simulation_interfaces::srv::UnloadWorld::Response::NO_WORLD_LOADED, errorMsg));
  265. }
  266. }
  267. ILevelSystem* levelSystem = GetLevelSystem();
  268. if (!levelSystem)
  269. {
  270. constexpr const char* errorMsg = "Level system is not available";
  271. AZ_Warning("SimulationInterfaces", false, errorMsg);
  272. return AZ::Failure(FailedResult(simulation_interfaces::msg::Result::RESULT_OPERATION_FAILED, errorMsg));
  273. }
  274. levelSystem->UnloadLevel();
  275. SimulationManagerRequestBus::Broadcast(
  276. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_NO_WORLD);
  277. m_actionRequestedFromSimInterfaces = false;
  278. return AZ::Success();
  279. }
  280. void LevelManager::ReloadLevel()
  281. {
  282. if (m_isAppEditor)
  283. {
  284. [[maybe_unused]] constexpr const char* errorMsg = "ReloadWorld is not supported in Editor";
  285. AZ_Warning("SimulationInterfaces", false, errorMsg);
  286. return;
  287. }
  288. m_actionRequestedFromSimInterfaces = true;
  289. auto levelGathering = GetCurrentWorld();
  290. if (!levelGathering.IsSuccess())
  291. {
  292. AZ_Error("LevelManager", false, "Error occurred during level gathering: %s", levelGathering.GetError().m_errorString.c_str());
  293. return;
  294. }
  295. UnloadWorld();
  296. LoadWorldRequest request;
  297. request.levelResource = levelGathering.GetValue().m_worldResource;
  298. LoadWorld(request);
  299. m_actionRequestedFromSimInterfaces = false;
  300. }
  301. AZ::Outcome<AZStd::vector<AZStd::string>, FailedResult> LevelManager::GetAllAvailableLevels()
  302. {
  303. ILevelSystem* levelSystem = GetLevelSystem();
  304. if (!levelSystem)
  305. {
  306. constexpr const char* errorMsg = "Level system is not available";
  307. AZ_Warning("SimulationInterfaces", false, errorMsg);
  308. return AZ::Failure(FailedResult(simulation_interfaces::srv::GetAvailableWorlds::Response::DEFAULT_SOURCES_FAILED, errorMsg));
  309. }
  310. // Run through all the assets in the asset catalog and gather up the list of level assets
  311. AZ::Data::AssetType levelAssetType = levelSystem->GetLevelAssetType();
  312. AZStd::vector<AZStd::string> levelNames;
  313. auto enumerateCB = [levelAssetType, &levelNames](const AZ::Data::AssetId id, const AZ::Data::AssetInfo& assetInfo)
  314. {
  315. if (assetInfo.m_assetType != levelAssetType)
  316. {
  317. return;
  318. }
  319. AZStd::string assetPath;
  320. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, id);
  321. AZStd::string lowerCaseLevelPath = assetPath;
  322. AZStd::to_lower(lowerCaseLevelPath.begin(), lowerCaseLevelPath.end());
  323. if (!lowerCaseLevelPath.starts_with("levels"))
  324. {
  325. return;
  326. }
  327. levelNames.push_back(assetPath);
  328. };
  329. AZ::Data::AssetCatalogRequestBus::Broadcast(
  330. &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, enumerateCB, nullptr);
  331. return AZ::Success(levelNames);
  332. }
  333. // below callbacks are triggered when simulation interfaces were used as well.
  334. // methods related to simulation interfaces have their own handling so to not duplicate handling, calls in this method are possible only
  335. // they were triggered in other way than simulation interfaces
  336. void LevelManager::OnLoadingStart(const char* levelName)
  337. {
  338. if (!m_actionRequestedFromSimInterfaces)
  339. {
  340. SimulationManagerRequestBus::Broadcast(
  341. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_LOADING_WORLD);
  342. }
  343. }
  344. void LevelManager::OnLoadingComplete(const char* levelName)
  345. {
  346. if (!m_actionRequestedFromSimInterfaces)
  347. {
  348. SimulationManagerRequestBus::Broadcast(
  349. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_STOPPED);
  350. }
  351. }
  352. void LevelManager::OnUnloadComplete(const char* levelName)
  353. {
  354. if (!m_actionRequestedFromSimInterfaces)
  355. {
  356. // literally order entities removal. Other way they would stay after reload
  357. SimulationEntityManagerRequestBus::Broadcast(
  358. &SimulationEntityManagerRequests::DeleteAllEntities,
  359. [](const AZ::Outcome<void, FailedResult>& outcome)
  360. {
  361. });
  362. SimulationManagerRequestBus::Broadcast(
  363. &SimulationManagerRequests::SetSimulationState, simulation_interfaces::msg::SimulationState::STATE_NO_WORLD);
  364. }
  365. }
  366. } // namespace SimulationInterfaces