PlatformConfiguration.cpp 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105
  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 "native/utilities/PlatformConfiguration.h"
  9. #include "native/AssetManager/FileStateCache.h"
  10. #include "native/assetprocessor.h"
  11. #include <QDirIterator>
  12. #include <AzCore/Component/ComponentApplicationBus.h>
  13. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  14. #include <AzCore/Settings/SettingsRegistryVisitorUtils.h>
  15. #include <AzCore/Serialization/Json/JsonUtils.h>
  16. #include <AzCore/Utils/Utils.h>
  17. #include <AzFramework/API/ApplicationAPI.h>
  18. #include <AzFramework/Gem/GemInfo.h>
  19. #include <AzToolsFramework/Asset/AssetUtils.h>
  20. #include <AzCore/Serialization/SerializeContext.h>
  21. #include <AzToolsFramework/Metadata/MetadataManager.h>
  22. namespace AssetProcessor
  23. {
  24. struct AssetImporterPathsVisitor
  25. : AZ::SettingsRegistryInterface::Visitor
  26. {
  27. AssetImporterPathsVisitor(AZ::SettingsRegistryInterface* settingsRegistry, AZStd::vector<AZStd::string>& supportedExtension)
  28. : m_settingsRegistry(settingsRegistry)
  29. , m_supportedFileExtensions(supportedExtension)
  30. {
  31. }
  32. using AZ::SettingsRegistryInterface::Visitor::Visit;
  33. void Visit(const AZ::SettingsRegistryInterface::VisitArgs&, AZStd::string_view value) override
  34. {
  35. if (auto found = value.find('.'); found != AZStd::string::npos)
  36. {
  37. m_supportedFileExtensions.emplace_back(value.substr(found + 1));
  38. }
  39. else
  40. {
  41. m_supportedFileExtensions.emplace_back(value);
  42. }
  43. }
  44. AZ::SettingsRegistryInterface* m_settingsRegistry;
  45. AZStd::vector<AZStd::string> m_supportedFileExtensions;
  46. };
  47. //! Visitor for reading the "/Amazon/AssetProcessor/Settings/ScanFolder *" entries from the Settings Registry
  48. //! Expects the key to path to the visitor to be "/Amazon/AssetProcessor/Settings"
  49. struct ScanFolderVisitor
  50. : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
  51. {
  52. using AZ::SettingsRegistryInterface::Visitor::Visit;
  53. AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
  54. struct ScanFolderInfo
  55. {
  56. AZStd::string m_scanFolderIdentifier;
  57. AZStd::string m_scanFolderDisplayName;
  58. AZ::IO::Path m_watchPath{ AZ::IO::PosixPathSeparator };
  59. AZStd::vector<AZStd::string> m_includeIdentifiers;
  60. AZStd::vector<AZStd::string> m_excludeIdentifiers;
  61. int m_scanOrder{};
  62. bool m_isRecursive{};
  63. };
  64. AZStd::vector<ScanFolderInfo> m_scanFolderInfos;
  65. };
  66. struct ExcludeVisitor
  67. : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
  68. {
  69. using AZ::SettingsRegistryInterface::Visitor::Visit;
  70. AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
  71. AZStd::vector<ExcludeAssetRecognizer> m_excludeAssetRecognizers;
  72. };
  73. struct SimpleJobVisitor
  74. : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
  75. {
  76. SimpleJobVisitor(const AZStd::vector<AssetBuilderSDK::PlatformInfo>& enabledPlatforms)
  77. : m_enabledPlatforms(enabledPlatforms)
  78. {
  79. }
  80. using AZ::SettingsRegistryInterface::Visitor::Visit;
  81. AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
  82. struct SimpleJobAssetRecognizer
  83. {
  84. AssetRecognizer m_recognizer;
  85. AZStd::string m_defaultParams;
  86. bool m_ignore{};
  87. };
  88. AZStd::vector<SimpleJobAssetRecognizer> m_assetRecognizers;
  89. private:
  90. void ApplyParamsOverrides(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs,
  91. SimpleJobAssetRecognizer& assetRecognizer);
  92. const AZStd::vector<AssetBuilderSDK::PlatformInfo>& m_enabledPlatforms;
  93. };
  94. //! This vistor reads in the Asset Cache Server configuration elements from the settings registry
  95. struct ACSVisitor
  96. : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
  97. {
  98. using AZ::SettingsRegistryInterface::Visitor::Visit;
  99. AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
  100. AZStd::vector<AssetRecognizer> m_assetRecognizers;
  101. };
  102. struct PlatformsInfoVisitor
  103. : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
  104. {
  105. using AZ::SettingsRegistryInterface::Visitor::Visit;
  106. AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override
  107. {
  108. // Visit any each "Platform *" field that is a direct child of the object at the AssetProcessorSettingsKey
  109. constexpr AZStd::string_view PlatformInfoPrefix = "Platform ";
  110. if (!visitArgs.m_fieldName.starts_with(PlatformInfoPrefix))
  111. {
  112. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  113. }
  114. // Retrieve the platform name from the rest of valueName portion of the key "Platform (.*)"
  115. AZStd::string platformIdentifier = visitArgs.m_fieldName.substr(PlatformInfoPrefix.size());
  116. // Lowercase the platformIdentifier
  117. AZStd::to_lower(platformIdentifier.begin(), platformIdentifier.end());
  118. // Look up the "tags" field that is child of the "Platform (.*)" field
  119. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  120. const auto tagKeyPath = FixedValueString(visitArgs.m_jsonKeyPath) + "/tags";
  121. if (AZStd::string tagValue; visitArgs.m_registry.Get(tagValue, tagKeyPath))
  122. {
  123. AZStd::unordered_set<AZStd::string> platformTags;
  124. auto JoinTags = [&platformTags](AZStd::string_view token)
  125. {
  126. AZStd::string cleanedTag{ token };
  127. AZStd::to_lower(cleanedTag.begin(), cleanedTag.end());
  128. platformTags.insert(AZStd::move(cleanedTag));
  129. };
  130. AZ::StringFunc::TokenizeVisitor(tagValue, JoinTags, ',');
  131. m_platformInfos.emplace_back(platformIdentifier, platformTags);
  132. }
  133. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  134. }
  135. AZStd::vector<AssetBuilderSDK::PlatformInfo> m_platformInfos;
  136. };
  137. struct MetaDataTypesVisitor
  138. : AZ::SettingsRegistryInterface::Visitor
  139. {
  140. using AZ::SettingsRegistryInterface::Visitor::Visit;
  141. void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, AZStd::string_view value) override
  142. {
  143. m_metaDataTypes.push_back({ AZ::IO::PathView(visitArgs.m_fieldName, AZ::IO::PosixPathSeparator).LexicallyNormal().String(), value });
  144. }
  145. struct MetaDataType
  146. {
  147. AZStd::string m_fileType;
  148. AZStd::string m_extensionType;
  149. };
  150. AZStd::vector<MetaDataType> m_metaDataTypes;
  151. };
  152. AZ::SettingsRegistryInterface::VisitResponse ScanFolderVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
  153. {
  154. constexpr AZStd::string_view ScanFolderInfoPrefix = "ScanFolder ";
  155. // Check if a "ScanFolder *" element is being traversed
  156. if (!visitArgs.m_fieldName.starts_with(ScanFolderInfoPrefix))
  157. {
  158. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  159. }
  160. AZStd::string_view currentScanFolderIdentifier = visitArgs.m_fieldName.substr(ScanFolderInfoPrefix.size());
  161. ScanFolderInfo& scanFolderInfo = m_scanFolderInfos.emplace_back();
  162. scanFolderInfo.m_scanFolderIdentifier = currentScanFolderIdentifier;
  163. scanFolderInfo.m_scanFolderDisplayName = currentScanFolderIdentifier;
  164. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  165. if (AZ::s64 value;
  166. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/recursive"))
  167. {
  168. scanFolderInfo.m_isRecursive = value != 0;
  169. }
  170. if (AZ::s64 value;
  171. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/order"))
  172. {
  173. scanFolderInfo.m_scanOrder = static_cast<int>(value);
  174. }
  175. if (AZStd::string value;
  176. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/watch"))
  177. {
  178. scanFolderInfo.m_watchPath = value;
  179. }
  180. if (AZStd::string value;
  181. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/display")
  182. && !value.empty())
  183. {
  184. scanFolderInfo.m_scanFolderDisplayName = value;
  185. }
  186. if (AZStd::string value;
  187. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/include"))
  188. {
  189. auto JoinTags = [&scanFolderInfo](AZStd::string_view token)
  190. {
  191. scanFolderInfo.m_includeIdentifiers.push_back(token);
  192. };
  193. AZ::StringFunc::TokenizeVisitor(value, JoinTags, ',');
  194. }
  195. if (AZStd::string value;
  196. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/exclude"))
  197. {
  198. auto JoinTags = [&scanFolderInfo](AZStd::string_view token)
  199. {
  200. scanFolderInfo.m_excludeIdentifiers.push_back(token);
  201. };
  202. AZ::StringFunc::TokenizeVisitor(value, JoinTags, ',');
  203. }
  204. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  205. }
  206. AZ::SettingsRegistryInterface::VisitResponse ExcludeVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
  207. {
  208. constexpr AZStd::string_view ExcludeNamePrefix = "Exclude ";
  209. if (!visitArgs.m_fieldName.starts_with(ExcludeNamePrefix))
  210. {
  211. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  212. }
  213. AZStd::string_view excludeName = visitArgs.m_fieldName.substr(ExcludeNamePrefix.size());
  214. ExcludeAssetRecognizer& excludeAssetRecognizer = m_excludeAssetRecognizers.emplace_back();
  215. excludeAssetRecognizer.m_name = QString::fromUtf8(excludeName.data(), aznumeric_cast<int>(excludeName.size()));
  216. // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values
  217. // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the
  218. // backslash character used to escape other characters, therefore causing a "double escape"
  219. // situation
  220. auto UnescapePattern = [](AZStd::string_view pattern)
  221. {
  222. constexpr AZStd::string_view backslashEscape = R"(\\)";
  223. AZStd::string unescapedResult;
  224. while (!pattern.empty())
  225. {
  226. size_t pos = pattern.find(backslashEscape);
  227. if (pos != AZStd::string_view::npos)
  228. {
  229. unescapedResult += pattern.substr(0, pos);
  230. unescapedResult += '\\';
  231. // Move the pattern string after the double backslash characters
  232. pattern = pattern.substr(pos + backslashEscape.size());
  233. }
  234. else
  235. {
  236. unescapedResult += pattern;
  237. pattern = {};
  238. }
  239. }
  240. return unescapedResult;
  241. };
  242. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  243. if (AZStd::string value;
  244. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/pattern"))
  245. {
  246. if (!value.empty())
  247. {
  248. const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex;
  249. excludeAssetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
  250. }
  251. }
  252. if (AZStd::string value;
  253. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/glob"))
  254. {
  255. if (!excludeAssetRecognizer.m_patternMatcher.IsValid())
  256. {
  257. const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard;
  258. excludeAssetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
  259. }
  260. }
  261. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  262. }
  263. AZ::SettingsRegistryInterface::VisitResponse SimpleJobVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
  264. {
  265. constexpr AZStd::string_view RCNamePrefix = "RC "; // RC = Resource Compiler
  266. constexpr AZStd::string_view SJNamePrefix = "SJ "; // SJ = Simple Job
  267. if (!visitArgs.m_fieldName.starts_with(RCNamePrefix) && !visitArgs.m_fieldName.starts_with(SJNamePrefix))
  268. {
  269. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  270. }
  271. AZStd::string_view sjNameView = visitArgs.m_fieldName.starts_with(SJNamePrefix)
  272. ? visitArgs.m_fieldName.substr(SJNamePrefix.size())
  273. : visitArgs.m_fieldName.substr(RCNamePrefix.size());
  274. auto& assetRecognizer = m_assetRecognizers.emplace_back();
  275. assetRecognizer.m_recognizer.m_name = sjNameView;
  276. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  277. if (bool value;
  278. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/ignore"))
  279. {
  280. assetRecognizer.m_ignore = value;
  281. }
  282. if (bool value;
  283. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/lockSource"))
  284. {
  285. assetRecognizer.m_recognizer.m_testLockSource = value;
  286. }
  287. if (bool value;
  288. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/critical"))
  289. {
  290. assetRecognizer.m_recognizer.m_isCritical = value;
  291. }
  292. if (bool value;
  293. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/checkServer"))
  294. {
  295. assetRecognizer.m_recognizer.m_checkServer = value;
  296. }
  297. if (bool value;
  298. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/supportsCreateJobs"))
  299. {
  300. assetRecognizer.m_recognizer.m_supportsCreateJobs = value;
  301. }
  302. if (bool value;
  303. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/outputProductDependencies"))
  304. {
  305. assetRecognizer.m_recognizer.m_outputProductDependencies = value;
  306. }
  307. if (AZ::s64 value;
  308. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/priority"))
  309. {
  310. assetRecognizer.m_recognizer.m_priority = static_cast<int>(value);
  311. }
  312. // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values
  313. // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the
  314. // backslash character used to escape other characters, therefore causing a "double escape"
  315. // situation
  316. auto UnescapePattern = [](AZStd::string_view pattern)
  317. {
  318. constexpr AZStd::string_view backslashEscape = R"(\\)";
  319. AZStd::string unescapedResult;
  320. while (!pattern.empty())
  321. {
  322. size_t pos = pattern.find(backslashEscape);
  323. if (pos != AZStd::string_view::npos)
  324. {
  325. unescapedResult += pattern.substr(0, pos);
  326. unescapedResult += '\\';
  327. // Move the pattern string after the double backslash characters
  328. pattern = pattern.substr(pos + backslashEscape.size());
  329. }
  330. else
  331. {
  332. unescapedResult += pattern;
  333. pattern = {};
  334. }
  335. }
  336. return unescapedResult;
  337. };
  338. if (AZStd::string value;
  339. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/pattern"))
  340. {
  341. if (!value.empty())
  342. {
  343. const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex;
  344. assetRecognizer.m_recognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
  345. }
  346. }
  347. if (AZStd::string value;
  348. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/glob"))
  349. {
  350. // Add the glob pattern if it the matter matcher doesn't already contain a valid regex pattern
  351. if (!assetRecognizer.m_recognizer.m_patternMatcher.IsValid())
  352. {
  353. const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard;
  354. assetRecognizer.m_recognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
  355. }
  356. }
  357. if (AZStd::string value;
  358. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/version"))
  359. {
  360. assetRecognizer.m_recognizer.m_version = value;
  361. }
  362. if (AZStd::string value;
  363. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/productAssetType"))
  364. {
  365. if (!value.empty())
  366. {
  367. AZ::Uuid productAssetType{ value.data(), value.size() };
  368. if (!productAssetType.IsNull())
  369. {
  370. assetRecognizer.m_recognizer.m_productAssetType = productAssetType;
  371. }
  372. }
  373. }
  374. if (AZStd::string value;
  375. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/params"))
  376. {
  377. assetRecognizer.m_defaultParams = value;
  378. }
  379. ApplyParamsOverrides(visitArgs, assetRecognizer);
  380. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  381. }
  382. void SimpleJobVisitor::ApplyParamsOverrides(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, SimpleJobAssetRecognizer& assetRecognizer)
  383. {
  384. /* so in this particular case we want to end up with an AssetPlatformSpec struct that
  385. has only got the platforms that 'matter' in it
  386. so for example, if you have the following enabled platforms
  387. [Platform PC]
  388. tags=blah
  389. [Platform Mac]
  390. tags=whatever
  391. [Platform android]
  392. tags=mobile
  393. and you encounter a recognizer like:
  394. [SJ blahblah]
  395. pattern=whatever
  396. params=abc
  397. mac=skip
  398. mobile=hijklmnop
  399. android=1234
  400. then the outcome should be a recognizer which has:
  401. pattern=whatever
  402. pc=abc -- no tags or platforms matched but we do have a default params
  403. android=1234 -- because even though it matched the mobile tag, platforms explicitly specified take precedence
  404. (and no mac) -- because it matched a skip rule
  405. So the strategy will be to read the default params
  406. - if present, we pre-populate all the platforms with it
  407. - If missing, we pre-populate nothing
  408. Then loop over the other params and
  409. if the key matches a tag, if it does we add/change that platform
  410. (if its 'skip' we remove it)
  411. if the key matches a platform, if it does we add/change that platform
  412. (if its 'skip' we remove it)
  413. */
  414. for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
  415. {
  416. // Exclude the common platform from the internal copy builder, we don't support it as an output for assets currently
  417. if(platform.m_identifier == AssetBuilderSDK::CommonPlatformName)
  418. {
  419. continue;
  420. }
  421. AZStd::string_view currentParams = assetRecognizer.m_defaultParams;
  422. // The "/Amazon/AssetProcessor/Settings/SJ */<platform>" entry will be queried
  423. AZ::IO::Path overrideParamsKey = AZ::IO::Path(AZ::IO::PosixPathSeparator);
  424. overrideParamsKey /= visitArgs.m_jsonKeyPath;
  425. overrideParamsKey /= platform.m_identifier;
  426. AZ::SettingsRegistryInterface::FixedValueString overrideParamsValue;
  427. // Check if the enabled platform identifier matches a key within the "SJ *" object
  428. if (visitArgs.m_registry.Get(overrideParamsValue, overrideParamsKey.Native()))
  429. {
  430. currentParams = overrideParamsValue;
  431. }
  432. else
  433. {
  434. // otherwise check for tags associated with the platform
  435. for (const AZStd::string& tag : platform.m_tags)
  436. {
  437. overrideParamsKey.ReplaceFilename(AZ::IO::PathView(tag));
  438. if (visitArgs.m_registry.Get(overrideParamsValue, overrideParamsKey.Native()))
  439. {
  440. // if we get here it means we found a tag that applies to this platform
  441. currentParams = overrideParamsValue;
  442. break;
  443. }
  444. }
  445. }
  446. // now generate a platform spec as long as we're not skipping
  447. if (!AZ::StringFunc::Equal(currentParams, "skip"))
  448. {
  449. assetRecognizer.m_recognizer.m_platformSpecs[platform.m_identifier] = AssetInternalSpec::Copy;
  450. }
  451. }
  452. }
  453. AZ::SettingsRegistryInterface::VisitResponse ACSVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
  454. {
  455. constexpr AZStd::string_view ACSNamePrefix = "ACS ";
  456. if (!visitArgs.m_fieldName.starts_with(ACSNamePrefix))
  457. {
  458. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  459. }
  460. AZStd::string name = visitArgs.m_fieldName.substr(ACSNamePrefix.size());
  461. AssetRecognizer& assetRecognizer = m_assetRecognizers.emplace_back();
  462. assetRecognizer.m_name = name;
  463. using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
  464. if (bool value;
  465. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/lockSource"))
  466. {
  467. assetRecognizer.m_testLockSource = value;
  468. }
  469. if (bool value;
  470. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/critical"))
  471. {
  472. assetRecognizer.m_isCritical = value;
  473. }
  474. if (bool value;
  475. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/checkServer"))
  476. {
  477. assetRecognizer.m_checkServer = value;
  478. }
  479. if (bool value;
  480. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/supportsCreateJobs"))
  481. {
  482. assetRecognizer.m_supportsCreateJobs = value;
  483. }
  484. if (bool value;
  485. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/outputProductDependencies"))
  486. {
  487. assetRecognizer.m_outputProductDependencies = value;
  488. }
  489. if (AZ::s64 value;
  490. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/priority"))
  491. {
  492. assetRecognizer.m_priority = aznumeric_cast<int>(value);
  493. }
  494. // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values
  495. // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the
  496. // backslash character used to escape other characters, therefore causing a "double escape"
  497. // situation
  498. auto UnescapePattern = [](AZStd::string_view pattern)
  499. {
  500. constexpr AZStd::string_view backslashEscape = R"(\\)";
  501. AZStd::string unescapedResult;
  502. while (!pattern.empty())
  503. {
  504. size_t pos = pattern.find(backslashEscape);
  505. if (pos != AZStd::string_view::npos)
  506. {
  507. unescapedResult += pattern.substr(0, pos);
  508. unescapedResult += '\\';
  509. // Move the pattern string after the double backslash characters
  510. pattern = pattern.substr(pos + backslashEscape.size());
  511. }
  512. else
  513. {
  514. unescapedResult += pattern;
  515. pattern = {};
  516. }
  517. }
  518. return unescapedResult;
  519. };
  520. if (AZStd::string value;
  521. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/pattern"))
  522. {
  523. if (!value.empty())
  524. {
  525. const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex;
  526. assetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
  527. }
  528. }
  529. if (AZStd::string value;
  530. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/glob"))
  531. {
  532. // Add the glob pattern if it the matter matcher doesn't already contain a valid regex pattern
  533. if (!assetRecognizer.m_patternMatcher.IsValid())
  534. {
  535. const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard;
  536. assetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
  537. }
  538. }
  539. if (AZStd::string value;
  540. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/version"))
  541. {
  542. assetRecognizer.m_version = value;
  543. }
  544. if (AZStd::string value;
  545. visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/productAssetType"))
  546. {
  547. if (!value.empty())
  548. {
  549. AZ::Uuid productAssetType{ value.data(), value.size() };
  550. if (!productAssetType.IsNull())
  551. {
  552. assetRecognizer.m_productAssetType = productAssetType;
  553. }
  554. }
  555. }
  556. return AZ::SettingsRegistryInterface::VisitResponse::Skip;
  557. }
  558. const char AssetConfigPlatformDir[] = "AssetProcessorConfig/";
  559. const char AssetProcessorPlatformConfigFileName[] = "AssetProcessorPlatformConfig.ini";
  560. constexpr const char* ProjectScanFolderKey = "Project/Assets";
  561. constexpr const char* GemStartingPriorityOrderKey = "/GemScanFolderStartingPriorityOrder";
  562. constexpr const char* ProjectRelativeGemPriorityKey = "/ProjectRelativeGemsScanFolderPriority";
  563. PlatformConfiguration::PlatformConfiguration(QObject* pParent)
  564. : QObject(pParent)
  565. , m_minJobs(1)
  566. , m_maxJobs(8)
  567. {
  568. }
  569. bool PlatformConfiguration::AddPlatformConfigFilePaths(AZStd::vector<AZ::IO::Path>& configFilePaths)
  570. {
  571. auto settingsRegistry = AZ::SettingsRegistry::Get();
  572. if (settingsRegistry == nullptr)
  573. {
  574. AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not available, the "
  575. "Engine Root folder cannot be queried")
  576. return false;
  577. }
  578. AZ::IO::FixedMaxPath engineRoot;
  579. if (!settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
  580. {
  581. AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to find Engine Root in Settings Registry");
  582. return false;
  583. }
  584. return AzToolsFramework::AssetUtils::AddPlatformConfigFilePaths(engineRoot.Native(), configFilePaths);
  585. }
  586. bool PlatformConfiguration::InitializeFromConfigFiles(const QString& absoluteSystemRoot, const QString& absoluteAssetRoot,
  587. const QString& projectPath, bool addPlatformConfigs, bool addGemsConfigs)
  588. {
  589. // this function may look strange, but the point here is that each section in the config file
  590. // can depend on entries from the prior section, but also, each section can be overridden by
  591. // the other config files.
  592. // so we have to read each section one at a time, in order of config file priority (most important one last)
  593. static const char ScanFolderOption[] = "scanfolders";
  594. const AzFramework::CommandLine* commandLine = nullptr;
  595. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
  596. const bool scanFolderOverride = commandLine ? commandLine->HasSwitch(ScanFolderOption) : false;
  597. static const char NoConfigScanFolderOption[] = "noConfigScanFolders";
  598. const bool noConfigScanFolders = commandLine ? commandLine->HasSwitch(NoConfigScanFolderOption) : false;
  599. static const char NoGemScanFolderOption[] = "noGemScanFolders";
  600. const bool noGemScanFolders = commandLine ? commandLine->HasSwitch(NoGemScanFolderOption) : false;
  601. static const char ScanFolderPatternOption[] = "scanfolderpattern";
  602. QStringList scanFolderPatterns;
  603. if (commandLine && commandLine->HasSwitch(ScanFolderPatternOption))
  604. {
  605. for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(ScanFolderPatternOption); idx++)
  606. {
  607. scanFolderPatterns.push_back(commandLine->GetSwitchValue(ScanFolderPatternOption, idx).c_str());
  608. }
  609. }
  610. auto settingsRegistry = AZ::SettingsRegistry::Get();
  611. if (settingsRegistry == nullptr)
  612. {
  613. AZ_Error(AssetProcessor::ConsoleChannel, false, "There is no Global Settings Registry set."
  614. " Unable to merge AssetProcessor config files(*.ini) and Asset processor settings registry files(*.setreg)");
  615. return false;
  616. }
  617. AZStd::vector<AZ::IO::Path> configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(absoluteSystemRoot.toUtf8().constData(),
  618. projectPath.toUtf8().constData(),
  619. addPlatformConfigs, addGemsConfigs && !noGemScanFolders, settingsRegistry);
  620. // First Merge all Engine, Gem and Project specific AssetProcessor*Config.setreg/.inifiles
  621. for (const AZ::IO::Path& configFile : configFiles)
  622. {
  623. if (AZ::IO::SystemFile::Exists(configFile.c_str()))
  624. {
  625. MergeConfigFileToSettingsRegistry(*settingsRegistry, configFile);
  626. }
  627. }
  628. // Merge the Command Line to the Settings Registry after merging the AssetProcessor*Config.setreg/ini files
  629. // to allow the command line to override the settings
  630. #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
  631. if (commandLine)
  632. {
  633. AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, *commandLine, {});
  634. }
  635. #endif
  636. // first, read the platform informations.
  637. ReadPlatformInfosFromSettingsRegistry();
  638. // now read which platforms are currently enabled - this may alter the platform infos array and eradicate
  639. // the ones that are not suitable and currently enabled, leaving only the ones enabled either on command line
  640. // or config files.
  641. // the command line can always takes precedence - but can only turn on and off platforms, it cannot describe them.
  642. PopulateEnabledPlatforms();
  643. FinalizeEnabledPlatforms();
  644. if(!m_enabledPlatforms.empty())
  645. {
  646. // Add the common platform if we have some other platforms enabled. For now, this is only intended for intermediate assets
  647. // So we don't want to enable it unless at least one actual platform is available, to avoid hiding an error state of no real platforms being active
  648. EnableCommonPlatform();
  649. }
  650. if (scanFolderOverride)
  651. {
  652. AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
  653. PopulatePlatformsForScanFolder(platforms);
  654. for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(ScanFolderOption); idx++)
  655. {
  656. QString scanFolder{ commandLine->GetSwitchValue(ScanFolderOption, idx).c_str() };
  657. scanFolder = AssetUtilities::NormalizeFilePath(scanFolder);
  658. AddScanFolder(ScanFolderInfo(
  659. scanFolder,
  660. AZStd::string::format("ScanFolderParam %zu", idx).c_str(),
  661. AZStd::string::format("SF%zu", idx).c_str(),
  662. false,
  663. true,
  664. platforms,
  665. aznumeric_caster(idx),
  666. /*scanFolderId*/ 0,
  667. true));
  668. }
  669. }
  670. // Then read recognizers (which depend on platforms)
  671. if (!ReadRecognizersFromSettingsRegistry(absoluteAssetRoot, noConfigScanFolders, scanFolderPatterns))
  672. {
  673. if (m_fatalError.empty())
  674. {
  675. m_fatalError = "Unable to read recognizers specified in the configuration files during load. Please check the Asset Processor platform ini files for errors.";
  676. }
  677. return IsValid();
  678. }
  679. if(!m_scanFolders.empty())
  680. {
  681. // Enable the intermediate scanfolder if we have some other scanfolders. Since this is hardcoded we don't want to hide an error state
  682. // where no other scanfolders are enabled besides this one. It wouldn't make sense for the intermediate scanfolder to be the only enabled scanfolder
  683. AddIntermediateScanFolder();
  684. }
  685. if (!noGemScanFolders && addGemsConfigs)
  686. {
  687. if (settingsRegistry == nullptr || !AzFramework::GetGemsInfo(m_gemInfoList, *settingsRegistry))
  688. {
  689. AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to Get Gems Info for the project (%s).", projectPath.toUtf8().constData());
  690. return false;
  691. }
  692. // now add all the scan folders of gems.
  693. AddGemScanFolders(m_gemInfoList);
  694. }
  695. // Then read metadata (which depends on scan folders)
  696. ReadMetaDataFromSettingsRegistry();
  697. // at this point there should be at least some watch folders besides gems.
  698. if (m_scanFolders.empty())
  699. {
  700. m_fatalError = "Unable to find any scan folders specified in the configuration files during load. Please check the Asset Processor platform ini files for errors.";
  701. return IsValid();
  702. }
  703. return IsValid();
  704. }
  705. void PlatformConfiguration::PopulateEnabledPlatforms()
  706. {
  707. // if there are no platform informations inside the ini file, there's no point in proceeding
  708. // since we are unaware of the existence of the platform at all
  709. if (m_enabledPlatforms.empty())
  710. {
  711. AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no \"%s/Platform xxxxxx\" entries present in the settings registry. We cannot proceed.",
  712. AssetProcessorSettingsKey);
  713. return;
  714. }
  715. // the command line can always takes precedence - but can only turn on and off platforms, it cannot describe them.
  716. QStringList commandLinePlatforms = AssetUtilities::ReadPlatformsFromCommandLine();
  717. if (!commandLinePlatforms.isEmpty())
  718. {
  719. // command line overrides everything.
  720. m_tempEnabledPlatforms.clear();
  721. for (const QString& platformFromCommandLine : commandLinePlatforms)
  722. {
  723. QString platform = platformFromCommandLine.toLower().trimmed();
  724. if (!platform.isEmpty())
  725. {
  726. AZStd::string platformOverride{ platform.toUtf8().data() };
  727. if (auto foundIt = AZStd::find(m_tempEnabledPlatforms.begin(), m_tempEnabledPlatforms.end(), platformOverride);
  728. foundIt == m_tempEnabledPlatforms.end())
  729. {
  730. m_tempEnabledPlatforms.push_back(AZStd::move(platformOverride));
  731. }
  732. }
  733. }
  734. return; // command line wins!
  735. }
  736. // command line isn't active, read from settings registry instead.
  737. auto settingsRegistry = AZ::SettingsRegistry::Get();
  738. if (settingsRegistry == nullptr)
  739. {
  740. AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platforms")"
  741. " settings paths", AssetProcessorSettingsKey);
  742. return;
  743. }
  744. AZStd::vector<AZStd::string> enabledPlatforms;
  745. AzToolsFramework::AssetUtils::ReadEnabledPlatformsFromSettingsRegistry(*settingsRegistry, enabledPlatforms);
  746. m_tempEnabledPlatforms.insert(m_tempEnabledPlatforms.end(), AZStd::make_move_iterator(enabledPlatforms.begin()),
  747. AZStd::make_move_iterator(enabledPlatforms.end()));
  748. }
  749. void PlatformConfiguration::FinalizeEnabledPlatforms()
  750. {
  751. #if defined(AZ_ENABLE_TRACING)
  752. // verify command line platforms are valid:
  753. for (const auto& enabledPlatformFromConfigs : m_tempEnabledPlatforms)
  754. {
  755. bool found = false;
  756. for (const AssetBuilderSDK::PlatformInfo& platformInfo : m_enabledPlatforms)
  757. {
  758. if (platformInfo.m_identifier == enabledPlatformFromConfigs)
  759. {
  760. found = true;
  761. break;
  762. }
  763. }
  764. if (!found)
  765. {
  766. m_fatalError = AZStd::string::format(R"(The list of enabled platforms in the settings registry does not contain platform "%s")"
  767. " entries - check command line and settings registry files for errors!", enabledPlatformFromConfigs.c_str());
  768. return;
  769. }
  770. }
  771. #endif // defined(AZ_ENABLE_TRACING)
  772. // over here, we want to eliminate any platforms in the m_enabledPlatforms array that are not in the m_tempEnabledPlatforms
  773. for (int enabledPlatformIdx = static_cast<int>(m_enabledPlatforms.size() - 1); enabledPlatformIdx >= 0; --enabledPlatformIdx)
  774. {
  775. const AssetBuilderSDK::PlatformInfo& platformInfo = m_enabledPlatforms[enabledPlatformIdx];
  776. if (auto foundIt = AZStd::find(m_tempEnabledPlatforms.begin(), m_tempEnabledPlatforms.end(), platformInfo.m_identifier);
  777. foundIt == m_tempEnabledPlatforms.end())
  778. {
  779. m_enabledPlatforms.erase(m_enabledPlatforms.cbegin() + enabledPlatformIdx);
  780. }
  781. }
  782. if (m_enabledPlatforms.empty())
  783. {
  784. AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no \"%s/Platform xxxxxx\" entry present in the settings registry. We cannot proceed.",
  785. AssetProcessorSettingsKey);
  786. return;
  787. }
  788. m_tempEnabledPlatforms.clear();
  789. }
  790. void PlatformConfiguration::ReadPlatformInfosFromSettingsRegistry()
  791. {
  792. auto settingsRegistry = AZ::SettingsRegistry::Get();
  793. if (settingsRegistry == nullptr)
  794. {
  795. AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platform *")"
  796. " settings paths", AssetProcessorSettingsKey);
  797. return;
  798. }
  799. PlatformsInfoVisitor visitor;
  800. settingsRegistry->Visit(visitor, AssetProcessorSettingsKey);
  801. for (const AssetBuilderSDK::PlatformInfo& platformInfo : visitor.m_platformInfos)
  802. {
  803. EnablePlatform(platformInfo, true);
  804. }
  805. }
  806. void PlatformConfiguration::ReadEnabledPlatformsFromSettingsRegistry()
  807. {
  808. auto settingsRegistry = AZ::SettingsRegistry::Get();
  809. if (settingsRegistry == nullptr)
  810. {
  811. AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platforms")"
  812. " settings paths", AssetProcessorSettingsKey);
  813. return;
  814. }
  815. AzToolsFramework::AssetUtils::ReadEnabledPlatformsFromSettingsRegistry(*settingsRegistry, m_tempEnabledPlatforms);
  816. }
  817. void PlatformConfiguration::PopulatePlatformsForScanFolder(AZStd::vector<AssetBuilderSDK::PlatformInfo>& platformsList, QStringList includeTagsList, QStringList excludeTagsList)
  818. {
  819. if (includeTagsList.isEmpty())
  820. {
  821. // Add all enabled platforms
  822. for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
  823. {
  824. if(platform.m_identifier == AssetBuilderSDK::CommonPlatformName)
  825. {
  826. // The common platform is not included in any scanfolder to avoid builders by-default producing jobs for it
  827. continue;
  828. }
  829. if (AZStd::find(platformsList.begin(), platformsList.end(), platform) == platformsList.end())
  830. {
  831. platformsList.push_back(platform);
  832. }
  833. }
  834. }
  835. else
  836. {
  837. for (QString identifier : includeTagsList)
  838. {
  839. for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
  840. {
  841. if(platform.m_identifier == AssetBuilderSDK::CommonPlatformName)
  842. {
  843. // The common platform is not included in any scanfolder to avoid builders by-default producing jobs for it
  844. continue;
  845. }
  846. bool addPlatform = (QString::compare(identifier, platform.m_identifier.c_str(), Qt::CaseInsensitive) == 0) ||
  847. platform.m_tags.find(identifier.toLower().toUtf8().data()) != platform.m_tags.end();
  848. if (addPlatform)
  849. {
  850. if (AZStd::find(platformsList.begin(), platformsList.end(), platform) == platformsList.end())
  851. {
  852. platformsList.push_back(platform);
  853. }
  854. }
  855. }
  856. }
  857. }
  858. for (QString identifier : excludeTagsList)
  859. {
  860. for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
  861. {
  862. bool removePlatform = (QString::compare(identifier, platform.m_identifier.c_str(), Qt::CaseInsensitive) == 0) ||
  863. platform.m_tags.find(identifier.toLower().toUtf8().data()) != platform.m_tags.end();
  864. if (removePlatform)
  865. {
  866. platformsList.erase(AZStd::remove(platformsList.begin(), platformsList.end(), platform), platformsList.end());
  867. }
  868. }
  869. }
  870. }
  871. void PlatformConfiguration::CacheIntermediateAssetsScanFolderId() const
  872. {
  873. for (const auto& scanfolder : m_scanFolders)
  874. {
  875. if (scanfolder.GetPortableKey() == AssetProcessor::IntermediateAssetsFolderName)
  876. {
  877. m_intermediateAssetScanFolderId = scanfolder.ScanFolderID();
  878. return;
  879. }
  880. }
  881. AZ_Error(
  882. "PlatformConfiguration", false,
  883. "CacheIntermediateAssetsScanFolderId: Failed to find Intermediate Assets folder in scanfolder list");
  884. }
  885. AZStd::optional<AZ::s64> PlatformConfiguration::GetIntermediateAssetsScanFolderId() const
  886. {
  887. if (m_intermediateAssetScanFolderId >= 0)
  888. {
  889. return m_intermediateAssetScanFolderId;
  890. }
  891. return AZStd::nullopt;
  892. }
  893. // used to save our the AssetCacheServer settings to a remote location
  894. struct AssetCacheServerMatcher
  895. {
  896. AZ_CLASS_ALLOCATOR(AssetCacheServerMatcher, AZ::SystemAllocator);
  897. AZ_TYPE_INFO(AssetCacheServerMatcher, "{329A59C9-755E-4FA9-AADB-05C50AC62FD5}");
  898. static void Reflect(AZ::SerializeContext* serializeContext)
  899. {
  900. serializeContext->Class<AssetCacheServerMatcher>()->Version(0)
  901. ->Field("name", &AssetCacheServerMatcher::m_name)
  902. ->Field("glob", &AssetCacheServerMatcher::m_glob)
  903. ->Field("pattern", &AssetCacheServerMatcher::m_pattern)
  904. ->Field("productAssetType", &AssetCacheServerMatcher::m_productAssetType)
  905. ->Field("checkServer", &AssetCacheServerMatcher::m_checkServer);
  906. serializeContext->RegisterGenericType<AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher>>();
  907. }
  908. AZStd::string m_name;
  909. AZStd::string m_glob;
  910. AZStd::string m_pattern;
  911. AZ::Uuid m_productAssetType = AZ::Uuid::CreateNull();
  912. bool m_checkServer = false;
  913. };
  914. bool PlatformConfiguration::ConvertToJson(const RecognizerContainer& recognizerContainer, AZStd::string& jsonText)
  915. {
  916. AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher> assetCacheServerMatcherMap;
  917. for (const auto& recognizer : recognizerContainer)
  918. {
  919. AssetCacheServerMatcher matcher;
  920. matcher.m_name = recognizer.first;
  921. matcher.m_checkServer = recognizer.second.m_checkServer;
  922. matcher.m_productAssetType = recognizer.second.m_productAssetType;
  923. if (recognizer.second.m_patternMatcher.GetBuilderPattern().m_type == AssetBuilderSDK::AssetBuilderPattern::Wildcard)
  924. {
  925. matcher.m_glob = recognizer.second.m_patternMatcher.GetBuilderPattern().m_pattern;
  926. }
  927. else if (recognizer.second.m_patternMatcher.GetBuilderPattern().m_type == AssetBuilderSDK::AssetBuilderPattern::Regex)
  928. {
  929. matcher.m_pattern = recognizer.second.m_patternMatcher.GetBuilderPattern().m_pattern;
  930. }
  931. assetCacheServerMatcherMap.insert({"ACS " + matcher.m_name, matcher});
  932. }
  933. AZ::JsonSerializerSettings settings;
  934. AZ::ComponentApplicationBus::BroadcastResult(settings.m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
  935. settings.m_registrationContext = nullptr;
  936. rapidjson::Document jsonDocument;
  937. auto jsonResult = AZ::JsonSerialization::Store(jsonDocument, jsonDocument.GetAllocator(), assetCacheServerMatcherMap, settings);
  938. if (jsonResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
  939. {
  940. return false;
  941. }
  942. auto saveToFileOutcome = AZ::JsonSerializationUtils::WriteJsonString(jsonDocument, jsonText);
  943. return saveToFileOutcome.IsSuccess();
  944. }
  945. bool PlatformConfiguration::ConvertFromJson(const AZStd::string& jsonText, RecognizerContainer& recognizerContainer)
  946. {
  947. rapidjson::Document assetCacheServerMatcherDoc;
  948. assetCacheServerMatcherDoc.Parse(jsonText.c_str());
  949. if (assetCacheServerMatcherDoc.HasParseError())
  950. {
  951. return false;
  952. }
  953. AZ::JsonDeserializerSettings settings;
  954. AZ::ComponentApplicationBus::BroadcastResult(settings.m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
  955. settings.m_registrationContext = nullptr;
  956. AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher> assetCacheServerMatcherMap;
  957. auto resultCode = AZ::JsonSerialization::Load(assetCacheServerMatcherMap, assetCacheServerMatcherDoc, settings);
  958. if (!resultCode.HasDoneWork())
  959. {
  960. return false;
  961. }
  962. recognizerContainer.clear();
  963. for (const auto& matcher : assetCacheServerMatcherMap)
  964. {
  965. AssetRecognizer assetRecognizer;
  966. assetRecognizer.m_checkServer = matcher.second.m_checkServer;
  967. assetRecognizer.m_name = matcher.second.m_name;
  968. assetRecognizer.m_productAssetType = matcher.second.m_productAssetType;
  969. if (!matcher.second.m_glob.empty())
  970. {
  971. assetRecognizer.m_patternMatcher = { matcher.second.m_glob , AssetBuilderSDK::AssetBuilderPattern::Wildcard };
  972. }
  973. else if (!matcher.second.m_pattern.empty())
  974. {
  975. assetRecognizer.m_patternMatcher = { matcher.second.m_pattern , AssetBuilderSDK::AssetBuilderPattern::Regex };
  976. }
  977. recognizerContainer.insert({ "ACS " + matcher.second.m_name, assetRecognizer });
  978. }
  979. return !recognizerContainer.empty();
  980. }
  981. void PlatformConfiguration::Reflect(AZ::ReflectContext* context)
  982. {
  983. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  984. {
  985. AssetCacheServerMatcher::Reflect(serializeContext);
  986. }
  987. }
  988. bool PlatformConfiguration::ReadRecognizersFromSettingsRegistry(const QString& assetRoot, bool skipScanFolders, QStringList scanFolderPatterns)
  989. {
  990. auto settingsRegistry = AZ::SettingsRegistry::Get();
  991. if (settingsRegistry == nullptr)
  992. {
  993. AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not set."
  994. " Unable to read recognizers Asset Processor Settings");
  995. return false;
  996. }
  997. AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
  998. AZ::IO::FixedMaxPathString projectName = AZ::Utils::GetProjectName();
  999. AZ::IO::FixedMaxPathString executableDirectory = AZ::Utils::GetExecutableDirectory();
  1000. AZ::IO::FixedMaxPath engineRoot(AZ::IO::PosixPathSeparator);
  1001. settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
  1002. engineRoot = engineRoot.LexicallyNormal(); // Normalize the path to use posix slashes
  1003. AZ::s64 jobCount = m_minJobs;
  1004. if (settingsRegistry->Get(jobCount, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/Jobs/minJobs"))
  1005. {
  1006. m_minJobs = aznumeric_cast<int>(jobCount);
  1007. }
  1008. jobCount = m_maxJobs;
  1009. if (settingsRegistry->Get(jobCount, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/Jobs/maxJobs"))
  1010. {
  1011. m_maxJobs = aznumeric_cast<int>(jobCount);
  1012. }
  1013. if (!skipScanFolders)
  1014. {
  1015. AZStd::unordered_map<AZStd::string, AZ::IO::Path> gemNameToPathMap;
  1016. auto MakeGemNameToPathMap = [&gemNameToPathMap, &projectPath, &engineRoot]
  1017. (AZStd::string_view gemName, AZ::IO::PathView gemPath)
  1018. {
  1019. AZ::IO::FixedMaxPath gemAbsPath = gemPath;
  1020. if (gemPath.IsRelative())
  1021. {
  1022. gemAbsPath = projectPath / gemPath;
  1023. if (!AZ::IO::SystemFile::Exists(gemAbsPath.c_str()))
  1024. {
  1025. gemAbsPath = engineRoot / gemPath;
  1026. }
  1027. // convert the relative path to an absolute path
  1028. if (!AZ::IO::SystemFile::Exists(gemAbsPath.c_str()))
  1029. {
  1030. if (auto gemAbsPathOpt = AZ::Utils::ConvertToAbsolutePath(gemPath.Native());
  1031. gemAbsPathOpt.has_value())
  1032. {
  1033. gemAbsPath = AZStd::move(*gemAbsPathOpt);
  1034. }
  1035. }
  1036. }
  1037. if (AZ::IO::SystemFile::Exists(gemAbsPath.c_str()))
  1038. {
  1039. gemNameToPathMap.try_emplace(AZStd::string::format("@GEMROOT:%.*s@", AZ_STRING_ARG(gemName)), gemAbsPath.AsPosix());
  1040. }
  1041. };
  1042. AZ::SettingsRegistryMergeUtils::VisitActiveGems(*settingsRegistry, MakeGemNameToPathMap);
  1043. ScanFolderVisitor visitor;
  1044. settingsRegistry->Visit(visitor, AssetProcessorSettingsKey);
  1045. for (auto& scanFolderEntry : visitor.m_scanFolderInfos)
  1046. {
  1047. if (scanFolderEntry.m_watchPath.empty())
  1048. {
  1049. continue;
  1050. }
  1051. auto scanFolderMatch = [watchFolderQt = QString::fromUtf8(scanFolderEntry.m_watchPath.c_str(),
  1052. aznumeric_cast<int>(scanFolderEntry.m_watchPath.Native().size()))](const QString& scanFolderPattern)
  1053. {
  1054. QRegExp nameMatch(scanFolderPattern, Qt::CaseInsensitive, QRegExp::Wildcard);
  1055. return nameMatch.exactMatch(watchFolderQt);
  1056. };
  1057. if (!scanFolderPatterns.empty() && AZStd::none_of(scanFolderPatterns.begin(), scanFolderPatterns.end(), scanFolderMatch))
  1058. {
  1059. // Continue to the next iteration if the watch folder doesn't match any of the supplied patterns
  1060. continue;
  1061. }
  1062. // Substitute macro values into the watch path and the scan folder display name
  1063. AZStd::string assetRootPath = assetRoot.toUtf8().data();
  1064. AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@ROOT@", assetRootPath.c_str());
  1065. AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@PROJECTROOT@", projectPath.c_str());
  1066. AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@ENGINEROOT@", engineRoot.c_str());
  1067. AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@EXEFOLDER@", executableDirectory.c_str());
  1068. // Normalize path make sure it is using posix slashes
  1069. scanFolderEntry.m_watchPath = scanFolderEntry.m_watchPath.LexicallyNormal();
  1070. AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@ROOT@", assetRootPath.c_str());
  1071. AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@PROJECTROOT@", projectPath.c_str());
  1072. AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@PROJECTNAME@", projectName.c_str());
  1073. AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@ENGINEROOT@", engineRoot.c_str());
  1074. // Substitute gem root path if applicable
  1075. if (scanFolderEntry.m_watchPath.Native().contains("@GEMROOT")
  1076. || scanFolderEntry.m_scanFolderDisplayName.contains("@GEMROOT"))
  1077. {
  1078. for (const auto& [gemAlias, gemPath] : gemNameToPathMap)
  1079. {
  1080. AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), gemAlias.c_str(), gemPath.c_str());
  1081. AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, gemAlias.c_str(), gemPath.c_str());
  1082. }
  1083. }
  1084. QStringList includeIdentifiers;
  1085. for (AZStd::string_view includeIdentifier : scanFolderEntry.m_includeIdentifiers)
  1086. {
  1087. includeIdentifiers.push_back(QString::fromUtf8(includeIdentifier.data(), aznumeric_cast<int>(includeIdentifier.size())));
  1088. }
  1089. QStringList excludeIdentifiers;
  1090. for (AZStd::string_view excludeIdentifier : scanFolderEntry.m_excludeIdentifiers)
  1091. {
  1092. excludeIdentifiers.push_back(QString::fromUtf8(excludeIdentifier.data(), aznumeric_cast<int>(excludeIdentifier.size())));
  1093. }
  1094. AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
  1095. PopulatePlatformsForScanFolder(platforms, includeIdentifiers, excludeIdentifiers);
  1096. const bool isEngineRoot = scanFolderEntry.m_watchPath == engineRoot;
  1097. // If the scan folder happens to be the engine root, it is not recursive
  1098. scanFolderEntry.m_isRecursive = scanFolderEntry.m_isRecursive && !isEngineRoot;
  1099. // New assets can be saved in any scan folder defined except for the engine root.
  1100. const bool canSaveNewAssets = !isEngineRoot;
  1101. QString watchFolderPath = QString::fromUtf8(scanFolderEntry.m_watchPath.c_str(), static_cast<int>(scanFolderEntry.m_watchPath.Native().size()));
  1102. watchFolderPath = AssetUtilities::NormalizeDirectoryPath(watchFolderPath);
  1103. AddScanFolder(ScanFolderInfo(
  1104. watchFolderPath,
  1105. QString::fromUtf8(scanFolderEntry.m_scanFolderDisplayName.c_str(), aznumeric_cast<int>(scanFolderEntry.m_scanFolderDisplayName.size())),
  1106. QString::fromUtf8(scanFolderEntry.m_scanFolderIdentifier.c_str(), aznumeric_cast<int>(scanFolderEntry.m_scanFolderIdentifier.size())),
  1107. isEngineRoot,
  1108. scanFolderEntry.m_isRecursive,
  1109. platforms,
  1110. scanFolderEntry.m_scanOrder,
  1111. 0,
  1112. canSaveNewAssets
  1113. ));
  1114. }
  1115. }
  1116. ExcludeVisitor excludeVisitor;
  1117. settingsRegistry->Visit(excludeVisitor, AssetProcessorSettingsKey);
  1118. for (auto&& excludeRecognizer: excludeVisitor.m_excludeAssetRecognizers)
  1119. {
  1120. m_excludeAssetRecognizers[excludeRecognizer.m_name] = AZStd::move(excludeRecognizer);
  1121. }
  1122. SimpleJobVisitor simpleJobVisitor(m_enabledPlatforms);
  1123. settingsRegistry->Visit(simpleJobVisitor, AssetProcessorSettingsKey);
  1124. for (auto&& sjRecognizer : simpleJobVisitor.m_assetRecognizers)
  1125. {
  1126. if (!sjRecognizer.m_recognizer.m_platformSpecs.empty() && !sjRecognizer.m_ignore)
  1127. {
  1128. m_assetRecognizers[sjRecognizer.m_recognizer.m_name] = AZStd::move(sjRecognizer.m_recognizer);
  1129. }
  1130. }
  1131. ACSVisitor acsVistor;
  1132. settingsRegistry->Visit(acsVistor, AssetProcessorServerKey);
  1133. for (auto&& acsRecognizer : acsVistor.m_assetRecognizers)
  1134. {
  1135. m_assetCacheServerRecognizers[acsRecognizer.m_name] = AZStd::move(acsRecognizer);
  1136. }
  1137. return true;
  1138. }
  1139. void PlatformConfiguration::ReadMetaDataFromSettingsRegistry()
  1140. {
  1141. auto settingsRegistry = AZ::SettingsRegistry::Get();
  1142. if (settingsRegistry == nullptr)
  1143. {
  1144. AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not set."
  1145. " MetaDataTypes entries cannot be read from Asset Processor Settings");
  1146. return;
  1147. }
  1148. MetaDataTypesVisitor visitor;
  1149. settingsRegistry->Visit(visitor, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/MetaDataTypes");
  1150. using namespace AzToolsFramework::AssetUtils;
  1151. AZStd::vector<AZStd::string> supportedFileExtensions;
  1152. AssetImporterPathsVisitor assetImporterVisitor{ settingsRegistry, supportedFileExtensions };
  1153. settingsRegistry->Visit(assetImporterVisitor, AZ::SettingsRegistryInterface::FixedValueString(AssetImporterSettingsKey) + "/" + AssetImporterSupportedFileTypeKey);
  1154. for (auto& entry : assetImporterVisitor.m_supportedFileExtensions)
  1155. {
  1156. visitor.m_metaDataTypes.push_back({ AZStd::string::format("%s.assetinfo", entry.c_str()), entry });
  1157. }
  1158. AddMetaDataType(AzToolsFramework::MetadataManager::MetadataFileExtensionNoDot, "");
  1159. for (const auto& metaDataType : visitor.m_metaDataTypes)
  1160. {
  1161. QString fileType = AssetUtilities::NormalizeFilePath(QString::fromUtf8(metaDataType.m_fileType.c_str(),
  1162. aznumeric_cast<int>(metaDataType.m_fileType.size())));
  1163. auto extensionType = QString::fromUtf8(metaDataType.m_extensionType.c_str(),
  1164. aznumeric_cast<int>(metaDataType.m_extensionType.size()));
  1165. AddMetaDataType(fileType, extensionType);
  1166. // Check if the Metadata 'file type' is a real file
  1167. QString fullPath = FindFirstMatchingFile(fileType);
  1168. if (!fullPath.isEmpty())
  1169. {
  1170. m_metaDataRealFiles.insert(fileType.toLower());
  1171. }
  1172. }
  1173. }
  1174. int PlatformConfiguration::GetProjectScanFolderOrder() const
  1175. {
  1176. auto mainProjectScanFolder = FindScanFolder([](const AssetProcessor::ScanFolderInfo& scanFolderInfo) -> bool
  1177. {
  1178. return scanFolderInfo.GetPortableKey() == ProjectScanFolderKey;
  1179. });
  1180. if (mainProjectScanFolder)
  1181. {
  1182. return mainProjectScanFolder->GetOrder();
  1183. }
  1184. return 0;
  1185. }
  1186. bool PlatformConfiguration::MergeConfigFileToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, const AZ::IO::PathView& configFile)
  1187. {
  1188. // If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function
  1189. // otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style
  1190. // file to the settings registry
  1191. if (configFile.Extension() == ".setreg")
  1192. {
  1193. return static_cast<bool>(settingsRegistry.MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  1194. }
  1195. AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings;
  1196. configParserSettings.m_registryRootPointerPath = AssetProcessorSettingsKey;
  1197. return AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(settingsRegistry, configFile.Native(), configParserSettings);
  1198. }
  1199. const AZStd::vector<AssetBuilderSDK::PlatformInfo>& PlatformConfiguration::GetEnabledPlatforms() const
  1200. {
  1201. return m_enabledPlatforms;
  1202. }
  1203. const AssetBuilderSDK::PlatformInfo* const PlatformConfiguration::GetPlatformByIdentifier(const char* identifier) const
  1204. {
  1205. for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
  1206. {
  1207. if (platform.m_identifier == identifier)
  1208. {
  1209. // this may seem odd - returning a pointer into a vector, but this vector is initialized once during startup and then remains static thereafter.
  1210. return &platform;
  1211. }
  1212. }
  1213. return nullptr;
  1214. }
  1215. QPair<QString, QString> PlatformConfiguration::GetMetaDataFileTypeAt(int pos) const
  1216. {
  1217. return m_metaDataFileTypes[pos];
  1218. }
  1219. bool PlatformConfiguration::IsMetaDataTypeRealFile(QString relativeName) const
  1220. {
  1221. return m_metaDataRealFiles.find(relativeName.toLower()) != m_metaDataRealFiles.end();
  1222. }
  1223. void PlatformConfiguration::EnablePlatform(const AssetBuilderSDK::PlatformInfo& platform, bool enable)
  1224. {
  1225. // remove it if present.
  1226. auto platformIt = std::find_if(m_enabledPlatforms.begin(), m_enabledPlatforms.end(), [&](const AssetBuilderSDK::PlatformInfo& info)
  1227. {
  1228. return info.m_identifier == platform.m_identifier;
  1229. });
  1230. if (platformIt != m_enabledPlatforms.end())
  1231. {
  1232. // already present - replace or remove it.
  1233. if (enable)
  1234. {
  1235. *platformIt = platform;
  1236. }
  1237. else
  1238. {
  1239. m_enabledPlatforms.erase(platformIt);
  1240. }
  1241. }
  1242. else
  1243. {
  1244. // it is not already present. we only add it if we're enabling.
  1245. // if we're disabling, there's nothing to do.
  1246. if (enable)
  1247. {
  1248. m_enabledPlatforms.push_back(platform);
  1249. }
  1250. }
  1251. }
  1252. bool PlatformConfiguration::GetMatchingRecognizers(QString fileName, RecognizerPointerContainer& output) const
  1253. {
  1254. bool foundAny = false;
  1255. if (IsFileExcluded(fileName))
  1256. {
  1257. //if the file is excluded than return false;
  1258. return false;
  1259. }
  1260. for (const auto& assetRecognizer : m_assetRecognizers)
  1261. {
  1262. const AssetRecognizer& recognizer = assetRecognizer.second;
  1263. if (recognizer.m_patternMatcher.MatchesPath(fileName.toUtf8().constData()))
  1264. {
  1265. // found a match
  1266. output.push_back(&recognizer);
  1267. foundAny = true;
  1268. }
  1269. }
  1270. return foundAny;
  1271. }
  1272. int PlatformConfiguration::GetScanFolderCount() const
  1273. {
  1274. return aznumeric_caster(m_scanFolders.size());
  1275. }
  1276. AZStd::vector<AzFramework::GemInfo> PlatformConfiguration::GetGemsInformation() const
  1277. {
  1278. return m_gemInfoList;
  1279. }
  1280. AssetProcessor::ScanFolderInfo& PlatformConfiguration::GetScanFolderAt(int index)
  1281. {
  1282. Q_ASSERT(index >= 0);
  1283. Q_ASSERT(index < m_scanFolders.size());
  1284. return m_scanFolders[index];
  1285. }
  1286. const AssetProcessor::ScanFolderInfo& PlatformConfiguration::GetScanFolderAt(int index) const
  1287. {
  1288. Q_ASSERT(index >= 0);
  1289. Q_ASSERT(index < m_scanFolders.size());
  1290. return m_scanFolders[index];
  1291. }
  1292. const AssetProcessor::ScanFolderInfo* PlatformConfiguration::FindScanFolder(
  1293. AZStd::function<bool(const AssetProcessor::ScanFolderInfo&)> predicate) const
  1294. {
  1295. auto resultIt = AZStd::ranges::find_if(m_scanFolders, predicate);
  1296. return resultIt != m_scanFolders.end() ? &(*resultIt) : nullptr;
  1297. }
  1298. const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderById(AZ::s64 id) const
  1299. {
  1300. return FindScanFolder([id](const ScanFolderInfo& scanFolder)
  1301. {
  1302. return scanFolder.ScanFolderID() == id;
  1303. });
  1304. }
  1305. const AZ::s64 PlatformConfiguration::GetIntermediateAssetScanFolderId() const
  1306. {
  1307. return m_intermediateAssetScanFolderId;
  1308. }
  1309. void PlatformConfiguration::AddScanFolder(const AssetProcessor::ScanFolderInfo& source, bool isUnitTesting)
  1310. {
  1311. if (isUnitTesting)
  1312. {
  1313. //using a bool instead of using #define UNIT_TEST because the user can also run batch processing in unittest
  1314. m_scanFolders.push_back(source);
  1315. // since we're synthesizing folder adds, assign ascending folder ids if not provided.
  1316. if (source.ScanFolderID() == 0)
  1317. {
  1318. m_scanFolders.back().SetScanFolderID(m_scanFolders.size() - 1);
  1319. }
  1320. return;
  1321. }
  1322. // Find and remove any previous matching entry, last entry wins
  1323. auto it = std::find_if(m_scanFolders.begin(), m_scanFolders.end(), [&source](const ScanFolderInfo& info)
  1324. {
  1325. return info.GetPortableKey().toLower() == source.GetPortableKey().toLower();
  1326. });
  1327. if (it != m_scanFolders.end())
  1328. {
  1329. m_scanFolders.erase(it);
  1330. }
  1331. m_scanFolders.push_back(source);
  1332. std::stable_sort(m_scanFolders.begin(), m_scanFolders.end(), [](const ScanFolderInfo& a, const ScanFolderInfo& b)
  1333. {
  1334. return a.GetOrder() < b.GetOrder();
  1335. }
  1336. );
  1337. }
  1338. void PlatformConfiguration::AddRecognizer(const AssetRecognizer& source)
  1339. {
  1340. m_assetRecognizers.insert({source.m_name, source});
  1341. }
  1342. void PlatformConfiguration::RemoveRecognizer(QString name)
  1343. {
  1344. auto found = m_assetRecognizers.find(name.toUtf8().data());
  1345. m_assetRecognizers.erase(found);
  1346. }
  1347. void PlatformConfiguration::AddMetaDataType(const QString& type, const QString& extension)
  1348. {
  1349. QPair<QString, QString> key = qMakePair(type.toLower(), extension.toLower());
  1350. if (!m_metaDataFileTypes.contains(key))
  1351. {
  1352. m_metaDataFileTypes.push_back(key);
  1353. }
  1354. }
  1355. bool PlatformConfiguration::ConvertToRelativePath(QString fullFileName, QString& databaseSourceName, QString& scanFolderName) const
  1356. {
  1357. const ScanFolderInfo* info = GetScanFolderForFile(fullFileName);
  1358. if (info)
  1359. {
  1360. scanFolderName = info->ScanPath();
  1361. scanFolderName.replace(AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR);
  1362. return ConvertToRelativePath(fullFileName, info, databaseSourceName);
  1363. }
  1364. // did not find it.
  1365. return false;
  1366. }
  1367. bool PlatformConfiguration::ConvertToRelativePath(const QString& fullFileName, const ScanFolderInfo* scanFolderInfo, QString& databaseSourceName)
  1368. {
  1369. if(!scanFolderInfo)
  1370. {
  1371. return false;
  1372. }
  1373. QString relPath; // empty string.
  1374. if (fullFileName.length() > scanFolderInfo->ScanPath().length())
  1375. {
  1376. relPath = fullFileName.right(fullFileName.length() - scanFolderInfo->ScanPath().length() - 1); // also eat the slash, hence -1
  1377. }
  1378. databaseSourceName = relPath;
  1379. databaseSourceName.replace(AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR);
  1380. return true;
  1381. }
  1382. QString PlatformConfiguration::GetOverridingFile(QString relativeName, QString scanFolderName) const
  1383. {
  1384. for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
  1385. {
  1386. AssetProcessor::ScanFolderInfo scanFolderInfo = m_scanFolders[pathIdx];
  1387. if (scanFolderName.compare(scanFolderInfo.ScanPath(), Qt::CaseInsensitive) == 0)
  1388. {
  1389. // we have found the actual folder containing the file we started with
  1390. // since all other folders "deeper" in the override vector are lower priority than this one
  1391. // (they are sorted in priority order, most priority first).
  1392. return QString();
  1393. }
  1394. QString tempRelativeName(relativeName);
  1395. if ((!scanFolderInfo.RecurseSubFolders()) && (tempRelativeName.contains('/')))
  1396. {
  1397. // the name is a deeper relative path, but we don't recurse this scan folder, so it can't win
  1398. continue;
  1399. }
  1400. // note that we only Update To Correct Case here, because this is one of the few situations where
  1401. // a file with the same relative path may be overridden but different case.
  1402. if (AssetUtilities::UpdateToCorrectCase(scanFolderInfo.ScanPath(), tempRelativeName))
  1403. {
  1404. // we have found a file in an earlier scan folder that would override this file
  1405. return QDir(scanFolderInfo.ScanPath()).absoluteFilePath(tempRelativeName);
  1406. }
  1407. }
  1408. // we found it nowhere.
  1409. return QString();
  1410. }
  1411. // This function is one of the most frequently called ones in the entire application
  1412. // and is invoked several times per file. It can frequently become a bottleneck, so
  1413. // avoid doing expensive operations here, especially memory or IO operations.
  1414. QString PlatformConfiguration::FindFirstMatchingFile(QString relativeName, bool skipIntermediateScanFolder, const ScanFolderInfo** outScanFolderInfo) const
  1415. {
  1416. if (relativeName.isEmpty())
  1417. {
  1418. return QString();
  1419. }
  1420. auto* fileStateInterface = AZ::Interface<AssetProcessor::IFileStateRequests>::Get();
  1421. // Only compute the intermediate assets folder path if we are going to search for and skip it.
  1422. if (skipIntermediateScanFolder)
  1423. {
  1424. if (m_intermediateAssetScanFolderId == -1)
  1425. {
  1426. CacheIntermediateAssetsScanFolderId();
  1427. }
  1428. }
  1429. QString absolutePath; // avoid allocating memory repeatedly here by reusing absolutePath each scan folder.
  1430. absolutePath.reserve(AZ_MAX_PATH_LEN);
  1431. QFileInfo details(relativeName); // note that this does not actually hit the actual storage medium until you query something
  1432. bool isAbsolute = details.isAbsolute(); // note that this looks at the file name string only, it does not hit storage.
  1433. for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
  1434. {
  1435. const AssetProcessor::ScanFolderInfo& scanFolderInfo = m_scanFolders[pathIdx];
  1436. if ((skipIntermediateScanFolder) && (scanFolderInfo.ScanFolderID() == m_intermediateAssetScanFolderId))
  1437. {
  1438. // There's only 1 intermediate assets folder, if we've skipped it, theres no point continuing to check every folder afterwards
  1439. skipIntermediateScanFolder = false;
  1440. continue;
  1441. }
  1442. if ((!scanFolderInfo.RecurseSubFolders()) && (relativeName.contains('/')))
  1443. {
  1444. // the name is a deeper relative path, but we don't recurse this scan folder, so it can't win
  1445. continue;
  1446. }
  1447. if (isAbsolute)
  1448. {
  1449. if (!relativeName.startsWith(scanFolderInfo.ScanPath()))
  1450. {
  1451. continue; // its not this scanfolder.
  1452. }
  1453. absolutePath = relativeName;
  1454. }
  1455. else
  1456. {
  1457. // scanfolders are always absolute paths and already normalized. We can just concatenate.
  1458. // Do so with minimal allocation by using resize/append, instead of operator+
  1459. absolutePath.resize(0);
  1460. absolutePath.append(scanFolderInfo.ScanPath());
  1461. absolutePath.append('/');
  1462. absolutePath.append(relativeName);
  1463. }
  1464. AssetProcessor::FileStateInfo fileStateInfo;
  1465. if (fileStateInterface)
  1466. {
  1467. if (fileStateInterface->GetFileInfo(absolutePath, &fileStateInfo))
  1468. {
  1469. if (outScanFolderInfo)
  1470. {
  1471. *outScanFolderInfo = &scanFolderInfo;
  1472. }
  1473. return AssetUtilities::NormalizeFilePath(fileStateInfo.m_absolutePath);
  1474. }
  1475. }
  1476. }
  1477. return QString();
  1478. }
  1479. QStringList PlatformConfiguration::FindWildcardMatches(
  1480. const QString& sourceFolder,
  1481. QString relativeName,
  1482. bool includeFolders,
  1483. bool recursiveSearch) const
  1484. {
  1485. if (relativeName.isEmpty())
  1486. {
  1487. return QStringList();
  1488. }
  1489. QDir sourceFolderDir(sourceFolder);
  1490. QString posixRelativeName = QDir::fromNativeSeparators(relativeName);
  1491. QStringList returnList;
  1492. QRegExp nameMatch{ posixRelativeName, Qt::CaseInsensitive, QRegExp::Wildcard };
  1493. QDirIterator dirIterator(
  1494. sourceFolderDir.path(), QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot,
  1495. recursiveSearch ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags);
  1496. QStringList files;
  1497. while (dirIterator.hasNext())
  1498. {
  1499. dirIterator.next();
  1500. if (!includeFolders && !dirIterator.fileInfo().isFile())
  1501. {
  1502. continue;
  1503. }
  1504. QString pathMatch{ sourceFolderDir.relativeFilePath(dirIterator.filePath()) };
  1505. if (nameMatch.exactMatch(pathMatch))
  1506. {
  1507. returnList.append(QDir::fromNativeSeparators(dirIterator.filePath()));
  1508. }
  1509. }
  1510. return returnList;
  1511. }
  1512. QStringList PlatformConfiguration::FindWildcardMatches(
  1513. const QString& sourceFolder,
  1514. QString relativeName,
  1515. const AZStd::unordered_set<AZStd::string>& excludedFolders,
  1516. bool includeFolders,
  1517. bool recursiveSearch) const
  1518. {
  1519. if (relativeName.isEmpty())
  1520. {
  1521. return QStringList();
  1522. }
  1523. QDir sourceFolderDir(sourceFolder);
  1524. QString posixRelativeName = QDir::fromNativeSeparators(relativeName);
  1525. QStringList returnList;
  1526. QRegExp nameMatch{ posixRelativeName, Qt::CaseInsensitive, QRegExp::Wildcard };
  1527. AZStd::stack<QString> dirs;
  1528. dirs.push(sourceFolderDir.absolutePath());
  1529. while (!dirs.empty())
  1530. {
  1531. QString absolutePath = dirs.top();
  1532. dirs.pop();
  1533. if (excludedFolders.contains(absolutePath.toUtf8().constData()))
  1534. {
  1535. continue;
  1536. }
  1537. QDirIterator dirIterator(absolutePath, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot);
  1538. while (dirIterator.hasNext())
  1539. {
  1540. dirIterator.next();
  1541. if (!dirIterator.fileInfo().isFile())
  1542. {
  1543. if (recursiveSearch)
  1544. {
  1545. dirs.push(dirIterator.filePath());
  1546. }
  1547. if (!includeFolders)
  1548. {
  1549. continue;
  1550. }
  1551. }
  1552. QString pathMatch{ sourceFolderDir.relativeFilePath(dirIterator.filePath()) };
  1553. if (nameMatch.exactMatch(pathMatch))
  1554. {
  1555. returnList.append(QDir::fromNativeSeparators(dirIterator.filePath()));
  1556. }
  1557. }
  1558. }
  1559. return returnList;
  1560. }
  1561. const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderForFile(const QString& fullFileName) const
  1562. {
  1563. QString normalized = AssetUtilities::NormalizeFilePath(fullFileName);
  1564. // first, check for an EXACT match. If there's an exact match, this must be the one returned!
  1565. // this is to catch the case where the actual path of a scan folder is fed in to this.
  1566. // because exact matches are preferred over less exact, we first check exact matches:
  1567. for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
  1568. {
  1569. QString scanFolderName = m_scanFolders[pathIdx].ScanPath();
  1570. if (scanFolderName.length() == normalized.length())
  1571. {
  1572. if (normalized.compare(scanFolderName, Qt::CaseInsensitive) == 0)
  1573. {
  1574. // if its an exact match, we're basically done
  1575. return &m_scanFolders[pathIdx];
  1576. }
  1577. }
  1578. }
  1579. for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
  1580. {
  1581. QString scanFolderName = m_scanFolders[pathIdx].ScanPath();
  1582. if (normalized.length() > scanFolderName.length())
  1583. {
  1584. if (normalized.startsWith(scanFolderName, Qt::CaseInsensitive))
  1585. {
  1586. QChar examineChar = normalized[scanFolderName.length()]; // it must be a slash or its just a scan folder that starts with the same thing by coincidence.
  1587. if (examineChar != QChar('/'))
  1588. {
  1589. continue;
  1590. }
  1591. QString relPath = normalized.right(normalized.length() - scanFolderName.length() - 1); // also eat the slash, hence -1
  1592. if (!m_scanFolders[pathIdx].RecurseSubFolders())
  1593. {
  1594. // we only allow things that are in the root for nonrecursive folders
  1595. if (relPath.contains('/'))
  1596. {
  1597. continue;
  1598. }
  1599. }
  1600. return &m_scanFolders[pathIdx];
  1601. }
  1602. }
  1603. }
  1604. return nullptr; // not found.
  1605. }
  1606. //! Given a scan folder path, get its complete info
  1607. const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderByPath(const QString& scanFolderPath) const
  1608. {
  1609. return FindScanFolder([&scanFolderPath](const AssetProcessor::ScanFolderInfo& scanFolder)
  1610. {
  1611. return scanFolder.ScanPath() == scanFolderPath;
  1612. });
  1613. }
  1614. int PlatformConfiguration::GetMinJobs() const
  1615. {
  1616. return m_minJobs;
  1617. }
  1618. int PlatformConfiguration::GetMaxJobs() const
  1619. {
  1620. return m_maxJobs;
  1621. }
  1622. void PlatformConfiguration::EnableCommonPlatform()
  1623. {
  1624. EnablePlatform(AssetBuilderSDK::PlatformInfo{ AssetBuilderSDK::CommonPlatformName, AZStd::unordered_set<AZStd::string>{ "common" } });
  1625. }
  1626. void PlatformConfiguration::AddIntermediateScanFolder()
  1627. {
  1628. auto settingsRegistry = AZ::SettingsRegistry::Get();
  1629. AZ::SettingsRegistryInterface::FixedValueString cacheRootFolder;
  1630. settingsRegistry->Get(cacheRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder);
  1631. AZ::IO::Path scanfolderPath = cacheRootFolder.c_str();
  1632. scanfolderPath /= AssetProcessor::IntermediateAssetsFolderName;
  1633. AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
  1634. PopulatePlatformsForScanFolder(platforms);
  1635. scanfolderPath = AssetUtilities::NormalizeDirectoryPath(QString::fromUtf8(scanfolderPath.c_str())).toUtf8().constData();
  1636. // By default the project scanfolder is recursive with an order of 0
  1637. // The intermediate assets folder needs to be higher priority since its a subfolder (otherwise GetScanFolderForFile won't pick the right scanfolder)
  1638. constexpr int order = -1;
  1639. AddScanFolder(ScanFolderInfo{
  1640. scanfolderPath.c_str(),
  1641. AssetProcessor::IntermediateAssetsFolderName,
  1642. AssetProcessor::IntermediateAssetsFolderName,
  1643. false,
  1644. true,
  1645. platforms,
  1646. order
  1647. });
  1648. }
  1649. void PlatformConfiguration::AddGemScanFolders(const AZStd::vector<AzFramework::GemInfo>& gemInfoList)
  1650. {
  1651. // If the gem is project-relative, make adjustments to its priority order based on registry settings:
  1652. // /Amazon/AssetProcessor/Settings/GemScanFolderStartingPriorityOrder
  1653. // /Amazon/AssetProcessor/Settings/ProjectRelativeGemsScanFolderPriority
  1654. // See <o3de-root>/Registry/AssetProcessorPlatformConfig.setreg for more information.
  1655. AZ::s64 gemStartingOrder = 100;
  1656. AZStd::string projectGemPrioritySetting{};
  1657. const AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
  1658. int pathCount = 0;
  1659. const int projectScanOrder = GetProjectScanFolderOrder();
  1660. if (auto const settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
  1661. {
  1662. settingsRegistry->Get(gemStartingOrder,
  1663. AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + GemStartingPriorityOrderKey);
  1664. settingsRegistry->Get(projectGemPrioritySetting,
  1665. AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + ProjectRelativeGemPriorityKey);
  1666. AZStd::to_lower(projectGemPrioritySetting.begin(), projectGemPrioritySetting.end());
  1667. }
  1668. auto GetGemFolderOrder = [&](bool isProjectRelativeGem) -> int
  1669. {
  1670. ++pathCount;
  1671. int currentGemOrder = aznumeric_cast<int>(gemStartingOrder) + pathCount;
  1672. if (isProjectRelativeGem)
  1673. {
  1674. if (projectGemPrioritySetting == "higher")
  1675. {
  1676. currentGemOrder = projectScanOrder - pathCount;
  1677. }
  1678. else if (projectGemPrioritySetting == "lower")
  1679. {
  1680. currentGemOrder = projectScanOrder + pathCount;
  1681. }
  1682. }
  1683. return currentGemOrder;
  1684. };
  1685. int gemOrder = aznumeric_cast<int>(gemStartingOrder);
  1686. AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
  1687. PopulatePlatformsForScanFolder(platforms);
  1688. for (const AzFramework::GemInfo& gemElement : gemInfoList)
  1689. {
  1690. for (size_t sourcePathIndex{}; sourcePathIndex < gemElement.m_absoluteSourcePaths.size(); ++sourcePathIndex)
  1691. {
  1692. const AZ::IO::Path& absoluteSourcePath = gemElement.m_absoluteSourcePaths[sourcePathIndex];
  1693. QString gemAbsolutePath = QString::fromUtf8(absoluteSourcePath.c_str(), aznumeric_cast<int>(absoluteSourcePath.Native().size())); // this is an absolute path!
  1694. const bool isProjectGem = absoluteSourcePath.IsRelativeTo(projectPath);
  1695. // Append the index of the source path array element to make a unique portable key is created for each path of a gem
  1696. AZ::Uuid gemNameUuid = AZ::Uuid::CreateName((gemElement.m_gemName + AZStd::to_string(sourcePathIndex)).c_str());
  1697. QString gemNameAsUuid(gemNameUuid.ToFixedString().c_str());
  1698. QDir gemDir(gemAbsolutePath);
  1699. // The gems /Assets/ folders are always added to the watch list, we want the following params
  1700. // Watched folder: (absolute path to the gem /Assets/ folder) MUST BE CORRECT CASE
  1701. // Display name: "Gems/GemName/Assets" // uppercase, for human eyes
  1702. // portable Key: "gemassets-(UUID Of Gem)"
  1703. // Is Root: False
  1704. // Recursive: True
  1705. QString gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemAssetFolder());
  1706. // note that we normalize this gem path with slashes so that there's nothing special about it compared to other scan folders
  1707. gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder);
  1708. QString assetBrowserDisplayName = AzFramework::GemInfo::GetGemAssetFolder(); // Gems always use assets folder as their displayname...
  1709. QString portableKey = QString("gemassets-%1").arg(gemNameAsUuid);
  1710. bool isRoot = false;
  1711. bool isRecursive = true;
  1712. gemOrder = GetGemFolderOrder(isProjectGem);
  1713. AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM assets folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data());
  1714. AddScanFolder(ScanFolderInfo(
  1715. gemFolder,
  1716. assetBrowserDisplayName,
  1717. portableKey,
  1718. isRoot,
  1719. isRecursive,
  1720. platforms,
  1721. gemOrder,
  1722. /*scanFolderId*/ 0,
  1723. /*canSaveNewAssets*/ true)); // Users can create assets like slices in Gem asset folders.
  1724. // Now add another scan folder on Gem/GemName/Registry...
  1725. gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemRegistryFolder());
  1726. gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder);
  1727. assetBrowserDisplayName = AzFramework::GemInfo::GetGemRegistryFolder();
  1728. portableKey = QString("gemregistry-%1").arg(gemNameAsUuid);
  1729. gemOrder = GetGemFolderOrder(isProjectGem);
  1730. AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM registry folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data());
  1731. AddScanFolder(ScanFolderInfo(
  1732. gemFolder,
  1733. assetBrowserDisplayName,
  1734. portableKey,
  1735. isRoot,
  1736. isRecursive,
  1737. platforms,
  1738. gemOrder));
  1739. }
  1740. }
  1741. }
  1742. const RecognizerContainer& PlatformConfiguration::GetAssetRecognizerContainer() const
  1743. {
  1744. return m_assetRecognizers;
  1745. }
  1746. const RecognizerContainer& PlatformConfiguration::GetAssetCacheRecognizerContainer() const
  1747. {
  1748. return m_assetCacheServerRecognizers;
  1749. }
  1750. const ExcludeRecognizerContainer& PlatformConfiguration::GetExcludeAssetRecognizerContainer() const
  1751. {
  1752. return m_excludeAssetRecognizers;
  1753. }
  1754. bool PlatformConfiguration::AddAssetCacheRecognizerContainer(const RecognizerContainer& recognizerContainer)
  1755. {
  1756. bool addedEntries = false;
  1757. for (const auto& recognizer : recognizerContainer)
  1758. {
  1759. auto entryIter = m_assetCacheServerRecognizers.find(recognizer.first);
  1760. if (entryIter != m_assetCacheServerRecognizers.end())
  1761. {
  1762. m_assetCacheServerRecognizers.insert(recognizer);
  1763. addedEntries = true;
  1764. }
  1765. }
  1766. return addedEntries;
  1767. }
  1768. // AssetProcessor
  1769. void AssetProcessor::PlatformConfiguration::AddExcludeRecognizer(const ExcludeAssetRecognizer& recogniser)
  1770. {
  1771. m_excludeAssetRecognizers.insert(recogniser.m_name, recogniser);
  1772. }
  1773. void AssetProcessor::PlatformConfiguration::RemoveExcludeRecognizer(QString name)
  1774. {
  1775. auto found = m_excludeAssetRecognizers.find(name);
  1776. if (found != m_excludeAssetRecognizers.end())
  1777. {
  1778. m_excludeAssetRecognizers.erase(found);
  1779. }
  1780. }
  1781. bool AssetProcessor::PlatformConfiguration::IsFileExcluded(QString fileName) const
  1782. {
  1783. QString relPath, scanFolderName;
  1784. if (ConvertToRelativePath(fileName, relPath, scanFolderName))
  1785. {
  1786. return IsFileExcludedRelPath(relPath);
  1787. }
  1788. return false;
  1789. }
  1790. bool AssetProcessor::PlatformConfiguration::IsFileExcludedRelPath(QString relPath) const
  1791. {
  1792. AZ::IO::FixedMaxPathString encoded = relPath.toUtf8().constData();
  1793. for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
  1794. {
  1795. if (excludeRecognizer.m_patternMatcher.MatchesPath(encoded.c_str()))
  1796. {
  1797. return true;
  1798. }
  1799. }
  1800. return false;
  1801. }
  1802. bool AssetProcessor::PlatformConfiguration::IsValid() const
  1803. {
  1804. if (m_fatalError.empty())
  1805. {
  1806. if (m_enabledPlatforms.empty())
  1807. {
  1808. m_fatalError = "The configuration is invalid - no platforms appear to be enabled. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct.";
  1809. }
  1810. else if (m_assetRecognizers.empty())
  1811. {
  1812. m_fatalError = "The configuration is invalid - no matching asset recognizers appear valid. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct.";
  1813. }
  1814. else if (m_scanFolders.empty())
  1815. {
  1816. m_fatalError = "The configuration is invalid - no scan folders defined. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct.";
  1817. }
  1818. }
  1819. if (!m_fatalError.empty())
  1820. {
  1821. AZ_Error(AssetProcessor::ConsoleChannel, false, "Error: %s", m_fatalError.c_str());
  1822. return false;
  1823. }
  1824. return true;
  1825. }
  1826. const AZStd::string& AssetProcessor::PlatformConfiguration::GetError() const
  1827. {
  1828. return m_fatalError;
  1829. }
  1830. } // namespace assetProcessor