AssetUtils.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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 <AzCore/Component/ComponentApplicationBus.h>
  9. #include <AzCore/Debug/Trace.h>
  10. #include <AzCore/IO/Path/Path.h>
  11. #include <AzCore/IO/FileIO.h>
  12. #include <AzCore/Module/ModuleManagerBus.h>
  13. #include <AzCore/Module/DynamicModuleHandle.h>
  14. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  15. #include <AzCore/StringFunc/StringFunc.h>
  16. #include <AzCore/Utils/Utils.h>
  17. #include <AzFramework/IO/LocalFileIO.h>
  18. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  19. #include <AzToolsFramework/Asset/AssetUtils.h>
  20. #include <QString>
  21. namespace AzToolsFramework::AssetUtils::Internal
  22. {
  23. constexpr const char* AssetProcessorSettingsKey{ "/Amazon/AssetProcessor/Settings" };
  24. constexpr const char* AssetConfigPlatformDir = "AssetProcessorConfig";
  25. constexpr const char* RestrictedPlatformDir = "restricted";
  26. AZStd::vector<AZ::IO::Path> FindWildcardMatches(AZStd::string_view sourceFolder, AZStd::string_view relativeName)
  27. {
  28. if (relativeName.empty())
  29. {
  30. return {};
  31. }
  32. AZ::IO::Path sourceWildcard{ sourceFolder };
  33. AZStd::vector<AZ::IO::Path> returnList;
  34. // Walks the sourceFolder and subdirectories to search for the relativeName as a wild card using a breathe-first search
  35. AZStd::queue<AZ::IO::Path> searchFolders;
  36. searchFolders.push(AZStd::move(sourceWildcard));
  37. while (!searchFolders.empty())
  38. {
  39. const AZ::IO::Path& searchFolder = searchFolders.front();
  40. AZ::IO::SystemFile::FindFileCB findFiles = [&returnList, &relativeName, &searchFolder, &searchFolders](AZStd::string_view fileView, bool isFile) -> bool
  41. {
  42. if (fileView == "." || fileView == "..")
  43. {
  44. return true;
  45. }
  46. if (isFile)
  47. {
  48. if (AZStd::wildcard_match(relativeName, fileView))
  49. {
  50. returnList.emplace_back(searchFolder / fileView);
  51. }
  52. }
  53. else
  54. {
  55. // Use the current search directory to append the fileView directory wild card
  56. searchFolders.push(searchFolder / fileView);
  57. }
  58. return true;
  59. };
  60. AZ::IO::SystemFile::FindFiles((searchFolder / "*").c_str(), findFiles);
  61. searchFolders.pop();
  62. }
  63. return returnList;
  64. }
  65. void AddGemConfigFiles(const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AZStd::vector<AZ::IO::Path>& configFiles)
  66. {
  67. const char* AssetProcessorGemConfigIni = "AssetProcessorGemConfig.ini";
  68. const char* AssetProcessorGemConfigSetreg = "AssetProcessorGemConfig.setreg";
  69. for (const AzFramework::GemInfo& gemElement : gemInfoList)
  70. {
  71. for (const AZ::IO::Path& gemAbsoluteSourcePath : gemElement.m_absoluteSourcePaths)
  72. {
  73. configFiles.push_back(gemAbsoluteSourcePath / AssetProcessorGemConfigIni);
  74. configFiles.push_back(gemAbsoluteSourcePath / AssetProcessorGemConfigSetreg);
  75. }
  76. }
  77. }
  78. }
  79. namespace AzToolsFramework::AssetUtils
  80. {
  81. // Visitor for reading the "/Amazon/AssetProcessor/Settings/Platforms" entries from the Settings Registry
  82. struct EnabledPlatformsVisitor
  83. : AZ::SettingsRegistryInterface::Visitor
  84. {
  85. using AZ::SettingsRegistryInterface::Visitor::Visit;
  86. void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, AZStd::string_view value) override
  87. {
  88. if (value == "enabled")
  89. {
  90. m_enabledPlatforms.emplace_back(visitArgs.m_fieldName);
  91. }
  92. else if (value == "disabled")
  93. {
  94. auto platformEntrySearch = [&visitArgs](AZStd::string_view platformEntry)
  95. {
  96. return visitArgs.m_fieldName == platformEntry;
  97. };
  98. auto removeIt = AZStd::remove_if(m_enabledPlatforms.begin(), m_enabledPlatforms.end(), platformEntrySearch);
  99. m_enabledPlatforms.erase(removeIt, m_enabledPlatforms.end());
  100. }
  101. }
  102. AZStd::vector<AZStd::string> m_enabledPlatforms;
  103. };
  104. void ReadEnabledPlatformsFromSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry,
  105. AZStd::vector<AZStd::string>& enabledPlatforms)
  106. {
  107. // note that the current host platform is enabled by default.
  108. enabledPlatforms.push_back(AzToolsFramework::AssetSystem::GetHostAssetPlatform());
  109. // in the setreg the platform can be missing (commented out)
  110. // in which case it is disabled implicitly by not being there
  111. // or it can be 'disabled' which means that it is explicitly disabled.
  112. // or it can be 'enabled' which means that it is explicitly enabled.
  113. EnabledPlatformsVisitor visitor;
  114. settingsRegistry.Visit(visitor, AZ::SettingsRegistryInterface::FixedValueString(Internal::AssetProcessorSettingsKey) + "/Platforms");
  115. enabledPlatforms.insert(enabledPlatforms.end(), AZStd::make_move_iterator(visitor.m_enabledPlatforms.begin()),
  116. AZStd::make_move_iterator(visitor.m_enabledPlatforms.end()));
  117. }
  118. AZStd::vector<AZStd::string> GetEnabledPlatforms(AZ::SettingsRegistryInterface& settingsRegistry,
  119. const AZStd::vector<AZ::IO::Path>& configFiles)
  120. {
  121. AZStd::vector<AZStd::string> enabledPlatforms;
  122. for (const auto& configFile : configFiles)
  123. {
  124. if (AZ::IO::SystemFile::Exists(configFile.c_str()))
  125. {
  126. // If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function
  127. // otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style
  128. // file to the settings registry
  129. if (configFile.Extension() == ".setreg")
  130. {
  131. settingsRegistry.MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch);
  132. }
  133. else
  134. {
  135. AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings;
  136. configParserSettings.m_registryRootPointerPath = Internal::AssetProcessorSettingsKey;
  137. AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(settingsRegistry, configFile.Native(), configParserSettings);
  138. }
  139. }
  140. }
  141. ReadEnabledPlatformsFromSettingsRegistry(settingsRegistry, enabledPlatforms);
  142. return enabledPlatforms;
  143. }
  144. constexpr const char* AssetProcessorPlatformConfigFileName = "AssetProcessorPlatformConfig.ini";
  145. constexpr const char* AssetProcessorPlatformConfigSetreg = "AssetProcessorPlatformConfig.setreg";
  146. bool AddPlatformConfigFilePaths(AZStd::string_view engineRoot, AZStd::vector<AZ::IO::Path>& configFilePaths)
  147. {
  148. auto restrictedRoot = AZ::IO::Path{ engineRoot } / Internal::RestrictedPlatformDir;
  149. // first collect public platform configs
  150. AZStd::vector<AZ::IO::Path> platformDirs{ AZ::IO::Path{ engineRoot } / Internal::AssetConfigPlatformDir };
  151. // then collect restricted platform configs
  152. // Append the AssetConfigPlatformDir value to each directory
  153. AZ::IO::SystemFile::FindFileCB findRestrictedAssetConfigs = [&restrictedRoot, &platformDirs](AZStd::string_view fileView, bool isFile) -> bool
  154. {
  155. if (fileView != "." && fileView != "..")
  156. {
  157. if (!isFile)
  158. {
  159. platformDirs.push_back(restrictedRoot / fileView / Internal::AssetConfigPlatformDir);
  160. }
  161. }
  162. return true;
  163. };
  164. AZ::IO::SystemFile::FindFiles((restrictedRoot / "*").c_str(), findRestrictedAssetConfigs);
  165. // Iterator over all platform directories for platform config files
  166. AZStd::vector<AZ::IO::Path> allPlatformConfigs;
  167. for (const auto& platformDir : platformDirs)
  168. {
  169. for (const char* configPath : { AssetProcessorPlatformConfigFileName, AssetProcessorPlatformConfigSetreg })
  170. {
  171. AZStd::vector<AZ::IO::Path> platformConfigs = Internal::FindWildcardMatches(platformDir.Native(), configPath);
  172. allPlatformConfigs.insert(allPlatformConfigs.end(), AZStd::make_move_iterator(platformConfigs.begin()), AZStd::make_move_iterator(platformConfigs.end()));
  173. }
  174. }
  175. const bool platformConfigFilePathsAdded = !allPlatformConfigs.empty();
  176. configFilePaths.insert(configFilePaths.end(), AZStd::make_move_iterator(allPlatformConfigs.begin()), AZStd::make_move_iterator(allPlatformConfigs.end()));
  177. return platformConfigFilePathsAdded;
  178. }
  179. AZStd::vector<AZ::IO::Path> GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view projectPath,
  180. bool addPlatformConfigs, bool addGemsConfigs, AZ::SettingsRegistryInterface* settingsRegistry)
  181. {
  182. constexpr const char* AssetProcessorGamePlatformConfigFileName = "AssetProcessorGamePlatformConfig.ini";
  183. constexpr const char* AssetProcessorGamePlatformConfigSetreg = "AssetProcessorGamePlatformConfig.setreg";
  184. AZStd::vector<AZ::IO::Path> configFiles;
  185. // Add the AssetProcessorPlatformConfig setreg file at the engine root
  186. configFiles.push_back(AZ::IO::Path(engineRoot) / AssetProcessorPlatformConfigSetreg);
  187. if (addPlatformConfigs)
  188. {
  189. AddPlatformConfigFilePaths(engineRoot, configFiles);
  190. }
  191. if (addGemsConfigs)
  192. {
  193. AZStd::vector<AzFramework::GemInfo> gemInfoList;
  194. if (!AzFramework::GetGemsInfo(gemInfoList, *settingsRegistry))
  195. {
  196. AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to read gems from project folder(%.*s).\n", AZ_STRING_ARG(projectPath));
  197. return {};
  198. }
  199. Internal::AddGemConfigFiles(gemInfoList, configFiles);
  200. }
  201. AZ::IO::Path projectRoot(projectPath);
  202. AZ::IO::Path projectConfigFile = projectRoot / AssetProcessorGamePlatformConfigFileName;
  203. configFiles.push_back(projectConfigFile);
  204. // Add a file entry for the Project AssetProcessor setreg file
  205. projectConfigFile = projectRoot / AssetProcessorGamePlatformConfigSetreg;
  206. configFiles.push_back(projectConfigFile);
  207. return configFiles;
  208. }
  209. bool UpdateFilePathToCorrectCase(AZStd::string_view rootPath, AZStd::string& relPathFromRoot)
  210. {
  211. AZ::StringFunc::Path::Normalize(relPathFromRoot);
  212. AZStd::vector<AZStd::string> tokens;
  213. AZ::StringFunc::Tokenize(relPathFromRoot.c_str(), tokens, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
  214. AZ::IO::FixedMaxPath validatedPath;
  215. if (rootPath.empty())
  216. {
  217. validatedPath = AZ::Utils::GetEnginePath();
  218. }
  219. else
  220. {
  221. validatedPath = rootPath;
  222. }
  223. bool success = true;
  224. for (int idx = 0; idx < tokens.size(); idx++)
  225. {
  226. AZStd::string element = tokens[idx];
  227. bool foundAMatch = false;
  228. AZ::IO::FileIOBase::GetInstance()->FindFiles(validatedPath.c_str(), "*", [&](const char* file)
  229. {
  230. if (idx != tokens.size() - 1 && !AZ::IO::FileIOBase::GetInstance()->IsDirectory(file))
  231. {
  232. // only the last token is supposed to be a filename, we can skip filenames before that
  233. return true;
  234. }
  235. AZStd::string absFilePath(file);
  236. AZ::StringFunc::Path::Normalize(absFilePath);
  237. auto found = absFilePath.rfind(AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
  238. size_t startingPos = found + 1;
  239. if (found != AZStd::string::npos && absFilePath.size() > startingPos)
  240. {
  241. AZStd::string componentName = AZStd::string(absFilePath.begin() + startingPos, absFilePath.end());
  242. if (AZ::StringFunc::Equal(componentName.c_str(), tokens[idx].c_str()))
  243. {
  244. tokens[idx] = componentName;
  245. foundAMatch = true;
  246. return false;
  247. }
  248. }
  249. return true;
  250. });
  251. if (!foundAMatch)
  252. {
  253. success = false;
  254. break;
  255. }
  256. validatedPath /= element; // go one step deeper.
  257. }
  258. if (success)
  259. {
  260. relPathFromRoot.clear();
  261. AZ::StringFunc::Join(relPathFromRoot, tokens.begin(), tokens.end(), AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
  262. }
  263. return success;
  264. }
  265. } //namespace AzToolsFramework::AssetUtils