123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "native/utilities/PlatformConfiguration.h"
- #include "native/AssetManager/FileStateCache.h"
- #include <QDirIterator>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
- #include <AzCore/Settings/SettingsRegistryVisitorUtils.h>
- #include <AzCore/Serialization/Json/JsonUtils.h>
- #include <AzCore/Utils/Utils.h>
- #include <AzFramework/API/ApplicationAPI.h>
- #include <AzFramework/Gem/GemInfo.h>
- #include <AzToolsFramework/Asset/AssetUtils.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzToolsFramework/Metadata/MetadataManager.h>
- namespace AssetProcessor
- {
- struct AssetImporterPathsVisitor
- : AZ::SettingsRegistryInterface::Visitor
- {
- AssetImporterPathsVisitor(AZ::SettingsRegistryInterface* settingsRegistry, AZStd::vector<AZStd::string>& supportedExtension)
- : m_settingsRegistry(settingsRegistry)
- , m_supportedFileExtensions(supportedExtension)
- {
- }
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- void Visit(const AZ::SettingsRegistryInterface::VisitArgs&, AZStd::string_view value) override
- {
- if (auto found = value.find('.'); found != AZStd::string::npos)
- {
- m_supportedFileExtensions.emplace_back(value.substr(found + 1));
- }
- else
- {
- m_supportedFileExtensions.emplace_back(value);
- }
- }
- AZ::SettingsRegistryInterface* m_settingsRegistry;
- AZStd::vector<AZStd::string> m_supportedFileExtensions;
- };
- //! Visitor for reading the "/Amazon/AssetProcessor/Settings/ScanFolder *" entries from the Settings Registry
- //! Expects the key to path to the visitor to be "/Amazon/AssetProcessor/Settings"
- struct ScanFolderVisitor
- : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
- {
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
- struct ScanFolderInfo
- {
- AZStd::string m_scanFolderIdentifier;
- AZStd::string m_scanFolderDisplayName;
- AZ::IO::Path m_watchPath{ AZ::IO::PosixPathSeparator };
- AZStd::vector<AZStd::string> m_includeIdentifiers;
- AZStd::vector<AZStd::string> m_excludeIdentifiers;
- int m_scanOrder{};
- bool m_isRecursive{};
- };
- AZStd::vector<ScanFolderInfo> m_scanFolderInfos;
- };
- struct ExcludeVisitor
- : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
- {
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
- AZStd::vector<ExcludeAssetRecognizer> m_excludeAssetRecognizers;
- };
- struct SimpleJobVisitor
- : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
- {
- SimpleJobVisitor(const AZStd::vector<AssetBuilderSDK::PlatformInfo>& enabledPlatforms)
- : m_enabledPlatforms(enabledPlatforms)
- {
- }
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
- struct SimpleJobAssetRecognizer
- {
- AssetRecognizer m_recognizer;
- AZStd::string m_defaultParams;
- bool m_ignore{};
- };
- AZStd::vector<SimpleJobAssetRecognizer> m_assetRecognizers;
- private:
- void ApplyParamsOverrides(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs,
- SimpleJobAssetRecognizer& assetRecognizer);
- const AZStd::vector<AssetBuilderSDK::PlatformInfo>& m_enabledPlatforms;
- };
- //! This vistor reads in the Asset Cache Server configuration elements from the settings registry
- struct ACSVisitor
- : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
- {
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override;
- AZStd::vector<AssetRecognizer> m_assetRecognizers;
- };
- struct PlatformsInfoVisitor
- : AZ::SettingsRegistryVisitorUtils::ObjectVisitor
- {
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- AZ::SettingsRegistryInterface::VisitResponse Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs) override
- {
- // Visit any each "Platform *" field that is a direct child of the object at the AssetProcessorSettingsKey
- constexpr AZStd::string_view PlatformInfoPrefix = "Platform ";
- if (!visitArgs.m_fieldName.starts_with(PlatformInfoPrefix))
- {
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- // Retrieve the platform name from the rest of valueName portion of the key "Platform (.*)"
- AZStd::string platformIdentifier = visitArgs.m_fieldName.substr(PlatformInfoPrefix.size());
- // Lowercase the platformIdentifier
- AZStd::to_lower(platformIdentifier.begin(), platformIdentifier.end());
- // Look up the "tags" field that is child of the "Platform (.*)" field
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- const auto tagKeyPath = FixedValueString(visitArgs.m_jsonKeyPath) + "/tags";
- if (AZStd::string tagValue; visitArgs.m_registry.Get(tagValue, tagKeyPath))
- {
- AZStd::unordered_set<AZStd::string> platformTags;
- auto JoinTags = [&platformTags](AZStd::string_view token)
- {
- AZStd::string cleanedTag{ token };
- AZStd::to_lower(cleanedTag.begin(), cleanedTag.end());
- platformTags.insert(AZStd::move(cleanedTag));
- };
- AZ::StringFunc::TokenizeVisitor(tagValue, JoinTags, ',');
- m_platformInfos.emplace_back(platformIdentifier, platformTags);
- }
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZStd::vector<AssetBuilderSDK::PlatformInfo> m_platformInfos;
- };
- struct MetaDataTypesVisitor
- : AZ::SettingsRegistryInterface::Visitor
- {
- using AZ::SettingsRegistryInterface::Visitor::Visit;
- void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, AZStd::string_view value) override
- {
- m_metaDataTypes.push_back({ AZ::IO::PathView(visitArgs.m_fieldName, AZ::IO::PosixPathSeparator).LexicallyNormal().String(), value });
- }
- struct MetaDataType
- {
- AZStd::string m_fileType;
- AZStd::string m_extensionType;
- };
- AZStd::vector<MetaDataType> m_metaDataTypes;
- };
- AZ::SettingsRegistryInterface::VisitResponse ScanFolderVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
- {
- constexpr AZStd::string_view ScanFolderInfoPrefix = "ScanFolder ";
- // Check if a "ScanFolder *" element is being traversed
- if (!visitArgs.m_fieldName.starts_with(ScanFolderInfoPrefix))
- {
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZStd::string_view currentScanFolderIdentifier = visitArgs.m_fieldName.substr(ScanFolderInfoPrefix.size());
- ScanFolderInfo& scanFolderInfo = m_scanFolderInfos.emplace_back();
- scanFolderInfo.m_scanFolderIdentifier = currentScanFolderIdentifier;
- scanFolderInfo.m_scanFolderDisplayName = currentScanFolderIdentifier;
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- if (AZ::s64 value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/recursive"))
- {
- scanFolderInfo.m_isRecursive = value != 0;
- }
- if (AZ::s64 value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/order"))
- {
- scanFolderInfo.m_scanOrder = static_cast<int>(value);
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/watch"))
- {
- scanFolderInfo.m_watchPath = value;
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/display")
- && !value.empty())
- {
- scanFolderInfo.m_scanFolderDisplayName = value;
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/include"))
- {
- auto JoinTags = [&scanFolderInfo](AZStd::string_view token)
- {
- scanFolderInfo.m_includeIdentifiers.push_back(token);
- };
- AZ::StringFunc::TokenizeVisitor(value, JoinTags, ',');
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/exclude"))
- {
- auto JoinTags = [&scanFolderInfo](AZStd::string_view token)
- {
- scanFolderInfo.m_excludeIdentifiers.push_back(token);
- };
- AZ::StringFunc::TokenizeVisitor(value, JoinTags, ',');
- }
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZ::SettingsRegistryInterface::VisitResponse ExcludeVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
- {
- constexpr AZStd::string_view ExcludeNamePrefix = "Exclude ";
- if (!visitArgs.m_fieldName.starts_with(ExcludeNamePrefix))
- {
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZStd::string_view excludeName = visitArgs.m_fieldName.substr(ExcludeNamePrefix.size());
- ExcludeAssetRecognizer& excludeAssetRecognizer = m_excludeAssetRecognizers.emplace_back();
- excludeAssetRecognizer.m_name = QString::fromUtf8(excludeName.data(), aznumeric_cast<int>(excludeName.size()));
- // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values
- // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the
- // backslash character used to escape other characters, therefore causing a "double escape"
- // situation
- auto UnescapePattern = [](AZStd::string_view pattern)
- {
- constexpr AZStd::string_view backslashEscape = R"(\\)";
- AZStd::string unescapedResult;
- while (!pattern.empty())
- {
- size_t pos = pattern.find(backslashEscape);
- if (pos != AZStd::string_view::npos)
- {
- unescapedResult += pattern.substr(0, pos);
- unescapedResult += '\\';
- // Move the pattern string after the double backslash characters
- pattern = pattern.substr(pos + backslashEscape.size());
- }
- else
- {
- unescapedResult += pattern;
- pattern = {};
- }
- }
- return unescapedResult;
- };
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/pattern"))
- {
- if (!value.empty())
- {
- const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex;
- excludeAssetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
- }
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/glob"))
- {
- if (!excludeAssetRecognizer.m_patternMatcher.IsValid())
- {
- const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard;
- excludeAssetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
- }
- }
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZ::SettingsRegistryInterface::VisitResponse SimpleJobVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
- {
- constexpr AZStd::string_view RCNamePrefix = "RC "; // RC = Resource Compiler
- constexpr AZStd::string_view SJNamePrefix = "SJ "; // SJ = Simple Job
- if (!visitArgs.m_fieldName.starts_with(RCNamePrefix) && !visitArgs.m_fieldName.starts_with(SJNamePrefix))
- {
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZStd::string_view sjNameView = visitArgs.m_fieldName.starts_with(SJNamePrefix)
- ? visitArgs.m_fieldName.substr(SJNamePrefix.size())
- : visitArgs.m_fieldName.substr(RCNamePrefix.size());
- auto& assetRecognizer = m_assetRecognizers.emplace_back();
- assetRecognizer.m_recognizer.m_name = sjNameView;
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/ignore"))
- {
- assetRecognizer.m_ignore = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/lockSource"))
- {
- assetRecognizer.m_recognizer.m_testLockSource = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/critical"))
- {
- assetRecognizer.m_recognizer.m_isCritical = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/checkServer"))
- {
- assetRecognizer.m_recognizer.m_checkServer = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/supportsCreateJobs"))
- {
- assetRecognizer.m_recognizer.m_supportsCreateJobs = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/outputProductDependencies"))
- {
- assetRecognizer.m_recognizer.m_outputProductDependencies = value;
- }
- if (AZ::s64 value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/priority"))
- {
- assetRecognizer.m_recognizer.m_priority = static_cast<int>(value);
- }
- // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values
- // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the
- // backslash character used to escape other characters, therefore causing a "double escape"
- // situation
- auto UnescapePattern = [](AZStd::string_view pattern)
- {
- constexpr AZStd::string_view backslashEscape = R"(\\)";
- AZStd::string unescapedResult;
- while (!pattern.empty())
- {
- size_t pos = pattern.find(backslashEscape);
- if (pos != AZStd::string_view::npos)
- {
- unescapedResult += pattern.substr(0, pos);
- unescapedResult += '\\';
- // Move the pattern string after the double backslash characters
- pattern = pattern.substr(pos + backslashEscape.size());
- }
- else
- {
- unescapedResult += pattern;
- pattern = {};
- }
- }
- return unescapedResult;
- };
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/pattern"))
- {
- if (!value.empty())
- {
- const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex;
- assetRecognizer.m_recognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
- }
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/glob"))
- {
- // Add the glob pattern if it the matter matcher doesn't already contain a valid regex pattern
- if (!assetRecognizer.m_recognizer.m_patternMatcher.IsValid())
- {
- const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard;
- assetRecognizer.m_recognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
- }
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/version"))
- {
- assetRecognizer.m_recognizer.m_version = value;
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/productAssetType"))
- {
- if (!value.empty())
- {
- AZ::Uuid productAssetType{ value.data(), value.size() };
- if (!productAssetType.IsNull())
- {
- assetRecognizer.m_recognizer.m_productAssetType = productAssetType;
- }
- }
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/params"))
- {
- assetRecognizer.m_defaultParams = value;
- }
- ApplyParamsOverrides(visitArgs, assetRecognizer);
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- void SimpleJobVisitor::ApplyParamsOverrides(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, SimpleJobAssetRecognizer& assetRecognizer)
- {
- /* so in this particular case we want to end up with an AssetPlatformSpec struct that
- has only got the platforms that 'matter' in it
- so for example, if you have the following enabled platforms
- [Platform PC]
- tags=blah
- [Platform Mac]
- tags=whatever
- [Platform android]
- tags=mobile
- and you encounter a recognizer like:
- [SJ blahblah]
- pattern=whatever
- params=abc
- mac=skip
- mobile=hijklmnop
- android=1234
- then the outcome should be a recognizer which has:
- pattern=whatever
- pc=abc -- no tags or platforms matched but we do have a default params
- android=1234 -- because even though it matched the mobile tag, platforms explicitly specified take precedence
- (and no mac) -- because it matched a skip rule
- So the strategy will be to read the default params
- - if present, we pre-populate all the platforms with it
- - If missing, we pre-populate nothing
- Then loop over the other params and
- if the key matches a tag, if it does we add/change that platform
- (if its 'skip' we remove it)
- if the key matches a platform, if it does we add/change that platform
- (if its 'skip' we remove it)
- */
- for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
- {
- // Exclude the common platform from the internal copy builder, we don't support it as an output for assets currently
- if(platform.m_identifier == AssetBuilderSDK::CommonPlatformName)
- {
- continue;
- }
- AZStd::string_view currentParams = assetRecognizer.m_defaultParams;
- // The "/Amazon/AssetProcessor/Settings/SJ */<platform>" entry will be queried
- AZ::IO::Path overrideParamsKey = AZ::IO::Path(AZ::IO::PosixPathSeparator);
- overrideParamsKey /= visitArgs.m_jsonKeyPath;
- overrideParamsKey /= platform.m_identifier;
- AZ::SettingsRegistryInterface::FixedValueString overrideParamsValue;
- // Check if the enabled platform identifier matches a key within the "SJ *" object
- if (visitArgs.m_registry.Get(overrideParamsValue, overrideParamsKey.Native()))
- {
- currentParams = overrideParamsValue;
- }
- else
- {
- // otherwise check for tags associated with the platform
- for (const AZStd::string& tag : platform.m_tags)
- {
- overrideParamsKey.ReplaceFilename(AZ::IO::PathView(tag));
- if (visitArgs.m_registry.Get(overrideParamsValue, overrideParamsKey.Native()))
- {
- // if we get here it means we found a tag that applies to this platform
- currentParams = overrideParamsValue;
- break;
- }
- }
- }
- // now generate a platform spec as long as we're not skipping
- if (!AZ::StringFunc::Equal(currentParams, "skip"))
- {
- assetRecognizer.m_recognizer.m_platformSpecs[platform.m_identifier] = AssetInternalSpec::Copy;
- }
- }
- }
- AZ::SettingsRegistryInterface::VisitResponse ACSVisitor::Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs)
- {
- constexpr AZStd::string_view ACSNamePrefix = "ACS ";
- if (!visitArgs.m_fieldName.starts_with(ACSNamePrefix))
- {
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- AZStd::string name = visitArgs.m_fieldName.substr(ACSNamePrefix.size());
- AssetRecognizer& assetRecognizer = m_assetRecognizers.emplace_back();
- assetRecognizer.m_name = name;
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/lockSource"))
- {
- assetRecognizer.m_testLockSource = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/critical"))
- {
- assetRecognizer.m_isCritical = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/checkServer"))
- {
- assetRecognizer.m_checkServer = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/supportsCreateJobs"))
- {
- assetRecognizer.m_supportsCreateJobs = value;
- }
- if (bool value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/outputProductDependencies"))
- {
- assetRecognizer.m_outputProductDependencies = value;
- }
- if (AZ::s64 value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/priority"))
- {
- assetRecognizer.m_priority = aznumeric_cast<int>(value);
- }
- // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values
- // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the
- // backslash character used to escape other characters, therefore causing a "double escape"
- // situation
- auto UnescapePattern = [](AZStd::string_view pattern)
- {
- constexpr AZStd::string_view backslashEscape = R"(\\)";
- AZStd::string unescapedResult;
- while (!pattern.empty())
- {
- size_t pos = pattern.find(backslashEscape);
- if (pos != AZStd::string_view::npos)
- {
- unescapedResult += pattern.substr(0, pos);
- unescapedResult += '\\';
- // Move the pattern string after the double backslash characters
- pattern = pattern.substr(pos + backslashEscape.size());
- }
- else
- {
- unescapedResult += pattern;
- pattern = {};
- }
- }
- return unescapedResult;
- };
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/pattern"))
- {
- if (!value.empty())
- {
- const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex;
- assetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
- }
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/glob"))
- {
- // Add the glob pattern if it the matter matcher doesn't already contain a valid regex pattern
- if (!assetRecognizer.m_patternMatcher.IsValid())
- {
- const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard;
- assetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType);
- }
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/version"))
- {
- assetRecognizer.m_version = value;
- }
- if (AZStd::string value;
- visitArgs.m_registry.Get(value, FixedValueString(visitArgs.m_jsonKeyPath) + "/productAssetType"))
- {
- if (!value.empty())
- {
- AZ::Uuid productAssetType{ value.data(), value.size() };
- if (!productAssetType.IsNull())
- {
- assetRecognizer.m_productAssetType = productAssetType;
- }
- }
- }
- return AZ::SettingsRegistryInterface::VisitResponse::Skip;
- }
- const char AssetConfigPlatformDir[] = "AssetProcessorConfig/";
- const char AssetProcessorPlatformConfigFileName[] = "AssetProcessorPlatformConfig.ini";
- constexpr const char* ProjectScanFolderKey = "Project/Assets";
- constexpr const char* GemStartingPriorityOrderKey = "/GemScanFolderStartingPriorityOrder";
- constexpr const char* ProjectRelativeGemPriorityKey = "/ProjectRelativeGemsScanFolderPriority";
- PlatformConfiguration::PlatformConfiguration(QObject* pParent)
- : QObject(pParent)
- , m_minJobs(1)
- , m_maxJobs(8)
- {
- }
- bool PlatformConfiguration::AddPlatformConfigFilePaths(AZStd::vector<AZ::IO::Path>& configFilePaths)
- {
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not available, the "
- "Engine Root folder cannot be queried")
- return false;
- }
- AZ::IO::FixedMaxPath engineRoot;
- if (!settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to find Engine Root in Settings Registry");
- return false;
- }
- return AzToolsFramework::AssetUtils::AddPlatformConfigFilePaths(engineRoot.Native(), configFilePaths);
- }
- bool PlatformConfiguration::InitializeFromConfigFiles(const QString& absoluteSystemRoot, const QString& absoluteAssetRoot,
- const QString& projectPath, bool addPlatformConfigs, bool addGemsConfigs)
- {
- // this function may look strange, but the point here is that each section in the config file
- // can depend on entries from the prior section, but also, each section can be overridden by
- // the other config files.
- // so we have to read each section one at a time, in order of config file priority (most important one last)
- static const char ScanFolderOption[] = "scanfolders";
- const AzFramework::CommandLine* commandLine = nullptr;
- AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
- const bool scanFolderOverride = commandLine ? commandLine->HasSwitch(ScanFolderOption) : false;
- static const char NoConfigScanFolderOption[] = "noConfigScanFolders";
- const bool noConfigScanFolders = commandLine ? commandLine->HasSwitch(NoConfigScanFolderOption) : false;
- static const char NoGemScanFolderOption[] = "noGemScanFolders";
- const bool noGemScanFolders = commandLine ? commandLine->HasSwitch(NoGemScanFolderOption) : false;
- static const char ScanFolderPatternOption[] = "scanfolderpattern";
- QStringList scanFolderPatterns;
- if (commandLine && commandLine->HasSwitch(ScanFolderPatternOption))
- {
- for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(ScanFolderPatternOption); idx++)
- {
- scanFolderPatterns.push_back(commandLine->GetSwitchValue(ScanFolderPatternOption, idx).c_str());
- }
- }
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "There is no Global Settings Registry set."
- " Unable to merge AssetProcessor config files(*.ini) and Asset processor settings registry files(*.setreg)");
- return false;
- }
- AZStd::vector<AZ::IO::Path> configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(absoluteSystemRoot.toUtf8().constData(),
- projectPath.toUtf8().constData(),
- addPlatformConfigs, addGemsConfigs && !noGemScanFolders, settingsRegistry);
- // First Merge all Engine, Gem and Project specific AssetProcessor*Config.setreg/.inifiles
- for (const AZ::IO::Path& configFile : configFiles)
- {
- if (AZ::IO::SystemFile::Exists(configFile.c_str()))
- {
- MergeConfigFileToSettingsRegistry(*settingsRegistry, configFile);
- }
- }
- // Merge the Command Line to the Settings Registry after merging the AssetProcessor*Config.setreg/ini files
- // to allow the command line to override the settings
- #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
- if (commandLine)
- {
- AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, *commandLine, true);
- }
- #endif
- // first, read the platform informations.
- ReadPlatformInfosFromSettingsRegistry();
- // now read which platforms are currently enabled - this may alter the platform infos array and eradicate
- // the ones that are not suitable and currently enabled, leaving only the ones enabled either on command line
- // or config files.
- // the command line can always takes precedence - but can only turn on and off platforms, it cannot describe them.
- PopulateEnabledPlatforms();
- FinalizeEnabledPlatforms();
- if(!m_enabledPlatforms.empty())
- {
- // Add the common platform if we have some other platforms enabled. For now, this is only intended for intermediate assets
- // 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
- EnableCommonPlatform();
- }
- if (scanFolderOverride)
- {
- AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
- PopulatePlatformsForScanFolder(platforms);
- for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(ScanFolderOption); idx++)
- {
- QString scanFolder{ commandLine->GetSwitchValue(ScanFolderOption, idx).c_str() };
- scanFolder = AssetUtilities::NormalizeFilePath(scanFolder);
- AddScanFolder(ScanFolderInfo(
- scanFolder,
- AZStd::string::format("ScanFolderParam %zu", idx).c_str(),
- AZStd::string::format("SF%zu", idx).c_str(),
- false,
- true,
- platforms,
- aznumeric_caster(idx),
- /*scanFolderId*/ 0,
- true));
- }
- }
- // Then read recognizers (which depend on platforms)
- if (!ReadRecognizersFromSettingsRegistry(absoluteAssetRoot, noConfigScanFolders, scanFolderPatterns))
- {
- if (m_fatalError.empty())
- {
- m_fatalError = "Unable to read recognizers specified in the configuration files during load. Please check the Asset Processor platform ini files for errors.";
- }
- return IsValid();
- }
- if(!m_scanFolders.empty())
- {
- // Enable the intermediate scanfolder if we have some other scanfolders. Since this is hardcoded we don't want to hide an error state
- // where no other scanfolders are enabled besides this one. It wouldn't make sense for the intermediate scanfolder to be the only enabled scanfolder
- AddIntermediateScanFolder();
- }
- if (!noGemScanFolders && addGemsConfigs)
- {
- if (settingsRegistry == nullptr || !AzFramework::GetGemsInfo(m_gemInfoList, *settingsRegistry))
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to Get Gems Info for the project (%s).", projectPath.toUtf8().constData());
- return false;
- }
- // now add all the scan folders of gems.
- AddGemScanFolders(m_gemInfoList);
- }
- // Then read metadata (which depends on scan folders)
- ReadMetaDataFromSettingsRegistry();
- // at this point there should be at least some watch folders besides gems.
- if (m_scanFolders.empty())
- {
- 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.";
- return IsValid();
- }
- return IsValid();
- }
- void PlatformConfiguration::PopulateEnabledPlatforms()
- {
- // if there are no platform informations inside the ini file, there's no point in proceeding
- // since we are unaware of the existence of the platform at all
- if (m_enabledPlatforms.empty())
- {
- AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no \"%s/Platform xxxxxx\" entries present in the settings registry. We cannot proceed.",
- AssetProcessorSettingsKey);
- return;
- }
- // the command line can always takes precedence - but can only turn on and off platforms, it cannot describe them.
- QStringList commandLinePlatforms = AssetUtilities::ReadPlatformsFromCommandLine();
- if (!commandLinePlatforms.isEmpty())
- {
- // command line overrides everything.
- m_tempEnabledPlatforms.clear();
- for (const QString& platformFromCommandLine : commandLinePlatforms)
- {
- QString platform = platformFromCommandLine.toLower().trimmed();
- if (!platform.isEmpty())
- {
- AZStd::string platformOverride{ platform.toUtf8().data() };
- if (auto foundIt = AZStd::find(m_tempEnabledPlatforms.begin(), m_tempEnabledPlatforms.end(), platformOverride);
- foundIt == m_tempEnabledPlatforms.end())
- {
- m_tempEnabledPlatforms.push_back(AZStd::move(platformOverride));
- }
- }
- }
- return; // command line wins!
- }
- // command line isn't active, read from settings registry instead.
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platforms")"
- " settings paths", AssetProcessorSettingsKey);
- return;
- }
- AZStd::vector<AZStd::string> enabledPlatforms;
- AzToolsFramework::AssetUtils::ReadEnabledPlatformsFromSettingsRegistry(*settingsRegistry, enabledPlatforms);
- m_tempEnabledPlatforms.insert(m_tempEnabledPlatforms.end(), AZStd::make_move_iterator(enabledPlatforms.begin()),
- AZStd::make_move_iterator(enabledPlatforms.end()));
- }
- void PlatformConfiguration::FinalizeEnabledPlatforms()
- {
- #if defined(AZ_ENABLE_TRACING)
- // verify command line platforms are valid:
- for (const auto& enabledPlatformFromConfigs : m_tempEnabledPlatforms)
- {
- bool found = false;
- for (const AssetBuilderSDK::PlatformInfo& platformInfo : m_enabledPlatforms)
- {
- if (platformInfo.m_identifier == enabledPlatformFromConfigs)
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- m_fatalError = AZStd::string::format(R"(The list of enabled platforms in the settings registry does not contain platform "%s")"
- " entries - check command line and settings registry files for errors!", enabledPlatformFromConfigs.c_str());
- return;
- }
- }
- #endif // defined(AZ_ENABLE_TRACING)
- // over here, we want to eliminate any platforms in the m_enabledPlatforms array that are not in the m_tempEnabledPlatforms
- for (int enabledPlatformIdx = static_cast<int>(m_enabledPlatforms.size() - 1); enabledPlatformIdx >= 0; --enabledPlatformIdx)
- {
- const AssetBuilderSDK::PlatformInfo& platformInfo = m_enabledPlatforms[enabledPlatformIdx];
- if (auto foundIt = AZStd::find(m_tempEnabledPlatforms.begin(), m_tempEnabledPlatforms.end(), platformInfo.m_identifier);
- foundIt == m_tempEnabledPlatforms.end())
- {
- m_enabledPlatforms.erase(m_enabledPlatforms.cbegin() + enabledPlatformIdx);
- }
- }
- if (m_enabledPlatforms.empty())
- {
- AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no \"%s/Platform xxxxxx\" entry present in the settings registry. We cannot proceed.",
- AssetProcessorSettingsKey);
- return;
- }
- m_tempEnabledPlatforms.clear();
- }
- void PlatformConfiguration::ReadPlatformInfosFromSettingsRegistry()
- {
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platform *")"
- " settings paths", AssetProcessorSettingsKey);
- return;
- }
- PlatformsInfoVisitor visitor;
- settingsRegistry->Visit(visitor, AssetProcessorSettingsKey);
- for (const AssetBuilderSDK::PlatformInfo& platformInfo : visitor.m_platformInfos)
- {
- EnablePlatform(platformInfo, true);
- }
- }
- void PlatformConfiguration::ReadEnabledPlatformsFromSettingsRegistry()
- {
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platforms")"
- " settings paths", AssetProcessorSettingsKey);
- return;
- }
- AzToolsFramework::AssetUtils::ReadEnabledPlatformsFromSettingsRegistry(*settingsRegistry, m_tempEnabledPlatforms);
- }
- void PlatformConfiguration::PopulatePlatformsForScanFolder(AZStd::vector<AssetBuilderSDK::PlatformInfo>& platformsList, QStringList includeTagsList, QStringList excludeTagsList)
- {
- if (includeTagsList.isEmpty())
- {
- // Add all enabled platforms
- for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
- {
- if(platform.m_identifier == AssetBuilderSDK::CommonPlatformName)
- {
- // The common platform is not included in any scanfolder to avoid builders by-default producing jobs for it
- continue;
- }
- if (AZStd::find(platformsList.begin(), platformsList.end(), platform) == platformsList.end())
- {
- platformsList.push_back(platform);
- }
- }
- }
- else
- {
- for (QString identifier : includeTagsList)
- {
- for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
- {
- if(platform.m_identifier == AssetBuilderSDK::CommonPlatformName)
- {
- // The common platform is not included in any scanfolder to avoid builders by-default producing jobs for it
- continue;
- }
- bool addPlatform = (QString::compare(identifier, platform.m_identifier.c_str(), Qt::CaseInsensitive) == 0) ||
- platform.m_tags.find(identifier.toLower().toUtf8().data()) != platform.m_tags.end();
- if (addPlatform)
- {
- if (AZStd::find(platformsList.begin(), platformsList.end(), platform) == platformsList.end())
- {
- platformsList.push_back(platform);
- }
- }
- }
- }
- }
- for (QString identifier : excludeTagsList)
- {
- for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
- {
- bool removePlatform = (QString::compare(identifier, platform.m_identifier.c_str(), Qt::CaseInsensitive) == 0) ||
- platform.m_tags.find(identifier.toLower().toUtf8().data()) != platform.m_tags.end();
- if (removePlatform)
- {
- platformsList.erase(AZStd::remove(platformsList.begin(), platformsList.end(), platform), platformsList.end());
- }
- }
- }
- }
- void PlatformConfiguration::CacheIntermediateAssetsScanFolderId() const
- {
- for (const auto& scanfolder : m_scanFolders)
- {
- if (scanfolder.GetPortableKey() == IntermediateAssetsFolderName)
- {
- m_intermediateAssetScanFolderId = scanfolder.ScanFolderID();
- return;
- }
- }
- AZ_Error(
- "PlatformConfiguration", false,
- "CacheIntermediateAssetsScanFolderId: Failed to find Intermediate Assets folder in scanfolder list");
- }
- AZStd::optional<AZ::s64> PlatformConfiguration::GetIntermediateAssetsScanFolderId() const
- {
- if (m_intermediateAssetScanFolderId >= 0)
- {
- return m_intermediateAssetScanFolderId;
- }
- return AZStd::nullopt;
- }
- // used to save our the AssetCacheServer settings to a remote location
- struct AssetCacheServerMatcher
- {
- AZ_CLASS_ALLOCATOR(AssetCacheServerMatcher, AZ::SystemAllocator, 0);
- AZ_TYPE_INFO(AssetCacheServerMatcher, "{329A59C9-755E-4FA9-AADB-05C50AC62FD5}");
- static void Reflect(AZ::SerializeContext* serializeContext)
- {
- serializeContext->Class<AssetCacheServerMatcher>()->Version(0)
- ->Field("name", &AssetCacheServerMatcher::m_name)
- ->Field("glob", &AssetCacheServerMatcher::m_glob)
- ->Field("pattern", &AssetCacheServerMatcher::m_pattern)
- ->Field("productAssetType", &AssetCacheServerMatcher::m_productAssetType)
- ->Field("checkServer", &AssetCacheServerMatcher::m_checkServer);
- serializeContext->RegisterGenericType<AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher>>();
- }
- AZStd::string m_name;
- AZStd::string m_glob;
- AZStd::string m_pattern;
- AZ::Uuid m_productAssetType = AZ::Uuid::CreateNull();
- bool m_checkServer = false;
- };
- bool PlatformConfiguration::ConvertToJson(const RecognizerContainer& recognizerContainer, AZStd::string& jsonText)
- {
- AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher> assetCacheServerMatcherMap;
- for (const auto& recognizer : recognizerContainer)
- {
- AssetCacheServerMatcher matcher;
- matcher.m_name = recognizer.first;
- matcher.m_checkServer = recognizer.second.m_checkServer;
- matcher.m_productAssetType = recognizer.second.m_productAssetType;
- if (recognizer.second.m_patternMatcher.GetBuilderPattern().m_type == AssetBuilderSDK::AssetBuilderPattern::Wildcard)
- {
- matcher.m_glob = recognizer.second.m_patternMatcher.GetBuilderPattern().m_pattern;
- }
- else if (recognizer.second.m_patternMatcher.GetBuilderPattern().m_type == AssetBuilderSDK::AssetBuilderPattern::Regex)
- {
- matcher.m_pattern = recognizer.second.m_patternMatcher.GetBuilderPattern().m_pattern;
- }
- assetCacheServerMatcherMap.insert({"ACS " + matcher.m_name, matcher});
- }
- AZ::JsonSerializerSettings settings;
- AZ::ComponentApplicationBus::BroadcastResult(settings.m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
- settings.m_registrationContext = nullptr;
- rapidjson::Document jsonDocument;
- auto jsonResult = AZ::JsonSerialization::Store(jsonDocument, jsonDocument.GetAllocator(), assetCacheServerMatcherMap, settings);
- if (jsonResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
- {
- return false;
- }
- auto saveToFileOutcome = AZ::JsonSerializationUtils::WriteJsonString(jsonDocument, jsonText);
- return saveToFileOutcome.IsSuccess();
- }
- bool PlatformConfiguration::ConvertFromJson(const AZStd::string& jsonText, RecognizerContainer& recognizerContainer)
- {
- rapidjson::Document assetCacheServerMatcherDoc;
- assetCacheServerMatcherDoc.Parse(jsonText.c_str());
- if (assetCacheServerMatcherDoc.HasParseError())
- {
- return false;
- }
- AZ::JsonDeserializerSettings settings;
- AZ::ComponentApplicationBus::BroadcastResult(settings.m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
- settings.m_registrationContext = nullptr;
- AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher> assetCacheServerMatcherMap;
- auto resultCode = AZ::JsonSerialization::Load(assetCacheServerMatcherMap, assetCacheServerMatcherDoc, settings);
- if (!resultCode.HasDoneWork())
- {
- return false;
- }
- recognizerContainer.clear();
- for (const auto& matcher : assetCacheServerMatcherMap)
- {
- AssetRecognizer assetRecognizer;
- assetRecognizer.m_checkServer = matcher.second.m_checkServer;
- assetRecognizer.m_name = matcher.second.m_name;
- assetRecognizer.m_productAssetType = matcher.second.m_productAssetType;
- if (!matcher.second.m_glob.empty())
- {
- assetRecognizer.m_patternMatcher = { matcher.second.m_glob , AssetBuilderSDK::AssetBuilderPattern::Wildcard };
- }
- else if (!matcher.second.m_pattern.empty())
- {
- assetRecognizer.m_patternMatcher = { matcher.second.m_pattern , AssetBuilderSDK::AssetBuilderPattern::Regex };
- }
- recognizerContainer.insert({ "ACS " + matcher.second.m_name, assetRecognizer });
- }
- return !recognizerContainer.empty();
- }
- void PlatformConfiguration::Reflect(AZ::ReflectContext* context)
- {
- if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
- {
- AssetCacheServerMatcher::Reflect(serializeContext);
- }
- }
- bool PlatformConfiguration::ReadRecognizersFromSettingsRegistry(const QString& assetRoot, bool skipScanFolders, QStringList scanFolderPatterns)
- {
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not set."
- " Unable to read recognizers Asset Processor Settings");
- return false;
- }
- AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
- AZ::IO::FixedMaxPathString projectName = AZ::Utils::GetProjectName();
- AZ::IO::FixedMaxPath engineRoot(AZ::IO::PosixPathSeparator);
- settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
- engineRoot = engineRoot.LexicallyNormal(); // Normalize the path to use posix slashes
- AZ::s64 jobCount = m_minJobs;
- if (settingsRegistry->Get(jobCount, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/Jobs/minJobs"))
- {
- m_minJobs = aznumeric_cast<int>(jobCount);
- }
- jobCount = m_maxJobs;
- if (settingsRegistry->Get(jobCount, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/Jobs/maxJobs"))
- {
- m_maxJobs = aznumeric_cast<int>(jobCount);
- }
- if (!skipScanFolders)
- {
- AZStd::unordered_map<AZStd::string, AZ::IO::Path> gemNameToPathMap;
- auto MakeGemNameToPathMap = [&gemNameToPathMap, &projectPath, &engineRoot]
- (AZStd::string_view gemName, AZ::IO::PathView gemPath)
- {
- AZ::IO::FixedMaxPath gemAbsPath = gemPath;
- if (gemPath.IsRelative())
- {
- gemAbsPath = projectPath / gemPath;
- if (!AZ::IO::SystemFile::Exists(gemAbsPath.c_str()))
- {
- gemAbsPath = engineRoot / gemPath;
- }
- // convert the relative path to an absolute path
- if (!AZ::IO::SystemFile::Exists(gemAbsPath.c_str()))
- {
- if (auto gemAbsPathOpt = AZ::Utils::ConvertToAbsolutePath(gemPath.Native());
- gemAbsPathOpt.has_value())
- {
- gemAbsPath = AZStd::move(*gemAbsPathOpt);
- }
- }
- }
- if (AZ::IO::SystemFile::Exists(gemAbsPath.c_str()))
- {
- gemNameToPathMap.try_emplace(AZStd::string::format("@GEMROOT:%.*s@", AZ_STRING_ARG(gemName)), gemAbsPath.AsPosix());
- }
- };
- AZ::SettingsRegistryMergeUtils::VisitActiveGems(*settingsRegistry, MakeGemNameToPathMap);
- ScanFolderVisitor visitor;
- settingsRegistry->Visit(visitor, AssetProcessorSettingsKey);
- for (auto& scanFolderEntry : visitor.m_scanFolderInfos)
- {
- if (scanFolderEntry.m_watchPath.empty())
- {
- continue;
- }
- auto scanFolderMatch = [watchFolderQt = QString::fromUtf8(scanFolderEntry.m_watchPath.c_str(),
- aznumeric_cast<int>(scanFolderEntry.m_watchPath.Native().size()))](const QString& scanFolderPattern)
- {
- QRegExp nameMatch(scanFolderPattern, Qt::CaseInsensitive, QRegExp::Wildcard);
- return nameMatch.exactMatch(watchFolderQt);
- };
- if (!scanFolderPatterns.empty() && AZStd::none_of(scanFolderPatterns.begin(), scanFolderPatterns.end(), scanFolderMatch))
- {
- // Continue to the next iteration if the watch folder doesn't match any of the supplied patterns
- continue;
- }
- // Substitute macro values into the watch path and the scan folder display name
- AZStd::string assetRootPath = assetRoot.toUtf8().data();
- AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@ROOT@", assetRootPath.c_str());
- AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@PROJECTROOT@", projectPath.c_str());
- AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@ENGINEROOT@", engineRoot.c_str());
- // Normalize path make sure it is using posix slashes
- scanFolderEntry.m_watchPath = scanFolderEntry.m_watchPath.LexicallyNormal();
- AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@ROOT@", assetRootPath.c_str());
- AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@PROJECTROOT@", projectPath.c_str());
- AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@PROJECTNAME@", projectName.c_str());
- AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@ENGINEROOT@", engineRoot.c_str());
- // Substitute gem root path if applicable
- if (scanFolderEntry.m_watchPath.Native().contains("@GEMROOT")
- || scanFolderEntry.m_scanFolderDisplayName.contains("@GEMROOT"))
- {
- for (const auto& [gemAlias, gemPath] : gemNameToPathMap)
- {
- AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), gemAlias.c_str(), gemPath.c_str());
- AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, gemAlias.c_str(), gemPath.c_str());
- }
- }
- QStringList includeIdentifiers;
- for (AZStd::string_view includeIdentifier : scanFolderEntry.m_includeIdentifiers)
- {
- includeIdentifiers.push_back(QString::fromUtf8(includeIdentifier.data(), aznumeric_cast<int>(includeIdentifier.size())));
- }
- QStringList excludeIdentifiers;
- for (AZStd::string_view excludeIdentifier : scanFolderEntry.m_excludeIdentifiers)
- {
- excludeIdentifiers.push_back(QString::fromUtf8(excludeIdentifier.data(), aznumeric_cast<int>(excludeIdentifier.size())));
- }
- AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
- PopulatePlatformsForScanFolder(platforms, includeIdentifiers, excludeIdentifiers);
- const bool isEngineRoot = scanFolderEntry.m_watchPath == engineRoot;
- // If the scan folder happens to be the engine root, it is not recursive
- scanFolderEntry.m_isRecursive = scanFolderEntry.m_isRecursive && !isEngineRoot;
- // New assets can be saved in any scan folder defined except for the engine root.
- const bool canSaveNewAssets = !isEngineRoot;
- QString watchFolderPath = QString::fromUtf8(scanFolderEntry.m_watchPath.c_str(), static_cast<int>(scanFolderEntry.m_watchPath.Native().size()));
- watchFolderPath = AssetUtilities::NormalizeDirectoryPath(watchFolderPath);
- AddScanFolder(ScanFolderInfo(
- watchFolderPath,
- QString::fromUtf8(scanFolderEntry.m_scanFolderDisplayName.c_str(), aznumeric_cast<int>(scanFolderEntry.m_scanFolderDisplayName.size())),
- QString::fromUtf8(scanFolderEntry.m_scanFolderIdentifier.c_str(), aznumeric_cast<int>(scanFolderEntry.m_scanFolderIdentifier.size())),
- isEngineRoot,
- scanFolderEntry.m_isRecursive,
- platforms,
- scanFolderEntry.m_scanOrder,
- 0,
- canSaveNewAssets
- ));
- }
- }
- ExcludeVisitor excludeVisitor;
- settingsRegistry->Visit(excludeVisitor, AssetProcessorSettingsKey);
- for (auto&& excludeRecognizer: excludeVisitor.m_excludeAssetRecognizers)
- {
- m_excludeAssetRecognizers[excludeRecognizer.m_name] = AZStd::move(excludeRecognizer);
- }
- SimpleJobVisitor simpleJobVisitor(m_enabledPlatforms);
- settingsRegistry->Visit(simpleJobVisitor, AssetProcessorSettingsKey);
- for (auto&& sjRecognizer : simpleJobVisitor.m_assetRecognizers)
- {
- if (!sjRecognizer.m_recognizer.m_platformSpecs.empty() && !sjRecognizer.m_ignore)
- {
- m_assetRecognizers[sjRecognizer.m_recognizer.m_name] = AZStd::move(sjRecognizer.m_recognizer);
- }
- }
- ACSVisitor acsVistor;
- settingsRegistry->Visit(acsVistor, AssetProcessorServerKey);
- for (auto&& acsRecognizer : acsVistor.m_assetRecognizers)
- {
- m_assetCacheServerRecognizers[acsRecognizer.m_name] = AZStd::move(acsRecognizer);
- }
- return true;
- }
- void PlatformConfiguration::ReadMetaDataFromSettingsRegistry()
- {
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- if (settingsRegistry == nullptr)
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not set."
- " MetaDataTypes entries cannot be read from Asset Processor Settings");
- return;
- }
- MetaDataTypesVisitor visitor;
- settingsRegistry->Visit(visitor, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/MetaDataTypes");
- using namespace AzToolsFramework::AssetUtils;
- AZStd::vector<AZStd::string> supportedFileExtensions;
- AssetImporterPathsVisitor assetImporterVisitor{ settingsRegistry, supportedFileExtensions };
- settingsRegistry->Visit(assetImporterVisitor, AZ::SettingsRegistryInterface::FixedValueString(AssetImporterSettingsKey) + "/" + AssetImporterSupportedFileTypeKey);
- for (auto& entry : assetImporterVisitor.m_supportedFileExtensions)
- {
- visitor.m_metaDataTypes.push_back({ AZStd::string::format("%s.assetinfo", entry.c_str()), entry });
- }
- AddMetaDataType(AzToolsFramework::MetadataManager::MetadataFileExtensionNoDot, "");
- for (const auto& metaDataType : visitor.m_metaDataTypes)
- {
- QString fileType = AssetUtilities::NormalizeFilePath(QString::fromUtf8(metaDataType.m_fileType.c_str(),
- aznumeric_cast<int>(metaDataType.m_fileType.size())));
- auto extensionType = QString::fromUtf8(metaDataType.m_extensionType.c_str(),
- aznumeric_cast<int>(metaDataType.m_extensionType.size()));
- AddMetaDataType(fileType, extensionType);
- // Check if the Metadata 'file type' is a real file
- QString fullPath = FindFirstMatchingFile(fileType);
- if (!fullPath.isEmpty())
- {
- m_metaDataRealFiles.insert(fileType.toLower());
- }
- }
- }
- int PlatformConfiguration::GetProjectScanFolderOrder() const
- {
- auto mainProjectScanFolder = FindScanFolder([](const AssetProcessor::ScanFolderInfo& scanFolderInfo) -> bool
- {
- return scanFolderInfo.GetPortableKey() == ProjectScanFolderKey;
- });
- if (mainProjectScanFolder)
- {
- return mainProjectScanFolder->GetOrder();
- }
- return 0;
- }
- bool PlatformConfiguration::MergeConfigFileToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, const AZ::IO::PathView& configFile)
- {
- // If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function
- // otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style
- // file to the settings registry
- if (configFile.Extension() == ".setreg")
- {
- return settingsRegistry.MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch).IsSuccess();
- }
- AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings;
- configParserSettings.m_registryRootPointerPath = AssetProcessorSettingsKey;
- return AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(settingsRegistry, configFile.Native(), configParserSettings);
- }
- const AZStd::vector<AssetBuilderSDK::PlatformInfo>& PlatformConfiguration::GetEnabledPlatforms() const
- {
- return m_enabledPlatforms;
- }
- const AssetBuilderSDK::PlatformInfo* const PlatformConfiguration::GetPlatformByIdentifier(const char* identifier) const
- {
- for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms)
- {
- if (platform.m_identifier == identifier)
- {
- // this may seem odd - returning a pointer into a vector, but this vector is initialized once during startup and then remains static thereafter.
- return &platform;
- }
- }
- return nullptr;
- }
- QPair<QString, QString> PlatformConfiguration::GetMetaDataFileTypeAt(int pos) const
- {
- return m_metaDataFileTypes[pos];
- }
- bool PlatformConfiguration::IsMetaDataTypeRealFile(QString relativeName) const
- {
- return m_metaDataRealFiles.find(relativeName.toLower()) != m_metaDataRealFiles.end();
- }
- void PlatformConfiguration::EnablePlatform(const AssetBuilderSDK::PlatformInfo& platform, bool enable)
- {
- // remove it if present.
- auto platformIt = std::find_if(m_enabledPlatforms.begin(), m_enabledPlatforms.end(), [&](const AssetBuilderSDK::PlatformInfo& info)
- {
- return info.m_identifier == platform.m_identifier;
- });
- if (platformIt != m_enabledPlatforms.end())
- {
- // already present - replace or remove it.
- if (enable)
- {
- *platformIt = platform;
- }
- else
- {
- m_enabledPlatforms.erase(platformIt);
- }
- }
- else
- {
- // it is not already present. we only add it if we're enabling.
- // if we're disabling, there's nothing to do.
- if (enable)
- {
- m_enabledPlatforms.push_back(platform);
- }
- }
- }
- bool PlatformConfiguration::GetMatchingRecognizers(QString fileName, RecognizerPointerContainer& output) const
- {
- bool foundAny = false;
- if (IsFileExcluded(fileName))
- {
- //if the file is excluded than return false;
- return false;
- }
- for (const auto& assetRecognizer : m_assetRecognizers)
- {
- const AssetRecognizer& recognizer = assetRecognizer.second;
- if (recognizer.m_patternMatcher.MatchesPath(fileName.toUtf8().constData()))
- {
- // found a match
- output.push_back(&recognizer);
- foundAny = true;
- }
- }
- return foundAny;
- }
- int PlatformConfiguration::GetScanFolderCount() const
- {
- return aznumeric_caster(m_scanFolders.size());
- }
- AZStd::vector<AzFramework::GemInfo> PlatformConfiguration::GetGemsInformation() const
- {
- return m_gemInfoList;
- }
- AssetProcessor::ScanFolderInfo& PlatformConfiguration::GetScanFolderAt(int index)
- {
- Q_ASSERT(index >= 0);
- Q_ASSERT(index < m_scanFolders.size());
- return m_scanFolders[index];
- }
- const AssetProcessor::ScanFolderInfo& PlatformConfiguration::GetScanFolderAt(int index) const
- {
- Q_ASSERT(index >= 0);
- Q_ASSERT(index < m_scanFolders.size());
- return m_scanFolders[index];
- }
- const AssetProcessor::ScanFolderInfo* PlatformConfiguration::FindScanFolder(
- AZStd::function<bool(const AssetProcessor::ScanFolderInfo&)> predicate) const
- {
- auto resultIt = AZStd::ranges::find_if(m_scanFolders, predicate);
- return resultIt != m_scanFolders.end() ? &(*resultIt) : nullptr;
- }
- const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderById(AZ::s64 id) const
- {
- return FindScanFolder([id](const ScanFolderInfo& scanFolder)
- {
- return scanFolder.ScanFolderID() == id;
- });
- }
- void PlatformConfiguration::AddScanFolder(const AssetProcessor::ScanFolderInfo& source, bool isUnitTesting)
- {
- if (isUnitTesting)
- {
- //using a bool instead of using #define UNIT_TEST because the user can also run batch processing in unittest
- m_scanFolders.push_back(source);
- // since we're synthesizing folder adds, assign ascending folder ids if not provided.
- if (source.ScanFolderID() == 0)
- {
- m_scanFolders.back().SetScanFolderID(m_scanFolders.size() - 1);
- }
- return;
- }
- // Find and remove any previous matching entry, last entry wins
- auto it = std::find_if(m_scanFolders.begin(), m_scanFolders.end(), [&source](const ScanFolderInfo& info)
- {
- return info.GetPortableKey().toLower() == source.GetPortableKey().toLower();
- });
- if (it != m_scanFolders.end())
- {
- m_scanFolders.erase(it);
- }
- m_scanFolders.push_back(source);
- std::stable_sort(m_scanFolders.begin(), m_scanFolders.end(), [](const ScanFolderInfo& a, const ScanFolderInfo& b)
- {
- return a.GetOrder() < b.GetOrder();
- }
- );
- }
- void PlatformConfiguration::AddRecognizer(const AssetRecognizer& source)
- {
- m_assetRecognizers.insert({source.m_name, source});
- }
- void PlatformConfiguration::RemoveRecognizer(QString name)
- {
- auto found = m_assetRecognizers.find(name.toUtf8().data());
- m_assetRecognizers.erase(found);
- }
- void PlatformConfiguration::AddMetaDataType(const QString& type, const QString& extension)
- {
- QPair<QString, QString> key = qMakePair(type.toLower(), extension.toLower());
- if (!m_metaDataFileTypes.contains(key))
- {
- m_metaDataFileTypes.push_back(key);
- }
- }
- bool PlatformConfiguration::ConvertToRelativePath(QString fullFileName, QString& databaseSourceName, QString& scanFolderName) const
- {
- const ScanFolderInfo* info = GetScanFolderForFile(fullFileName);
- if (info)
- {
- scanFolderName = info->ScanPath();
- scanFolderName.replace(AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR);
- return ConvertToRelativePath(fullFileName, info, databaseSourceName);
- }
- // did not find it.
- return false;
- }
- bool PlatformConfiguration::ConvertToRelativePath(const QString& fullFileName, const ScanFolderInfo* scanFolderInfo, QString& databaseSourceName)
- {
- if(!scanFolderInfo)
- {
- return false;
- }
- QString relPath; // empty string.
- if (fullFileName.length() > scanFolderInfo->ScanPath().length())
- {
- relPath = fullFileName.right(fullFileName.length() - scanFolderInfo->ScanPath().length() - 1); // also eat the slash, hence -1
- }
- databaseSourceName = relPath;
- databaseSourceName.replace(AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR);
- return true;
- }
- QString PlatformConfiguration::GetOverridingFile(QString relativeName, QString scanFolderName) const
- {
- for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
- {
- AssetProcessor::ScanFolderInfo scanFolderInfo = m_scanFolders[pathIdx];
- if (scanFolderName.compare(scanFolderInfo.ScanPath(), Qt::CaseInsensitive) == 0)
- {
- // we have found the actual folder containing the file we started with
- // since all other folders "deeper" in the override vector are lower priority than this one
- // (they are sorted in priority order, most priority first).
- return QString();
- }
- QString tempRelativeName(relativeName);
- if ((!scanFolderInfo.RecurseSubFolders()) && (tempRelativeName.contains('/')))
- {
- // the name is a deeper relative path, but we don't recurse this scan folder, so it can't win
- continue;
- }
- // note that we only Update To Correct Case here, because this is one of the few situations where
- // a file with the same relative path may be overridden but different case.
- if (AssetUtilities::UpdateToCorrectCase(scanFolderInfo.ScanPath(), tempRelativeName))
- {
- // we have found a file in an earlier scan folder that would override this file
- return QDir(scanFolderInfo.ScanPath()).absoluteFilePath(tempRelativeName);
- }
- }
- // we found it nowhere.
- return QString();
- }
- // This function is one of the most frequently called ones in the entire application
- // and is invoked several times per file. It can frequently become a bottleneck, so
- // avoid doing expensive operations here, especially memory or IO operations.
- QString PlatformConfiguration::FindFirstMatchingFile(QString relativeName, bool skipIntermediateScanFolder) const
- {
- if (relativeName.isEmpty())
- {
- return QString();
- }
- auto* fileStateInterface = AZ::Interface<AssetProcessor::IFileStateRequests>::Get();
- // Only compute the intermediate assets folder path if we are going to search for and skip it.
- if (skipIntermediateScanFolder)
- {
- if (m_intermediateAssetScanFolderId == -1)
- {
- CacheIntermediateAssetsScanFolderId();
- }
- }
- QString absolutePath; // avoid allocating memory repeatedly here by reusing absolutePath each scan folder.
- absolutePath.reserve(AZ_MAX_PATH_LEN);
- QFileInfo details(relativeName); // note that this does not actually hit the actual storage medium until you query something
- bool isAbsolute = details.isAbsolute(); // note that this looks at the file name string only, it does not hit storage.
- for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
- {
- const AssetProcessor::ScanFolderInfo& scanFolderInfo = m_scanFolders[pathIdx];
- if ((skipIntermediateScanFolder) && (scanFolderInfo.ScanFolderID() == m_intermediateAssetScanFolderId))
- {
- // There's only 1 intermediate assets folder, if we've skipped it, theres no point continuing to check every folder afterwards
- skipIntermediateScanFolder = false;
- continue;
- }
- if ((!scanFolderInfo.RecurseSubFolders()) && (relativeName.contains('/')))
- {
- // the name is a deeper relative path, but we don't recurse this scan folder, so it can't win
- continue;
- }
- if (isAbsolute)
- {
- if (!relativeName.startsWith(scanFolderInfo.ScanPath()))
- {
- continue; // its not this scanfolder.
- }
- absolutePath = relativeName;
- }
- else
- {
- // scanfolders are always absolute paths and already normalized. We can just concatenate.
- // Do so with minimal allocation by using resize/append, instead of operator+
- absolutePath.resize(0);
- absolutePath.append(scanFolderInfo.ScanPath());
- absolutePath.append('/');
- absolutePath.append(relativeName);
- }
- AssetProcessor::FileStateInfo fileStateInfo;
- if (fileStateInterface)
- {
- if (fileStateInterface->GetFileInfo(absolutePath, &fileStateInfo))
- {
- return AssetUtilities::NormalizeFilePath(fileStateInfo.m_absolutePath);
- }
- }
- }
- return QString();
- }
- QStringList PlatformConfiguration::FindWildcardMatches(
- const QString& sourceFolder,
- QString relativeName,
- bool includeFolders,
- bool recursiveSearch) const
- {
- if (relativeName.isEmpty())
- {
- return QStringList();
- }
- QDir sourceFolderDir(sourceFolder);
- QString posixRelativeName = QDir::fromNativeSeparators(relativeName);
- QStringList returnList;
- QRegExp nameMatch{ posixRelativeName, Qt::CaseInsensitive, QRegExp::Wildcard };
- QDirIterator dirIterator(
- sourceFolderDir.path(), QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot,
- recursiveSearch ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags);
- QStringList files;
- while (dirIterator.hasNext())
- {
- dirIterator.next();
- if (!includeFolders && !dirIterator.fileInfo().isFile())
- {
- continue;
- }
- QString pathMatch{ sourceFolderDir.relativeFilePath(dirIterator.filePath()) };
- if (nameMatch.exactMatch(pathMatch))
- {
- returnList.append(QDir::fromNativeSeparators(dirIterator.filePath()));
- }
- }
- return returnList;
- }
- QStringList PlatformConfiguration::FindWildcardMatches(
- const QString& sourceFolder,
- QString relativeName,
- const AZStd::unordered_set<AZStd::string>& excludedFolders,
- bool includeFolders,
- bool recursiveSearch) const
- {
- if (relativeName.isEmpty())
- {
- return QStringList();
- }
- QDir sourceFolderDir(sourceFolder);
- QString posixRelativeName = QDir::fromNativeSeparators(relativeName);
- QStringList returnList;
- QRegExp nameMatch{ posixRelativeName, Qt::CaseInsensitive, QRegExp::Wildcard };
- AZStd::stack<QString> dirs;
- dirs.push(sourceFolderDir.absolutePath());
- while (!dirs.empty())
- {
- QString absolutePath = dirs.top();
- dirs.pop();
- if (excludedFolders.contains(absolutePath.toUtf8().constData()))
- {
- continue;
- }
- QDirIterator dirIterator(absolutePath, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot);
- while (dirIterator.hasNext())
- {
- dirIterator.next();
- if (!dirIterator.fileInfo().isFile())
- {
- if (recursiveSearch)
- {
- dirs.push(dirIterator.filePath());
- }
- if (!includeFolders)
- {
- continue;
- }
- }
- QString pathMatch{ sourceFolderDir.relativeFilePath(dirIterator.filePath()) };
- if (nameMatch.exactMatch(pathMatch))
- {
- returnList.append(QDir::fromNativeSeparators(dirIterator.filePath()));
- }
- }
- }
- return returnList;
- }
- const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderForFile(const QString& fullFileName) const
- {
- QString normalized = AssetUtilities::NormalizeFilePath(fullFileName);
- // first, check for an EXACT match. If there's an exact match, this must be the one returned!
- // this is to catch the case where the actual path of a scan folder is fed in to this.
- // because exact matches are preferred over less exact, we first check exact matches:
- for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
- {
- QString scanFolderName = m_scanFolders[pathIdx].ScanPath();
- if (scanFolderName.length() == normalized.length())
- {
- if (normalized.compare(scanFolderName, Qt::CaseInsensitive) == 0)
- {
- // if its an exact match, we're basically done
- return &m_scanFolders[pathIdx];
- }
- }
- }
- for (int pathIdx = 0; pathIdx < m_scanFolders.size(); ++pathIdx)
- {
- QString scanFolderName = m_scanFolders[pathIdx].ScanPath();
- if (normalized.length() > scanFolderName.length())
- {
- if (normalized.startsWith(scanFolderName, Qt::CaseInsensitive))
- {
- QChar examineChar = normalized[scanFolderName.length()]; // it must be a slash or its just a scan folder that starts with the same thing by coincidence.
- if (examineChar != QChar('/'))
- {
- continue;
- }
- QString relPath = normalized.right(normalized.length() - scanFolderName.length() - 1); // also eat the slash, hence -1
- if (!m_scanFolders[pathIdx].RecurseSubFolders())
- {
- // we only allow things that are in the root for nonrecursive folders
- if (relPath.contains('/'))
- {
- continue;
- }
- }
- return &m_scanFolders[pathIdx];
- }
- }
- }
- return nullptr; // not found.
- }
- //! Given a scan folder path, get its complete info
- const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderByPath(const QString& scanFolderPath) const
- {
- return FindScanFolder([&scanFolderPath](const AssetProcessor::ScanFolderInfo& scanFolder)
- {
- return scanFolder.ScanPath() == scanFolderPath;
- });
- }
- int PlatformConfiguration::GetMinJobs() const
- {
- return m_minJobs;
- }
- int PlatformConfiguration::GetMaxJobs() const
- {
- return m_maxJobs;
- }
- void PlatformConfiguration::EnableCommonPlatform()
- {
- EnablePlatform(AssetBuilderSDK::PlatformInfo{ AssetBuilderSDK::CommonPlatformName, AZStd::unordered_set<AZStd::string>{ "common" } });
- }
- void PlatformConfiguration::AddIntermediateScanFolder()
- {
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- AZ::SettingsRegistryInterface::FixedValueString cacheRootFolder;
- settingsRegistry->Get(cacheRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder);
- AZ::IO::Path scanfolderPath = cacheRootFolder.c_str();
- scanfolderPath /= IntermediateAssetsFolderName;
- AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
- PopulatePlatformsForScanFolder(platforms);
- scanfolderPath = AssetUtilities::NormalizeDirectoryPath(QString::fromUtf8(scanfolderPath.c_str())).toUtf8().constData();
- // By default the project scanfolder is recursive with an order of 0
- // The intermediate assets folder needs to be higher priority since its a subfolder (otherwise GetScanFolderForFile won't pick the right scanfolder)
- constexpr int order = -1;
- AddScanFolder(ScanFolderInfo{
- scanfolderPath.c_str(),
- IntermediateAssetsFolderName,
- IntermediateAssetsFolderName,
- false,
- true,
- platforms,
- order
- });
- }
- void PlatformConfiguration::AddGemScanFolders(const AZStd::vector<AzFramework::GemInfo>& gemInfoList)
- {
- // If the gem is project-relative, make adjustments to its priority order based on registry settings:
- // /Amazon/AssetProcessor/Settings/GemScanFolderStartingPriorityOrder
- // /Amazon/AssetProcessor/Settings/ProjectRelativeGemsScanFolderPriority
- // See <o3de-root>/Registry/AssetProcessorPlatformConfig.setreg for more information.
- AZ::s64 gemStartingOrder = 100;
- AZStd::string projectGemPrioritySetting{};
- const AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
- int pathCount = 0;
- const int projectScanOrder = GetProjectScanFolderOrder();
- if (auto const settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
- {
- settingsRegistry->Get(gemStartingOrder,
- AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + GemStartingPriorityOrderKey);
- settingsRegistry->Get(projectGemPrioritySetting,
- AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + ProjectRelativeGemPriorityKey);
- AZStd::to_lower(projectGemPrioritySetting.begin(), projectGemPrioritySetting.end());
- }
- auto GetGemFolderOrder = [&](bool isProjectRelativeGem) -> int
- {
- ++pathCount;
- int currentGemOrder = aznumeric_cast<int>(gemStartingOrder) + pathCount;
- if (isProjectRelativeGem)
- {
- if (projectGemPrioritySetting == "higher")
- {
- currentGemOrder = projectScanOrder - pathCount;
- }
- else if (projectGemPrioritySetting == "lower")
- {
- currentGemOrder = projectScanOrder + pathCount;
- }
- }
- return currentGemOrder;
- };
- int gemOrder = aznumeric_cast<int>(gemStartingOrder);
- AZStd::vector<AssetBuilderSDK::PlatformInfo> platforms;
- PopulatePlatformsForScanFolder(platforms);
- for (const AzFramework::GemInfo& gemElement : gemInfoList)
- {
- for (size_t sourcePathIndex{}; sourcePathIndex < gemElement.m_absoluteSourcePaths.size(); ++sourcePathIndex)
- {
- const AZ::IO::Path& absoluteSourcePath = gemElement.m_absoluteSourcePaths[sourcePathIndex];
- QString gemAbsolutePath = QString::fromUtf8(absoluteSourcePath.c_str(), aznumeric_cast<int>(absoluteSourcePath.Native().size())); // this is an absolute path!
- const bool isProjectGem = absoluteSourcePath.IsRelativeTo(projectPath);
- // Append the index of the source path array element to make a unique portable key is created for each path of a gem
- AZ::Uuid gemNameUuid = AZ::Uuid::CreateName((gemElement.m_gemName + AZStd::to_string(sourcePathIndex)).c_str());
- QString gemNameAsUuid(gemNameUuid.ToFixedString().c_str());
- QDir gemDir(gemAbsolutePath);
- // The gems /Assets/ folders are always added to the watch list, we want the following params
- // Watched folder: (absolute path to the gem /Assets/ folder) MUST BE CORRECT CASE
- // Display name: "Gems/GemName/Assets" // uppercase, for human eyes
- // portable Key: "gemassets-(UUID Of Gem)"
- // Is Root: False
- // Recursive: True
- QString gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemAssetFolder());
- // note that we normalize this gem path with slashes so that there's nothing special about it compared to other scan folders
- gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder);
- QString assetBrowserDisplayName = AzFramework::GemInfo::GetGemAssetFolder(); // Gems always use assets folder as their displayname...
- QString portableKey = QString("gemassets-%1").arg(gemNameAsUuid);
- bool isRoot = false;
- bool isRecursive = true;
- gemOrder = GetGemFolderOrder(isProjectGem);
- AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM assets folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data());
- AddScanFolder(ScanFolderInfo(
- gemFolder,
- assetBrowserDisplayName,
- portableKey,
- isRoot,
- isRecursive,
- platforms,
- gemOrder,
- /*scanFolderId*/ 0,
- /*canSaveNewAssets*/ true)); // Users can create assets like slices in Gem asset folders.
- // Now add another scan folder on Gem/GemName/Registry...
- gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemRegistryFolder());
- gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder);
- assetBrowserDisplayName = AzFramework::GemInfo::GetGemRegistryFolder();
- portableKey = QString("gemregistry-%1").arg(gemNameAsUuid);
- gemOrder = GetGemFolderOrder(isProjectGem);
- AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM registry folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data());
- AddScanFolder(ScanFolderInfo(
- gemFolder,
- assetBrowserDisplayName,
- portableKey,
- isRoot,
- isRecursive,
- platforms,
- gemOrder));
- }
- }
- }
- const RecognizerContainer& PlatformConfiguration::GetAssetRecognizerContainer() const
- {
- return m_assetRecognizers;
- }
- const RecognizerContainer& PlatformConfiguration::GetAssetCacheRecognizerContainer() const
- {
- return m_assetCacheServerRecognizers;
- }
- const ExcludeRecognizerContainer& PlatformConfiguration::GetExcludeAssetRecognizerContainer() const
- {
- return m_excludeAssetRecognizers;
- }
- bool PlatformConfiguration::AddAssetCacheRecognizerContainer(const RecognizerContainer& recognizerContainer)
- {
- bool addedEntries = false;
- for (const auto& recognizer : recognizerContainer)
- {
- auto entryIter = m_assetCacheServerRecognizers.find(recognizer.first);
- if (entryIter != m_assetCacheServerRecognizers.end())
- {
- m_assetCacheServerRecognizers.insert(recognizer);
- addedEntries = true;
- }
- }
- return addedEntries;
- }
- // AssetProcessor
- void AssetProcessor::PlatformConfiguration::AddExcludeRecognizer(const ExcludeAssetRecognizer& recogniser)
- {
- m_excludeAssetRecognizers.insert(recogniser.m_name, recogniser);
- }
- void AssetProcessor::PlatformConfiguration::RemoveExcludeRecognizer(QString name)
- {
- auto found = m_excludeAssetRecognizers.find(name);
- if (found != m_excludeAssetRecognizers.end())
- {
- m_excludeAssetRecognizers.erase(found);
- }
- }
- bool AssetProcessor::PlatformConfiguration::IsFileExcluded(QString fileName) const
- {
- QString relPath, scanFolderName;
- if (ConvertToRelativePath(fileName, relPath, scanFolderName))
- {
- return IsFileExcludedRelPath(relPath);
- }
- return false;
- }
- bool AssetProcessor::PlatformConfiguration::IsFileExcludedRelPath(QString relPath) const
- {
- AZ::IO::FixedMaxPathString encoded = relPath.toUtf8().constData();
- for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
- {
- if (excludeRecognizer.m_patternMatcher.MatchesPath(encoded.c_str()))
- {
- return true;
- }
- }
- return false;
- }
- bool AssetProcessor::PlatformConfiguration::IsValid() const
- {
- if (m_fatalError.empty())
- {
- if (m_enabledPlatforms.empty())
- {
- 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.";
- }
- else if (m_assetRecognizers.empty())
- {
- 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.";
- }
- else if (m_scanFolders.empty())
- {
- m_fatalError = "The configuration is invalid - no scan folders defined. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct.";
- }
- }
- if (!m_fatalError.empty())
- {
- AZ_Error(AssetProcessor::ConsoleChannel, false, "Error: %s", m_fatalError.c_str());
- return false;
- }
- return true;
- }
- const AZStd::string& AssetProcessor::PlatformConfiguration::GetError() const
- {
- return m_fatalError;
- }
- } // namespace assetProcessor
|