2
0
Эх сурвалжийг харах

Converted more of AP code to use SourceAssetReference

Signed-off-by: amzn-mike <[email protected]>
amzn-mike 2 жил өмнө
parent
commit
fcde4ded01

+ 2 - 2
Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp

@@ -1977,10 +1977,10 @@ namespace AssetProcessor
         return found && succeeded;
     }
 
-    bool AssetDatabaseConnection::GetJobsBySourceName(QString exactSourceName, JobDatabaseEntryContainer& container, AZ::Uuid builderGuid, QString jobKey, QString platform, JobStatus status)
+    bool AssetDatabaseConnection::GetJobsBySourceName(const SourceAssetReference& sourceAsset, JobDatabaseEntryContainer& container, AZ::Uuid builderGuid, QString jobKey, QString platform, JobStatus status)
     {
         bool found = false;
-        bool succeeded = QuerySourceBySourceName(exactSourceName.toUtf8().constData(),
+        bool succeeded = QuerySourceBySourceNameScanFolderID(sourceAsset.RelativePath().c_str(), sourceAsset.ScanfolderId(),
             [&](SourceDatabaseEntry& source)
         {
             succeeded = QueryJobBySourceID(source.m_sourceID,

+ 2 - 1
Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.h

@@ -18,6 +18,7 @@
 #include <QtCore/QString>
 
 #include "AzToolsFramework/API/EditorAssetSystemAPI.h"
+#include <native/AssetManager/SourceAssetReference.h>
 
 class QStringList;
 
@@ -111,7 +112,7 @@ namespace AssetProcessor
         bool GetJobByProductID(AZ::s64 productID, AzToolsFramework::AssetDatabase::JobDatabaseEntry& entry);
 
         bool GetJobsBySourceID(AZ::s64 sourceID, AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer& container, AZ::Uuid builderGuid = AZ::Uuid::CreateNull(), QString jobKey = QString(), QString platform = QString(), AzToolsFramework::AssetSystem::JobStatus status = AzToolsFramework::AssetSystem::JobStatus::Any);
-        bool GetJobsBySourceName(QString exactSourceName, AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer& container, AZ::Uuid builderGuid = AZ::Uuid::CreateNull(), QString jobKey = QString(), QString platform = QString(), AzToolsFramework::AssetSystem::JobStatus status = AzToolsFramework::AssetSystem::JobStatus::Any);
+        bool GetJobsBySourceName(const AssetProcessor::SourceAssetReference& sourceAsset, AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer& container, AZ::Uuid builderGuid = AZ::Uuid::CreateNull(), QString jobKey = QString(), QString platform = QString(), AzToolsFramework::AssetSystem::JobStatus status = AzToolsFramework::AssetSystem::JobStatus::Any);
         bool GetJobsLikeSourceName(QString likeSourceName, LikeType likeType, AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer& container, AZ::Uuid builderGuid = AZ::Uuid::CreateNull(), QString jobKey = QString(), QString platform = QString(), AzToolsFramework::AssetSystem::JobStatus status = AzToolsFramework::AssetSystem::JobStatus::Any);
 
         bool GetJobsByProductName(QString exactProductName, AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer& container, AZ::Uuid builderGuid = AZ::Uuid::CreateNull(), QString jobKey = QString(), QString platform = QString(), AzToolsFramework::AssetSystem::JobStatus status = AzToolsFramework::AssetSystem::JobStatus::Any);

+ 65 - 109
Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp

@@ -589,20 +589,16 @@ namespace AssetProcessor
         m_catalogIsDirty = true;
     }
 
-    void AssetCatalog::OnSourceQueued(AZ::Uuid sourceUuid, AZ::Uuid legacyUuid, QString rootPath, QString relativeFilePath)
+    void AssetCatalog::OnSourceQueued(AZ::Uuid sourceUuid, AZ::Uuid legacyUuid, const SourceAssetReference& sourceAsset)
     {
         AZStd::lock_guard<AZStd::mutex> lock(m_sourceUUIDToSourceNameMapMutex);
 
-        SourceInfo sourceInfo = { rootPath, relativeFilePath };
-        m_sourceUUIDToSourceNameMap.insert({ sourceUuid, sourceInfo });
+        m_sourceUUIDToSourceNameMap.insert({ sourceUuid, sourceAsset });
 
         //adding legacy source uuid as well
-        m_sourceUUIDToSourceNameMap.insert({ legacyUuid, sourceInfo });
+        m_sourceUUIDToSourceNameMap.insert({ legacyUuid, sourceAsset });
 
-        AZStd::string nameForMap(relativeFilePath.toUtf8().constData());
-        AZStd::to_lower(nameForMap.begin(), nameForMap.end());
-
-        m_sourceNameToSourceUUIDMap.insert({ nameForMap, sourceUuid });
+        m_sourceNameToSourceUUIDMap.insert({ sourceAsset, sourceUuid });
     }
 
     void AssetCatalog::OnSourceFinished(AZ::Uuid sourceUuid, AZ::Uuid legacyUuid)
@@ -612,9 +608,7 @@ namespace AssetProcessor
         auto found = m_sourceUUIDToSourceNameMap.find(sourceUuid);
         if (found != m_sourceUUIDToSourceNameMap.end())
         {
-            AZStd::string nameForMap = found->second.m_sourceName.toUtf8().constData();
-            AZStd::to_lower(nameForMap.begin(), nameForMap.end());
-            m_sourceNameToSourceUUIDMap.erase(nameForMap);
+            m_sourceNameToSourceUUIDMap.erase(found->second);
         }
 
         m_sourceUUIDToSourceNameMap.erase(sourceUuid);
@@ -737,7 +731,10 @@ namespace AssetProcessor
         // If the assetType wasn't provided, try to guess it
         if (assetType.IsNull())
         {
-            return GetAssetInfoByIdOnly(assetId, platformName, assetInfo, rootFilePath);
+            SourceAssetReference sourceAsset;
+            bool result = GetAssetInfoByIdOnly(assetId, platformName, assetInfo, sourceAsset);
+            rootFilePath = sourceAsset.ScanfolderPath().c_str();
+            return result;
         }
 
         bool isSourceType;
@@ -750,17 +747,14 @@ namespace AssetProcessor
         // If the assetType is registered as a source type, look up the source info
         if (isSourceType)
         {
-            AZStd::string relativePath;
+            SourceAssetReference sourceAsset;
 
-            if (GetSourceFileInfoFromAssetId(assetId, rootFilePath, relativePath))
+            if (GetSourceFileInfoFromAssetId(assetId, sourceAsset))
             {
-                AZStd::string sourceFileFullPath;
-                AzFramework::StringFunc::Path::Join(rootFilePath.c_str(), relativePath.c_str(), sourceFileFullPath);
-
                 assetInfo.m_assetId = assetId;
                 assetInfo.m_assetType = assetType;
-                assetInfo.m_relativePath = relativePath;
-                assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceFileFullPath.c_str());
+                assetInfo.m_relativePath = sourceAsset.RelativePath().c_str();
+                assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceAsset.AbsolutePath().c_str());
 
                 return true;
             }
@@ -954,20 +948,17 @@ namespace AssetProcessor
 
     bool AssetCatalog::GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder)
     {
-        if (!sourcePath)
+        if (!sourcePath || strlen(sourcePath) <= 0)
         {
             assetInfo.m_assetId.SetInvalid();
             return false;
         }
 
-        // regardless of which way we come into this function we must always use ConvertToRelativePath
-        // to convert from whatever the input format is to a database path (which may include output prefix)
-        QString databaseName;
-        QString scanFolder;
+        SourceAssetReference sourceAsset;
+
         if (!AzFramework::StringFunc::Path::IsRelative(sourcePath))
         {
-            // absolute paths just get converted directly.
-            m_platformConfig->ConvertToRelativePath(QString::fromUtf8(sourcePath), databaseName, scanFolder);
+            sourceAsset = SourceAssetReference(sourcePath);
         }
         else
         {
@@ -975,11 +966,11 @@ namespace AssetProcessor
             QString absolutePath = m_platformConfig->FindFirstMatchingFile(QString::fromUtf8(sourcePath));
             if (!absolutePath.isEmpty())
             {
-                m_platformConfig->ConvertToRelativePath(absolutePath, databaseName, scanFolder);
+                sourceAsset = SourceAssetReference(absolutePath);
             }
         }
 
-        if ((databaseName.isEmpty()) || (scanFolder.isEmpty()))
+        if (!sourceAsset)
         {
             assetInfo.m_assetId.SetInvalid();
             return false;
@@ -994,7 +985,7 @@ namespace AssetProcessor
             AZStd::lock_guard<AZStd::mutex> lock(m_databaseMutex);
             AzToolsFramework::AssetDatabase::SourceDatabaseEntryContainer returnedSources;
 
-            if (m_db->GetSourcesBySourceName(databaseName, returnedSources))
+            if (m_db->GetSourcesBySourceNameScanFolderId(sourceAsset.RelativePath().c_str(), sourceAsset.ScanfolderId(), returnedSources))
             {
                 if (!returnedSources.empty())
                 {
@@ -1031,30 +1022,31 @@ namespace AssetProcessor
             }
         }
 
+        watchFolder = sourceAsset.ScanfolderPath().c_str();
+
         // Source file isn't in the database yet, see if its in the job queue
-        if (GetQueuedAssetInfoByRelativeSourceName(databaseName.toUtf8().data(), assetInfo, watchFolder))
+        if (GetQueuedAssetInfoByRelativeSourceName(sourceAsset, assetInfo))
         {
             return true;
         }
 
         // Source file isn't in the job queue yet, source UUID needs to be created
-        watchFolder = scanFolder.toUtf8().data();
-        return GetUncachedSourceInfoFromDatabaseNameAndWatchFolder(databaseName.toUtf8().data(), watchFolder.c_str(), assetInfo);
+        return GetUncachedSourceInfoFromDatabaseNameAndWatchFolder(sourceAsset, assetInfo);
     }
 
     bool AssetCatalog::GetSourceInfoBySourceUUID(const AZ::Uuid& sourceUuid, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder)
     {
         AZ::Data::AssetId partialId(sourceUuid, 0);
-        AZStd::string relativePath;
+        SourceAssetReference sourceAsset;
 
-        if (GetSourceFileInfoFromAssetId(partialId, watchFolder, relativePath))
+        if (GetSourceFileInfoFromAssetId(partialId, sourceAsset))
         {
-            AZStd::string sourceFileFullPath;
-            AzFramework::StringFunc::Path::Join(watchFolder.c_str(), relativePath.c_str(), sourceFileFullPath);
+            watchFolder = sourceAsset.ScanfolderPath().c_str();
+
             assetInfo.m_assetId = partialId;
             assetInfo.m_assetType = AZ::Uuid::CreateNull(); // most source files don't have a type!
-            assetInfo.m_relativePath = relativePath;
-            assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceFileFullPath.c_str());
+            assetInfo.m_relativePath = sourceAsset.RelativePath().c_str();
+            assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceAsset.AbsolutePath().c_str());
 
             // if the type has registered with a typeid, then supply it here
             AZStd::lock_guard<AZStd::mutex> lock(m_sourceAssetTypesMutex);
@@ -1063,7 +1055,7 @@ namespace AssetProcessor
             // if it does, we know what type it is (if not, the above call to CreateNull ensures it is null).
             for (const auto& pair : m_sourceAssetTypeFilters)
             {
-                if (AZStd::wildcard_match(pair.first, relativePath))
+                if (AZStd::wildcard_match(pair.first, sourceAsset.RelativePath().c_str()))
                 {
                     assetInfo.m_assetType = pair.second;
                     break;
@@ -1412,7 +1404,7 @@ namespace AssetProcessor
 
     //////////////////////////////////////////////////////////////////////////
 
-    bool AssetCatalog::GetSourceFileInfoFromAssetId(const AZ::Data::AssetId &assetId, AZStd::string& watchFolder, AZStd::string& relativePath)
+    bool AssetCatalog::GetSourceFileInfoFromAssetId(const AZ::Data::AssetId &assetId, SourceAssetReference& sourceAsset)
     {
         // Check the database first
         {
@@ -1424,10 +1416,7 @@ namespace AssetProcessor
                 AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry scanEntry;
                 if (m_db->GetScanFolderByScanFolderID(entry.m_scanFolderPK, scanEntry))
                 {
-                    relativePath = entry.m_sourceName;
-
-                    watchFolder = scanEntry.m_scanFolder;
-
+                    sourceAsset = SourceAssetReference(scanEntry.m_scanFolder.c_str(), entry.m_sourceName.c_str());
 
                     return true;
                 }
@@ -1435,7 +1424,7 @@ namespace AssetProcessor
         }
 
         // Source file isn't in the database yet, see if its in the job queue
-        return GetQueuedAssetInfoById(assetId.m_guid, watchFolder, relativePath);
+        return GetQueuedAssetInfoById(assetId.m_guid, sourceAsset);
     }
 
     AZ::Data::AssetInfo AssetCatalog::GetProductAssetInfo(const char* platformName, const AZ::Data::AssetId& assetId)
@@ -1488,11 +1477,9 @@ namespace AssetProcessor
         return AssetInfo(); // not found!
     }
 
-    bool AssetCatalog::GetAssetInfoByIdOnly(const AZ::Data::AssetId& id, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, AZStd::string& rootFilePath)
+    bool AssetCatalog::GetAssetInfoByIdOnly(const AZ::Data::AssetId& id, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, SourceAssetReference& sourceAsset)
     {
-        AZStd::string relativePath;
-
-        if (GetSourceFileInfoFromAssetId(id, rootFilePath, relativePath))
+        if (GetSourceFileInfoFromAssetId(id, sourceAsset))
         {
             {
                 AZStd::lock_guard<AZStd::mutex> lock(m_sourceAssetTypesMutex);
@@ -1500,15 +1487,12 @@ namespace AssetProcessor
                 // Go through the list of source assets and see if this asset's file path matches any of the filters
                 for (const auto& pair : m_sourceAssetTypeFilters)
                 {
-                    if (AZStd::wildcard_match(pair.first, relativePath))
+                    if (AZStd::wildcard_match(pair.first, sourceAsset.AbsolutePath().c_str()))
                     {
-                        AZStd::string sourceFileFullPath;
-                        AzFramework::StringFunc::Path::Join(rootFilePath.c_str(), relativePath.c_str(), sourceFileFullPath);
-
                         assetInfo.m_assetId = id;
                         assetInfo.m_assetType = pair.second;
-                        assetInfo.m_relativePath = relativePath;
-                        assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceFileFullPath.c_str());
+                        assetInfo.m_relativePath = sourceAsset.RelativePath().c_str();
+                        assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceAsset.AbsolutePath().c_str());
 
                         return true;
                     }
@@ -1516,7 +1500,7 @@ namespace AssetProcessor
             }
 
             // If we get to here, we're going to assume it's a product type
-            rootFilePath.clear();
+            sourceAsset = {};
             assetInfo = GetProductAssetInfo(platformName.c_str(), id);
 
             return !assetInfo.m_relativePath.empty();
@@ -1526,7 +1510,7 @@ namespace AssetProcessor
         return false;
     }
 
-    bool AssetCatalog::GetQueuedAssetInfoById(const AZ::Uuid& guid, AZStd::string& watchFolder, AZStd::string& relativePath)
+    bool AssetCatalog::GetQueuedAssetInfoById(const AZ::Uuid& guid, SourceAssetReference& sourceAsset)
     {
         if (!guid.IsNull())
         {
@@ -1535,10 +1519,7 @@ namespace AssetProcessor
             auto foundSource = m_sourceUUIDToSourceNameMap.find(guid);
             if (foundSource != m_sourceUUIDToSourceNameMap.end())
             {
-                const SourceInfo& sourceInfo = foundSource->second;
-
-                watchFolder = sourceInfo.m_watchFolder.toStdString().c_str();
-                relativePath = sourceInfo.m_sourceName.toStdString().c_str();
+                sourceAsset = foundSource->second;
 
                 return true;
             }
@@ -1550,85 +1531,60 @@ namespace AssetProcessor
     }
 
 
-    bool AssetCatalog::GetQueuedAssetInfoByRelativeSourceName(const char* sourceName, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder)
+    bool AssetCatalog::GetQueuedAssetInfoByRelativeSourceName(const SourceAssetReference& sourceAsset, AZ::Data::AssetInfo& assetInfo)
     {
-        if (sourceName)
+        if (sourceAsset)
         {
-            AZStd::string sourceNameForMap = sourceName;
-            AZStd::to_lower(sourceNameForMap.begin(), sourceNameForMap.end());
             AZStd::lock_guard<AZStd::mutex> lock(m_sourceUUIDToSourceNameMapMutex);
 
-            auto foundSourceUUID = m_sourceNameToSourceUUIDMap.find(sourceNameForMap);
+            auto foundSourceUUID = m_sourceNameToSourceUUIDMap.find(sourceAsset);
             if (foundSourceUUID != m_sourceNameToSourceUUIDMap.end())
             {
-                auto foundSource = m_sourceUUIDToSourceNameMap.find(foundSourceUUID->second);
-                if (foundSource != m_sourceUUIDToSourceNameMap.end())
-                {
-                    const SourceInfo& sourceInfo = foundSource->second;
-
-                    watchFolder = sourceInfo.m_watchFolder.toStdString().c_str();
-
-                    AZStd::string sourceNameStr(sourceInfo.m_sourceName.toStdString().c_str());
-                    assetInfo.m_relativePath.swap(sourceNameStr);
-
-                    assetInfo.m_assetId = foundSource->first;
+                assetInfo.m_relativePath = sourceAsset.RelativePath().c_str();
+                assetInfo.m_assetId = foundSourceUUID->second;
+                assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceAsset.AbsolutePath().c_str());
+                assetInfo.m_assetType = AZ::Uuid::CreateNull(); // most source files don't have a type!
 
-                    AZStd::string sourceFileFullPath;
-                    AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), sourceFileFullPath);
-                    assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceFileFullPath.c_str());
-
-                    assetInfo.m_assetType = AZ::Uuid::CreateNull(); // most source files don't have a type!
-
-                    // Go through the list of source assets and see if this asset's file path matches any of the filters
-                    for (const auto& pair : m_sourceAssetTypeFilters)
+                // Go through the list of source assets and see if this asset's file path matches any of the filters
+                for (const auto& pair : m_sourceAssetTypeFilters)
+                {
+                    if (AZStd::wildcard_match(pair.first, assetInfo.m_relativePath))
                     {
-                        if (AZStd::wildcard_match(pair.first, assetInfo.m_relativePath))
-                        {
-                            assetInfo.m_assetType = pair.second;
-                            break;
-                        }
+                        assetInfo.m_assetType = pair.second;
+                        break;
                     }
-
-                    return true;
                 }
+
+                return true;
             }
         }
+
         assetInfo.m_assetId.SetInvalid();
 
         return false;
     }
 
-    bool AssetCatalog::GetUncachedSourceInfoFromDatabaseNameAndWatchFolder(const char* sourceDatabaseName, const char* watchFolder, AZ::Data::AssetInfo& assetInfo)
+    bool AssetCatalog::GetUncachedSourceInfoFromDatabaseNameAndWatchFolder(const SourceAssetReference& sourceAsset, AZ::Data::AssetInfo& assetInfo)
     {
-        AZ::Uuid sourceUUID = AssetUtilities::CreateSafeSourceUUIDFromName(sourceDatabaseName);
+        AZ::Uuid sourceUUID = AssetUtilities::CreateSafeSourceUUIDFromName(sourceAsset.RelativePath().c_str());
         if (sourceUUID.IsNull())
         {
             return false;
         }
 
         AZ::Data::AssetId sourceAssetId(sourceUUID, 0);
-        assetInfo.m_assetId = sourceAssetId;
 
-        // If relative path starts with the output prefix then remove it first
-        const ScanFolderInfo* scanFolderInfo = m_platformConfig->GetScanFolderForFile(watchFolder);
-        if (!scanFolderInfo)
-        {
-            return false;
-        }
-        QString databasePath = QString::fromUtf8(sourceDatabaseName);
-        assetInfo.m_relativePath = sourceDatabaseName;
+        assetInfo.m_assetId = sourceAssetId;
+        assetInfo.m_relativePath = sourceAsset.RelativePath().c_str();
+        assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceAsset.AbsolutePath().c_str());
+        assetInfo.m_assetType = AZ::Uuid::CreateNull();
 
-        AZStd::string absolutePath;
-        AzFramework::StringFunc::Path::Join(watchFolder, assetInfo.m_relativePath.c_str(), absolutePath);
-        assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(absolutePath.c_str());
         // Make sure the source file exists
-        if (assetInfo.m_sizeBytes == 0 && !AZ::IO::SystemFile::Exists(absolutePath.c_str()))
+        if (assetInfo.m_sizeBytes == 0 && !AZ::IO::SystemFile::Exists(sourceAsset.AbsolutePath().c_str()))
         {
             return false;
         }
 
-        assetInfo.m_assetType = AZ::Uuid::CreateNull();
-
         // Go through the list of source assets and see if this asset's file path matches any of the filters
         for (const auto& pair : m_sourceAssetTypeFilters)
         {

+ 8 - 14
Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h

@@ -72,7 +72,7 @@ namespace AssetProcessor
         virtual AzFramework::AssetSystem::GetUnresolvedDependencyCountsResponse HandleGetUnresolvedDependencyCountsRequest(MessageData<AzFramework::AssetSystem::GetUnresolvedDependencyCountsRequest> messageData);
         virtual void HandleSaveAssetCatalogRequest(MessageData<AzFramework::AssetSystem::SaveAssetCatalogRequest> messageData);
         void BuildRegistry();
-        void OnSourceQueued(AZ::Uuid sourceUuid, AZ::Uuid legacyUuid, QString rootPath, QString relativeFilePath);
+        void OnSourceQueued(AZ::Uuid sourceUuid, AZ::Uuid legacyUuid, const SourceAssetReference& sourceAsset);
         void OnSourceFinished(AZ::Uuid sourceUuid, AZ::Uuid legacyUuid);
         void AsyncAssetCatalogStatusRequest();
 
@@ -134,22 +134,22 @@ namespace AssetProcessor
         void ProcessGetFullSourcePathFromRelativeProductPathRequest(const AZStd::string& relPath, AZStd::string& fullSourcePath);
 
         //! Gets the source file info for an Asset by checking the DB first and the APM queue second
-        bool GetSourceFileInfoFromAssetId(const AZ::Data::AssetId &assetId, AZStd::string& watchFolder, AZStd::string& relativePath);
+        bool GetSourceFileInfoFromAssetId(const AZ::Data::AssetId &assetId, SourceAssetReference& sourceAsset);
 
         //! Gets the product AssetInfo based on a platform and assetId.  If you specify a null or empty platform the current or first available will be used.
         AZ::Data::AssetInfo GetProductAssetInfo(const char* platformName, const AZ::Data::AssetId& id);
 
         //! GetAssetInfo that tries to figure out if the asset is a product or source so it can return info about the product or source respectively
-        bool GetAssetInfoByIdOnly(const AZ::Data::AssetId& id, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, AZStd::string& rootFilePath);
+        bool GetAssetInfoByIdOnly(const AZ::Data::AssetId& id, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, SourceAssetReference& sourceAsset);
 
         //! Checks in the currently-in-queue assets list for info on an asset (by source Id)
-        bool GetQueuedAssetInfoById(const AZ::Uuid& guid, AZStd::string& watchFolder, AZStd::string& relativePath);
+        bool GetQueuedAssetInfoById(const AZ::Uuid& guid, SourceAssetReference& sourceAsset);
 
         //! Checks in the currently-in-queue assets list for info on an asset (by source name)
-        bool GetQueuedAssetInfoByRelativeSourceName(const char* sourceName, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder);
+        bool GetQueuedAssetInfoByRelativeSourceName(const SourceAssetReference& sourceAsset, AZ::Data::AssetInfo& assetInfo);
 
         //! Gets the source info for a source that is not in the DB or APM queue
-        bool GetUncachedSourceInfoFromDatabaseNameAndWatchFolder(const char* sourceDatabasePath, const char* watchFolder, AZ::Data::AssetInfo& assetInfo);
+        bool GetUncachedSourceInfoFromDatabaseNameAndWatchFolder(const SourceAssetReference& sourceAsset, AZ::Data::AssetInfo& assetInfo);
 
         bool ConnectToDatabase();
 
@@ -181,15 +181,9 @@ namespace AssetProcessor
         //! Used to protect access to the database connection, only one thread can use it at a time
         AZStd::mutex m_databaseMutex;
 
-        struct SourceInfo
-        {
-            QString m_watchFolder;
-            QString m_sourceName;
-        };
-
         AZStd::mutex m_sourceUUIDToSourceNameMapMutex;
-        using SourceUUIDToSourceNameMap = AZStd::unordered_map<AZ::Uuid, SourceInfo>;
-        using SourceNameToSourceUuidMap = AZStd::unordered_map<AZStd::string, AZ::Uuid>;
+        using SourceUUIDToSourceNameMap = AZStd::unordered_map<AZ::Uuid, SourceAssetReference>;
+        using SourceNameToSourceUuidMap = AZStd::unordered_map<SourceAssetReference, AZ::Uuid>;
 
         SourceUUIDToSourceNameMap m_sourceUUIDToSourceNameMap; // map of uuids to source file names for assets that are currently in the processing queue
         SourceNameToSourceUuidMap m_sourceNameToSourceUUIDMap;

+ 51 - 3
Code/Tools/AssetProcessor/native/AssetManager/SourceAssetReference.h

@@ -21,6 +21,16 @@ namespace AssetProcessor
     public:
         SourceAssetReference() = default;
 
+        explicit SourceAssetReference(const char* absolutePath)
+            : SourceAssetReference(AZ::IO::PathView(absolutePath))
+        {
+        }
+
+        explicit SourceAssetReference(QString absolutePath)
+            : SourceAssetReference(absolutePath.toUtf8().constData())
+        {
+        }
+
         explicit SourceAssetReference(AZ::IO::PathView absolutePath)
         {
             IPathConversion* pathConversion = AZ::Interface<IPathConversion>::Get();
@@ -41,10 +51,26 @@ namespace AssetProcessor
             Normalize();
         }
 
-        SourceAssetReference(AZ::IO::PathView scanfolderPath, AZ::IO::PathView pathRelativeToScanfolder)
+        SourceAssetReference(AZ::s64 scanFolderId, AZ::IO::PathView pathRelativeToScanFolder)
+            : SourceAssetReference(AZ::Interface<IPathConversion>::Get()->GetScanFolderById(scanFolderId)->ScanPath().toUtf8().constData(), pathRelativeToScanFolder)
+        {
+        }
+
+        SourceAssetReference(QString scanFolderPath, QString pathRelativeToScanFolder) : SourceAssetReference(AZ::IO::Path(scanFolderPath.toUtf8().constData()), AZ::IO::Path(pathRelativeToScanFolder.toUtf8().constData()))
         {
-            m_scanfolderPath = scanfolderPath;
-            m_relativePath = pathRelativeToScanfolder;
+        }
+
+        SourceAssetReference(const char* scanFolderPath, const char* pathRelativeToScanFolder) : SourceAssetReference(AZ::IO::Path(scanFolderPath), AZ::IO::Path(pathRelativeToScanFolder))
+        {
+        }
+
+        SourceAssetReference(AZ::IO::PathView scanFolderPath, AZ::IO::PathView pathRelativeToScanFolder)
+        {
+            AZ_Assert(!scanFolderPath.Native().empty(), "scanfolderPath is empty");
+            AZ_Assert(!pathRelativeToScanFolder.Native().empty(), "pathRelativeToScanFolder is empty");
+
+            m_scanfolderPath = scanFolderPath;
+            m_relativePath = pathRelativeToScanFolder;
             m_absolutePath = m_scanfolderPath / m_relativePath;
 
             IPathConversion* pathConversion = AZ::Interface<IPathConversion>::Get();
@@ -77,6 +103,11 @@ namespace AssetProcessor
             return m_absolutePath < other.m_absolutePath;
         }
 
+        explicit operator bool() const
+        {
+            return !m_absolutePath.empty();
+        }
+
         AZ::IO::Path AbsolutePath() const
         {
             return m_absolutePath;
@@ -111,3 +142,20 @@ namespace AssetProcessor
         AZ::s64 m_scanfolderId{};
     };
 }
+
+namespace AZStd
+{
+    template<>
+    struct hash<AssetProcessor::SourceAssetReference>
+    {
+        using argument_type = AssetProcessor::SourceAssetReference;
+        using result_type = size_t;
+
+        result_type operator()(const argument_type& obj) const
+        {
+            size_t h = 0;
+            hash_combine(h, obj.AbsolutePath());
+            return h;
+        }
+    };
+}

+ 80 - 70
Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp

@@ -100,7 +100,7 @@ namespace AssetProcessor
 
             if (m_stateData->GetSourceByJobID(jobEntry.m_jobID, sourceEntry))
             {
-                JobDesc jobDesc(sourceEntry.m_sourceName, jobEntry.m_jobKey, jobEntry.m_platform);
+                JobDesc jobDesc(SourceAssetReference(sourceEntry.m_scanFolderPK, sourceEntry.m_sourceName.c_str()), jobEntry.m_jobKey, jobEntry.m_platform);
                 JobIndentifier jobIdentifier(jobDesc, jobEntry.m_builderGuid);
 
                 m_jobDescToBuilderUuidMap[jobDesc].insert(jobEntry.m_builderGuid);
@@ -227,7 +227,7 @@ namespace AssetProcessor
         }
         else
         {
-            // TODO: Handle stat rename
+            // amzn-mike TODO: Handle stat rename
             QString statKey = QString("ProcessJob,%1,%2,%3,%4")
                                   .arg(jobEntry.m_sourceAssetReference.RelativePath().c_str())
                                   .arg(jobEntry.m_jobKey)
@@ -360,11 +360,12 @@ namespace AssetProcessor
 
     void AssetProcessorManager::ProcessGetAssetJobsInfoRequest(AssetJobsInfoRequest& request, AssetJobsInfoResponse& response)
     {
+        SourceAssetReference sourceAsset;
+
         if (request.m_assetId.IsValid())
         {
-            //If the assetId is valid than search both the database and the pending queue and update the searchTerm with the source name
-            SourceAssetReference searchResults;
-            if (!SearchSourceInfoBySourceUUID(request.m_assetId.m_guid, searchResults))
+            //If the assetId is valid then search both the database and the pending queue and update the searchTerm with the source name
+            if (!SearchSourceInfoBySourceUUID(request.m_assetId.m_guid, sourceAsset))
             {
                 // If still not found it means that this source asset is neither in the database nor in the queue for processing
                 AZ_TracePrintf(AssetProcessor::DebugChannel, "ProcessGetAssetJobsInfoRequest: AssetProcessor unable to find the requested source asset having uuid (%s).\n",
@@ -372,34 +373,36 @@ namespace AssetProcessor
                 response = AssetJobsInfoResponse(AzToolsFramework::AssetSystem::JobInfoContainer(), false);
                 return;
             }
-            request.m_searchTerm = searchResults.RelativePath().c_str();
         }
 
-        QString normalizedInputAssetPath;
-
         AzToolsFramework::AssetSystem::JobInfoContainer jobList;
         AssetProcessor::JobIdEscalationList jobIdEscalationList;
         if (!request.m_isSearchTermJobKey)
         {
-            normalizedInputAssetPath = AssetUtilities::NormalizeFilePath(request.m_searchTerm.c_str());
-
-            if (QFileInfo(normalizedInputAssetPath).isAbsolute())
+            if(sourceAsset.AbsolutePath().empty())
             {
-                QString scanFolderName;
-                QString relativePathToFile;
-                if (!m_platformConfig->ConvertToRelativePath(normalizedInputAssetPath, relativePathToFile, scanFolderName))
+                if (QFileInfo(request.m_searchTerm.c_str()).isAbsolute())
                 {
-                    response = AssetJobsInfoResponse(AzToolsFramework::AssetSystem::JobInfoContainer(), false);
-                    return;
+                    sourceAsset = SourceAssetReference(request.m_searchTerm.c_str());
                 }
+                else
+                {
+                    QString absolutePath = m_platformConfig->FindFirstMatchingFile(request.m_searchTerm.c_str());
 
-                normalizedInputAssetPath = relativePathToFile;
+                    if(absolutePath.isEmpty())
+                    {
+                        response = AssetJobsInfoResponse(AzToolsFramework::AssetSystem::JobInfoContainer(), false);
+                        return;
+                    }
+
+                    sourceAsset = SourceAssetReference(absolutePath.toUtf8().constData());
+                }
             }
 
             //any queued or in progress jobs will be in the map:
             for (const auto& entry : m_jobRunKeyToJobInfoMap)
             {
-                if (AzFramework::StringFunc::Equal(entry.second.m_sourceFile.c_str(), normalizedInputAssetPath.toUtf8().constData()))
+                if ((AZ::IO::Path(entry.second.m_watchFolder) / entry.second.m_sourceFile) == sourceAsset.AbsolutePath())
                 {
                     jobList.push_back(entry.second);
                     if (request.m_escalateJobs)
@@ -437,7 +440,7 @@ namespace AssetProcessor
         if (!request.m_isSearchTermJobKey)
         {
             //any succeeded or failed jobs will be in the table
-            m_stateData->GetJobInfoBySourceNameScanFolderId(normalizedInputAssetPath.toUtf8().constData(), jobListDataBase);
+            m_stateData->GetJobInfoBySourceNameScanFolderId(sourceAsset.RelativePath().c_str(), sourceAsset.ScanfolderId(), jobListDataBase);
         }
         else
         {
@@ -880,7 +883,7 @@ namespace AssetProcessor
                     // Check if this newly created intermediate will conflict with an existing source
                     if (!scanfolderIsIntermediateAssetsFolder)
                     {
-                        return ConflictResult{ ConflictResult::ConflictType::Intermediate, AZ::IO::Path(scanfolder.m_scanFolder) / source.m_sourceName };
+                        return ConflictResult{ ConflictResult::ConflictType::Intermediate, SourceAssetReference(scanfolder.m_scanFolder.c_str(), source.m_sourceName.c_str()) };
                     }
                 }
                 else
@@ -888,7 +891,7 @@ namespace AssetProcessor
                     // Check if the source for this product conflicts with an existing intermediate product (which is also a source)
                     if(scanfolderIsIntermediateAssetsFolder)
                     {
-                        return ConflictResult{ ConflictResult::ConflictType::Source, AZ::IO::Path(scanfolder.m_scanFolder) / source.m_sourceName };
+                        return ConflictResult{ ConflictResult::ConflictType::Source, SourceAssetReference(scanfolder.m_scanFolder.c_str(),source.m_sourceName.c_str()) };
                     }
                 }
             }
@@ -899,7 +902,7 @@ namespace AssetProcessor
             // Its possible we haven't recorded the source in the database yet, so check the filesystem to confirm there's no normal source we're overriding
             if (QString overriddenFile = m_platformConfig->FindFirstMatchingFile(searchSourcePath, true); !overriddenFile.isEmpty())
             {
-                return ConflictResult{ ConflictResult::ConflictType::Intermediate, AZ::IO::Path(overriddenFile.toUtf8().constData()) };
+                return ConflictResult{ ConflictResult::ConflictType::Intermediate, SourceAssetReference(overriddenFile) };
             }
         }
 
@@ -1002,7 +1005,7 @@ namespace AssetProcessor
                     AutoFailJob(errorMessage, errorMessage, itProcessedAsset);
                     productWrapper.DeleteFiles(false);
 
-                    FailTopLevelSourceForIntermediate(itProcessedAsset->m_entry.m_sourceAssetReference.RelativePath(), errorMessage);
+                    FailTopLevelSourceForIntermediate(itProcessedAsset->m_entry.m_sourceAssetReference, errorMessage);
                     remove = true;
                     break;
                 }
@@ -1018,24 +1021,24 @@ namespace AssetProcessor
                     {
                         auto errorMessage = AZStd::string::format(
                             "Asset (%s) has produced an intermediate asset file which conflicts with an existing source asset "
-                            "with the same relative path: " AZ_STRING_FORMAT ".  Please move/rename one of the files to fix the conflict.",
+                            "with the same relative path: %s.  Please move/rename one of the files to fix the conflict.",
                             itProcessedAsset->m_entry.m_sourceAssetReference.AbsolutePath().c_str(),
-                            AZ_STRING_ARG(result.m_conflictingFile.Native()));
+                            result.m_conflictingFile.AbsolutePath().c_str());
 
                         // Fail this job and delete its files, since it might actually be the top level source, and since we haven't recorded it yet, FailTopLevelSourceForIntermediate will do nothing in that case
                         AutoFailJob(errorMessage, errorMessage, itProcessedAsset);
                         productWrapper.DeleteFiles(false);
 
-                        FailTopLevelSourceForIntermediate(itProcessedAsset->m_entry.m_sourceAssetReference.RelativePath(), errorMessage);
+                        FailTopLevelSourceForIntermediate(itProcessedAsset->m_entry.m_sourceAssetReference, errorMessage);
                         remove = true;
                         break;
                     }
                     else
                     {
                         auto errorMessage = AZStd::string::format(
-                            "Asset (" AZ_STRING_FORMAT ") has produced an intermediate asset file which conflicts with an existing source asset "
+                            "Asset (%s) has produced an intermediate asset file which conflicts with an existing source asset "
                             "with the same relative path: %s.  Please move/rename one of the files to fix the conflict.",
-                            AZ_STRING_ARG(result.m_conflictingFile.Native()),
+                            result.m_conflictingFile.AbsolutePath().c_str(),
                             itProcessedAsset->m_entry.m_sourceAssetReference.AbsolutePath().c_str()
                         );
 
@@ -1187,7 +1190,7 @@ namespace AssetProcessor
                 continue;
             }
 
-            if (m_stateData->GetSourcesBySourceNameScanFolderId(processedAsset.m_entry.m_sourceAssetReference.AbsolutePath().c_str(), scanFolder->ScanFolderID(), sources))
+            if (m_stateData->GetSourcesBySourceNameScanFolderId(processedAsset.m_entry.m_sourceAssetReference.RelativePath().c_str(), scanFolder->ScanFolderID(), sources))
             {
                 AZ_Assert(sources.size() == 1, "Should have only found one source!!!");
                 source = AZStd::move(sources[0]);
@@ -1919,7 +1922,7 @@ namespace AssetProcessor
             {
                 if (IsInIntermediateAssetsFolder(sourceAsset.AbsolutePath()))
                 {
-                    auto topLevelSource = AssetUtilities::GetTopLevelSourceForProduct(source.m_sourceName.c_str(), m_stateData);
+                    auto topLevelSource = AssetUtilities::GetTopLevelSourceForIntermediateAsset(SourceAssetReference(source.m_scanFolderPK, source.m_sourceName.c_str()), m_stateData);
 
                     if (topLevelSource)
                     {
@@ -1999,7 +2002,7 @@ namespace AssetProcessor
         CheckMetaDataRealFiles(sourceAsset.AbsolutePath().c_str());
 
         // when a source is deleted, we also have to queue anything that depended on it, for re-processing:
-        QStringList dependents = GetSourceFilesWhichDependOnSourceFile(normalizedPath, {});
+        QStringList dependents = GetSourceFilesWhichDependOnSourceFile(sourceAsset.AbsolutePath().c_str(), {});
 
         for (QString dependent : dependents)
         {
@@ -2012,7 +2015,7 @@ namespace AssetProcessor
         if (!sources.empty())
         {
             SourceFileDependencyEntryContainer results;
-            m_stateData->GetDependsOnSourceBySource(sourceAsset.RelativePath().c_str(), SourceFileDependencyEntry::DEP_Any, results);
+            m_stateData->GetDependsOnSourceBySource(sources[0].m_sourceGuid, SourceFileDependencyEntry::DEP_Any, results);
             m_stateData->RemoveSourceFileDependencies(results);
         }
 
@@ -2228,7 +2231,7 @@ namespace AssetProcessor
 
         // First thing it checks is the computed fingerprint with its last known fingerprint in the database, if there is a mismatch than we need to process it
         AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer jobs; //should only find one when we specify builder, job key, platform
-        bool foundInDatabase = m_stateData->GetJobsBySourceName(jobDetails.m_jobEntry.m_sourceAssetReference.RelativePath().c_str(), jobs, jobDetails.m_jobEntry.m_builderGuid, jobDetails.m_jobEntry.m_jobKey, jobDetails.m_jobEntry.m_platformInfo.m_identifier.c_str());
+        bool foundInDatabase = m_stateData->GetJobsBySourceName(jobDetails.m_jobEntry.m_sourceAssetReference, jobs, jobDetails.m_jobEntry.m_builderGuid, jobDetails.m_jobEntry.m_jobKey, jobDetails.m_jobEntry.m_platformInfo.m_identifier.c_str());
 
         if (foundInDatabase && jobs[0].m_fingerprint == jobDetails.m_jobEntry.m_computedFingerprint)
         {
@@ -2294,7 +2297,7 @@ namespace AssetProcessor
 
             // Check whether another job emitted this job as a job dependency and if true, queue the dependent job source file also
             JobDesc jobDesc(
-                jobDetails.m_jobEntry.m_sourceAssetReference.RelativePath().c_str(),
+                jobDetails.m_jobEntry.m_sourceAssetReference,
                 jobDetails.m_jobEntry.m_jobKey.toUtf8().data(), jobDetails.m_jobEntry.m_platformInfo.m_identifier);
 
             shouldProcessAsset = true;
@@ -2540,14 +2543,17 @@ namespace AssetProcessor
     }
 
     void AssetProcessorManager::FailTopLevelSourceForIntermediate(
-        AZ::IO::PathView relativePathToIntermediateProduct, AZStd::string_view errorMessage)
+        const SourceAssetReference& intermediateAsset, AZStd::string_view errorMessage)
     {
         auto topLevelSourceForIntermediateConflict =
-            AssetUtilities::GetTopLevelSourceForProduct(relativePathToIntermediateProduct, m_stateData);
+            AssetUtilities::GetTopLevelSourceForIntermediateAsset(intermediateAsset, m_stateData);
 
         if (!topLevelSourceForIntermediateConflict)
         {
-            AZ_TracePrintf(AssetProcessor::DebugChannel, "FailTopLevelSourceForIntermediate: No top level source found for " AZ_STRING_FORMAT "\n", AZ_STRING_ARG(relativePathToIntermediateProduct.Native()));
+            AZ_TracePrintf(
+                AssetProcessor::DebugChannel,
+                "FailTopLevelSourceForIntermediate: No top level source found for %s\n",
+                intermediateAsset.AbsolutePath().c_str());
             return;
         }
 
@@ -2644,8 +2650,9 @@ namespace AssetProcessor
 
             // examination occurs here.
             // first, is it a source or is it a product in the cache folder?
-            SourceAssetReference sourceAssetReference(examineFile.m_fileName.toUtf8().constData());
-            QString normalizedPath = sourceAssetReference.AbsolutePath().c_str();
+
+
+            QString normalizedPath = examineFile.m_fileName.toUtf8().constData();
 
             AZ_TracePrintf(AssetProcessor::DebugChannel, "ProcessFilesToExamineQueue: %s delete: %s.\n", examineFile.m_fileName.toUtf8().constData(), examineFile.m_isDelete ? "true" : "false");
 
@@ -2729,6 +2736,8 @@ namespace AssetProcessor
             }
             else
             {
+                SourceAssetReference sourceAssetReference(examineFile.m_fileName.toUtf8().constData());
+
                 if (sourceAssetReference.AbsolutePath() == sourceAssetReference.ScanfolderPath())
                 {
                     // We found a scanfolder, record it
@@ -2904,7 +2913,7 @@ namespace AssetProcessor
                             overrider.toUtf8().constData(),
                             normalizedPath.toUtf8().constData());
 
-                        FailTopLevelSourceForIntermediate(sourceAssetReference.RelativePath(), errorMessage);
+                        FailTopLevelSourceForIntermediate(sourceAssetReference, errorMessage);
                     }
                 }
 
@@ -3553,7 +3562,7 @@ namespace AssetProcessor
 
         // Check the current builder jobs with the previous ones in the database:
         job.m_jobEntry.m_computedFingerprint = AssetUtilities::GenerateFingerprint(job);
-        JobIndentifier jobIndentifier(JobDesc(job.m_jobEntry.m_sourceAssetReference.RelativePath().c_str(), job.m_jobEntry.m_jobKey.toUtf8().data(), job.m_jobEntry.m_platformInfo.m_identifier), job.m_jobEntry.m_builderGuid);
+        JobIndentifier jobIndentifier(JobDesc(job.m_jobEntry.m_sourceAssetReference, job.m_jobEntry.m_jobKey.toUtf8().data(), job.m_jobEntry.m_platformInfo.m_identifier), job.m_jobEntry.m_builderGuid);
 
         {
             AZStd::lock_guard<AssetProcessor::ProcessingJobInfoBus::MutexType> lock(AssetProcessor::ProcessingJobInfoBus::GetOrCreateContext().m_contextMutex);
@@ -3628,10 +3637,10 @@ namespace AssetProcessor
 
             if(!sourceFileDependency.m_sourceFileDependencyUUID.IsNull())
             {
-                SourceInfo info;
-                if(SearchSourceInfoBySourceUUID(sourceFileDependency.m_sourceFileDependencyUUID, info))
+                SourceAssetReference sourceAsset;
+                if(SearchSourceInfoBySourceUUID(sourceFileDependency.m_sourceFileDependencyUUID, sourceAsset))
                 {
-                    databaseSourceName = info.m_sourceDatabaseName;
+                    databaseSourceName = sourceAsset.AbsolutePath().c_str();
                 }
                 else
                 {
@@ -3647,6 +3656,15 @@ namespace AssetProcessor
                     continue;
                 }
             }
+            else if(!AZ::IO::PathView(databaseSourceName.toUtf8().constData()).IsAbsolute())
+            {
+                QString absolutePath = m_platformConfig->FindFirstMatchingFile(databaseSourceName);
+
+                if (!absolutePath.isEmpty())
+                {
+                    databaseSourceName = absolutePath;
+                }
+            }
 
             sourceFileDependency.m_sourceFileDependencyPath = AssetUtilities::NormalizeFilePath(databaseSourceName).toUtf8().data();
 
@@ -3658,7 +3676,7 @@ namespace AssetProcessor
                 // after all the dependent jobs have completed at least once.
 
                 AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer jobs;
-                if (m_stateData->GetJobsBySourceName(sourceFileDependency.m_sourceFileDependencyPath.c_str(), jobs, AZ::Uuid::CreateNull(), jobDependencyInternal->m_jobDependency.m_jobKey.c_str(), jobDependencyInternal->m_jobDependency.m_platformIdentifier.c_str(), AzToolsFramework::AssetSystem::JobStatus::Completed))
+                if (m_stateData->GetJobsBySourceName(SourceAssetReference(sourceFileDependency.m_sourceFileDependencyPath.c_str()), jobs, AZ::Uuid::CreateNull(), jobDependencyInternal->m_jobDependency.m_jobKey.c_str(), jobDependencyInternal->m_jobDependency.m_platformIdentifier.c_str(), AzToolsFramework::AssetSystem::JobStatus::Completed))
                 {
                     job.m_jobDependencyList.erase(jobDependencyInternal);
                     continue;
@@ -3672,7 +3690,7 @@ namespace AssetProcessor
             {
                 // Listing all the builderUuids that have the same (sourcefile,platform,jobKey) for this job dependency
                 JobDesc jobDesc(
-                    sourceFileDependency.m_sourceFileDependencyPath,
+                    SourceAssetReference(sourceFileDependency.m_sourceFileDependencyPath.c_str()),
                     jobDependencyInternal->m_jobDependency.m_jobKey, jobDependencyInternal->m_jobDependency.m_platformIdentifier);
                 auto buildersFound = m_jobDescToBuilderUuidMap.find(jobDesc);
 
@@ -3739,7 +3757,7 @@ namespace AssetProcessor
             // If an entry exists, it implies than we have already send the job over to the RCController
             for (auto builderIter = jobDependencyInternal.m_builderUuidList.begin(); builderIter != jobDependencyInternal.m_builderUuidList.end(); ++builderIter)
             {
-                JobIndentifier jobIdentifier(JobDesc(jobDependencyInternal.m_jobDependency.m_sourceFile.m_sourceFileDependencyPath,
+                JobIndentifier jobIdentifier(JobDesc(SourceAssetReference(jobDependencyInternal.m_jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str()),
                     jobDependencyInternal.m_jobDependency.m_jobKey, jobDependencyInternal.m_jobDependency.m_platformIdentifier),
                     *builderIter);
 
@@ -3885,6 +3903,7 @@ namespace AssetProcessor
                     // if we succeeded, we can erase any jobs that had failed createjobs last time for this builder:
                     AzToolsFramework::AssetSystem::JobInfo jobInfo;
                     jobInfo.m_sourceFile = sourceAsset.RelativePath().Native();
+                    jobInfo.m_watchFolder = sourceAsset.ScanfolderPath().Native();
                     jobInfo.m_platform = "all";
                     jobInfo.m_jobKey = AZStd::string::format("CreateJobs_%s", builderInfo.m_busId.ToString<AZStd::string>().c_str());
                     Q_EMIT JobRemoved(jobInfo);
@@ -3950,8 +3969,8 @@ namespace AssetProcessor
                             ++numJobDependencies;
                         }
 
-                        // note that until analysis completes, the jobId is not set and neither is the destination pat
-                        JobDesc jobDesc(newJob.m_jobEntry.m_sourceAssetReference.RelativePath().c_str(), newJob.m_jobEntry.m_jobKey.toUtf8().data(), newJob.m_jobEntry.m_platformInfo.m_identifier);
+                        // note that until analysis completes, the jobId is not set and neither is the destination path
+                        JobDesc jobDesc(newJob.m_jobEntry.m_sourceAssetReference, newJob.m_jobEntry.m_jobKey.toUtf8().data(), newJob.m_jobEntry.m_platformInfo.m_identifier);
                         m_jobDescToBuilderUuidMap[jobDesc].insert(builderInfo.m_busId);
 
                         // until this job is analyzed, assume its fingerprint is not computed.
@@ -4011,7 +4030,7 @@ namespace AssetProcessor
         }
         else if (!sourceDependency.m_sourceFileDependencyPath.empty())
         {
-            // instead of a UUID, a path has been provided, prepare and use that.  We need to turn it into a database path
+            // instead of a UUID, a path has been provided, prepare and use that.
             QString encodedFileData = QString::fromUtf8(sourceDependency.m_sourceFileDependencyPath.c_str());
             encodedFileData = AssetUtilities::NormalizeFilePath(encodedFileData);
 
@@ -4117,22 +4136,14 @@ namespace AssetProcessor
                 {
                     AZ_Warning(AssetProcessor::ConsoleChannel, false, "'%s' does not appear to be in any input folder.  Use relative paths instead.", sourceDependency.m_sourceFileDependencyPath.c_str());
                 }
-            }
-            else
-            {
-                // its a relative path.  We want a database source name if possible, but we'll settle for relative path if we have to:
-                QString absolutePath = m_platformConfig->FindFirstMatchingFile(encodedFileData);
-                if (absolutePath.isEmpty())
-                {
-                    resultDatabaseSourceName = encodedFileData;
-                }
                 else
                 {
-                    // we have found the actual file, so we know what the scan folder and thus database path will be.
-                    QString scanFolderName;
-                    m_platformConfig->ConvertToRelativePath(absolutePath, resultDatabaseSourceName, scanFolderName);
+                    resultDatabaseSourceName = encodedFileData;
                 }
             }
+            else
+            {
+            }
         }
         else
         {
@@ -4619,12 +4630,11 @@ namespace AssetProcessor
                 }
             }
 
-            SourceInfo info;
-            if (SearchSourceInfoBySourceUUID(entry.m_sourceGuid, info))
+            SourceAssetReference sourceAsset;
+            if (SearchSourceInfoBySourceUUID(entry.m_sourceGuid, sourceAsset))
             {
-                auto absolutePath = QDir(info.m_watchFolder).absoluteFilePath(info.m_sourceRelativeToWatchFolder);
                 // add it to the queue for analysis:
-                absoluteSourceFilePathQueue.insert(absolutePath);
+                absoluteSourceFilePathQueue.insert(sourceAsset.AbsolutePath().c_str());
             }
 
             return true;
@@ -5141,14 +5151,14 @@ namespace AssetProcessor
 
             if (dep.IsUuid())
             {
-                SourceInfo info;
+                SourceAssetReference sourceAsset;
 
-                if (!SearchSourceInfoBySourceUUID(dep.GetUuid(), info))
+                if (!SearchSourceInfoBySourceUUID(dep.GetUuid(), sourceAsset))
                 {
                     continue;
                 }
 
-                absolutePath = QDir(info.m_watchFolder).absoluteFilePath(info.m_sourceRelativeToWatchFolder);
+                absolutePath = sourceAsset.AbsolutePath().c_str();
             }
             else
             {
@@ -5416,7 +5426,7 @@ namespace AssetProcessor
             for (const auto& source : sources)
             {
                 AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer jobs; // should only find one when we specify builder, job key, platform
-                m_stateData->GetJobsBySourceName(source.RelativePath().c_str(), jobs);
+                m_stateData->GetJobsBySourceName(source, jobs);
                 for (auto& job : jobs)
                 {
                     job.m_fingerprint = 0;

+ 4 - 4
Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h

@@ -337,7 +337,7 @@ namespace AssetProcessor
         void CheckDeletedCacheFolder(QString normalizedPath);
         void CheckDeletedSourceFolder(QString normalizedPath, QString relativePath, const ScanFolderInfo* scanFolderInfo);
         void CheckCreatedSourceFolder(QString normalizedPath);
-        void FailTopLevelSourceForIntermediate(AZ::IO::PathView relativePathToIntermediateProduct, AZStd::string_view errorMessage);
+        void FailTopLevelSourceForIntermediate(const SourceAssetReference& intermediateAsset, AZStd::string_view errorMessage);
         void CheckMetaDataRealFiles(QString relativePath);
         bool DeleteProducts(const AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer& products);
         void DispatchFileChange();
@@ -385,8 +385,8 @@ namespace AssetProcessor
 
             ConflictType m_type;
 
-            //! Full path to the file that has caused the conflict.  If ConflictType == Intermediate, this is the path to the source, if ConflictType == Source, this is the intermediate
-            AZ::IO::Path m_conflictingFile;
+            //! The file that has caused the conflict.  If ConflictType == Intermediate, this is the source, if ConflictType == Source, this is the intermediate
+            SourceAssetReference m_conflictingFile;
         };
 
         //! Search the database and the the source dependency maps for the the sourceUuid. if found returns the cached info
@@ -490,7 +490,7 @@ namespace AssetProcessor
         AZStd::multimap<AZStd::string, AZ::u64> m_jobKeyToJobRunKeyMap;
 
         using SourceUUIDToSourceInfoMap = AZStd::unordered_map<AZ::Uuid, SourceAssetReference>;
-        SourceUUIDToSourceInfoMap m_sourceUUIDToSourceInfoMap; // contains UUID -> SourceInfo, which includes database name and relative to watch folder:
+        SourceUUIDToSourceInfoMap m_sourceUUIDToSourceInfoMap; // contains UUID -> SourceAssetReference, which includes database name and relative to watch folder:
         AZStd::mutex m_sourceUUIDToSourceInfoMapMutex;
 
         QString m_normalizedCacheRootPath;

+ 5 - 5
Code/Tools/AssetProcessor/native/assetprocessor.h

@@ -249,19 +249,19 @@ namespace AssetProcessor
     //! because of job dependency declared on them by other jobs
     struct JobDesc
     {
-        AZStd::string m_databaseSourceName;
+        SourceAssetReference m_sourceAsset;
         AZStd::string m_jobKey;
         AZStd::string m_platformIdentifier;
 
         bool operator==(const JobDesc& rhs) const
         {
-            return AzFramework::StringFunc::Equal(m_databaseSourceName.c_str(), rhs.m_databaseSourceName.c_str())
+            return m_sourceAsset == rhs.m_sourceAsset
                 && m_platformIdentifier == rhs.m_platformIdentifier
                 && m_jobKey == rhs.m_jobKey;
         }
 
-        JobDesc(const AZStd::string& databaseSourceName, const AZStd::string& jobKey, const AZStd::string& platformIdentifier)
-            : m_databaseSourceName(databaseSourceName)
+        JobDesc(SourceAssetReference sourceAsset, const AZStd::string& jobKey, const AZStd::string& platformIdentifier)
+            : m_sourceAsset(AZStd::move(sourceAsset))
             , m_jobKey(jobKey)
             , m_platformIdentifier(platformIdentifier)
         {
@@ -269,7 +269,7 @@ namespace AssetProcessor
 
         AZStd::string ToString() const
         {
-            AZStd::string lowerSourceName = m_databaseSourceName;
+            AZStd::string lowerSourceName = m_sourceAsset.AbsolutePath().Native();
             AZStd::to_lower(lowerSourceName.begin(), lowerSourceName.end());
 
             return AZStd::string::format("%s %s %s", lowerSourceName.c_str(), m_platformIdentifier.c_str(), m_jobKey.c_str());

+ 1 - 0
Code/Tools/AssetProcessor/native/resourcecompiler/JobsModel.cpp

@@ -368,6 +368,7 @@ namespace AssetProcessor
                     //elementId.SetJobDescriptor(tokens[2].c_str());
                     //elementId.SetPlatform(tokens[3].c_str());
                     //historicalStats[elementId] = entry.m_statValue;
+                    AZ_UNUSED(historicalStats);
                 }
                 else
                 {

+ 8 - 1
Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.cpp

@@ -61,7 +61,14 @@ namespace AssetProcessor
                     if (jobDepedencyInternal.m_jobDependency.m_type == AssetBuilderSDK::JobDependencyType::Order || jobDepedencyInternal.m_jobDependency.m_type == AssetBuilderSDK::JobDependencyType::OrderOnce)
                     {
                         const AssetBuilderSDK::JobDependency& jobDependency = jobDepedencyInternal.m_jobDependency;
-                        QueueElementID elementId(jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str(), jobDependency.m_platformIdentifier.c_str(), jobDependency.m_jobKey.c_str());
+                        AZ_Assert(
+                            AZ::IO::PathView(jobDependency.m_sourceFile.m_sourceFileDependencyPath).IsAbsolute(),
+                            "Dependency path %s is not an absolute path",
+                            jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str());
+                        QueueElementID elementId(
+                            SourceAssetReference(jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str()),
+                            jobDependency.m_platformIdentifier.c_str(),
+                            jobDependency.m_jobKey.c_str());
 
                         if (m_sourceModel->isInFlight(elementId) || m_sourceModel->isInQueue(elementId))
                         {

+ 2 - 0
Code/Tools/AssetProcessor/native/utilities/IPathConversion.h

@@ -26,5 +26,7 @@ namespace AssetProcessor
 
         //! given a full file name (assumed already fed through the normalization funciton), return the first matching scan folder
         virtual const AssetProcessor::ScanFolderInfo* GetScanFolderForFile(const QString& fullFileName) const = 0;
+
+        virtual const AssetProcessor::ScanFolderInfo* GetScanFolderById(AZ::s64 id) const = 0;
     };
 }

+ 15 - 2
Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp

@@ -621,7 +621,7 @@ namespace AssetProcessor
 
         return AZ::SettingsRegistryInterface::VisitResponse::Skip;
     }
- 
+
     const char AssetConfigPlatformDir[] = "AssetProcessorConfig/";
     const char AssetProcessorPlatformConfigFileName[] = "AssetProcessorPlatformConfig.ini";
 
@@ -1031,7 +1031,7 @@ namespace AssetProcessor
     bool PlatformConfiguration::ConvertToJson(const RecognizerContainer& recognizerContainer, AZStd::string& jsonText)
     {
         AZStd::unordered_map<AZStd::string, AssetCacheServerMatcher> assetCacheServerMatcherMap;
-        
+
         for (const auto& recognizer : recognizerContainer)
         {
             AssetCacheServerMatcher matcher;
@@ -1443,6 +1443,19 @@ namespace AssetProcessor
         return m_scanFolders[index];
     }
 
+    const AssetProcessor::ScanFolderInfo* PlatformConfiguration::GetScanFolderById(AZ::s64 id) const
+    {
+        auto* result = AZStd::find_if(
+            m_scanFolders.begin(),
+            m_scanFolders.end(),
+            [id](const ScanFolderInfo& scanFolder)
+            {
+                return scanFolder.ScanFolderID() == id;
+            });
+
+        return result != m_scanFolders.end() ? result : nullptr;
+    }
+
     void PlatformConfiguration::AddScanFolder(const AssetProcessor::ScanFolderInfo& source, bool isUnitTesting)
     {
         if (isUnitTesting)

+ 2 - 0
Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.h

@@ -197,6 +197,8 @@ namespace AssetProcessor
         //! Retrieve the scan folder at a given index.
         const AssetProcessor::ScanFolderInfo& GetScanFolderAt(int index) const;
 
+        const AssetProcessor::ScanFolderInfo* GetScanFolderById(AZ::s64 id) const override;
+
         //!  Manually add a scan folder.  Also used for testing.
         void AddScanFolder(const AssetProcessor::ScanFolderInfo& source, bool isUnitTesting = false);
 

+ 11 - 6
Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp

@@ -1039,7 +1039,7 @@ namespace AssetUtilities
                 // we do not want to include the fingerprint of dependent jobs if the job dependency type is OrderOnce.
                 continue;
             }
-            AssetProcessor::JobDesc jobDesc(jobDependencyInternal.m_jobDependency.m_sourceFile.m_sourceFileDependencyPath,
+            AssetProcessor::JobDesc jobDesc(AssetProcessor::SourceAssetReference(jobDependencyInternal.m_jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str()),
                 jobDependencyInternal.m_jobDependency.m_jobKey, jobDependencyInternal.m_jobDependency.m_platformIdentifier);
 
             for (auto builderIter = jobDependencyInternal.m_builderUuidList.begin(); builderIter != jobDependencyInternal.m_builderUuidList.end(); ++builderIter)
@@ -1399,7 +1399,7 @@ namespace AssetUtilities
         return (platformPrefix / relativePath).LexicallyNormal().StringAsPosix();
     }
 
-    AZStd::optional<AzToolsFramework::AssetDatabase::SourceDatabaseEntry> GetTopLevelSourceForProduct(
+    AZStd::optional<AzToolsFramework::AssetDatabase::SourceDatabaseEntry> GetTopLevelSourceForIntermediateAsset(
         const AssetProcessor::SourceAssetReference& sourceAsset, AZStd::shared_ptr<AssetProcessor::AssetDatabaseConnection> db)
     {
         AzToolsFramework::AssetDatabase::SourceDatabaseEntryContainer sources;
@@ -1432,7 +1432,7 @@ namespace AssetUtilities
     {
         AZStd::vector<AssetProcessor::SourceAssetReference> sources;
 
-        auto topLevelSource = GetTopLevelSourceForProduct(sourceAsset, db);
+        auto topLevelSource = GetTopLevelSourceForIntermediateAsset(sourceAsset, db);
 
         if (!topLevelSource)
         {
@@ -1440,19 +1440,24 @@ namespace AssetUtilities
             db->GetSourcesBySourceNameScanFolderId(sourceAsset.RelativePath().c_str(), sourceAsset.ScanfolderId(), source);
 
             AZ_Assert(
-                source.size() == 1,
+                source.size() <= 1,
                 "Should find exactly 1 source for the given path (%s) and scanfolder (%d).  Found %d",
                 sourceAsset.RelativePath().c_str(),
                 sourceAsset.ScanfolderId(),
                 source.size());
 
+            if(source.empty())
+            {
+                return {};
+            }
+
             topLevelSource = source[0];
         }
 
         AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry scanFolder;
         db->GetScanFolderByScanFolderID(topLevelSource->m_scanFolderPK, scanFolder);
 
-        sources.emplace_back(scanFolder.m_scanFolder, topLevelSource->m_sourceName);
+        sources.emplace_back(scanFolder.m_scanFolder.c_str(), topLevelSource->m_sourceName.c_str());
 
         AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer products;
         db->GetProductsBySourceID(topLevelSource->m_sourceID, products);
@@ -1465,7 +1470,7 @@ namespace AssetUtilities
             if ((static_cast<AssetBuilderSDK::ProductOutputFlags>(product.m_flags.to_ullong()) & AssetBuilderSDK::ProductOutputFlags::IntermediateAsset) == AssetBuilderSDK::ProductOutputFlags::IntermediateAsset)
             {
                 auto productSourceName = StripAssetPlatformNoCopy(product.m_productName);
-                sources.emplace_back(productSourceName);
+                sources.emplace_back(scanFolder.m_scanFolder.c_str(), productSourceName);
 
                 // Note: This call is intentionally re-using the products array.  The new results will be appended to the end (via push_back).
                 // The array will not be cleared.  We're essentially using products as a queue

+ 1 - 1
Code/Tools/AssetProcessor/native/utilities/assetUtils.h

@@ -265,7 +265,7 @@ namespace AssetUtilities
     AZStd::string GetIntermediateAssetDatabaseName(AZ::IO::PathView relativePath);
 
     //! Finds the top level source that produced an intermediate product.  If the source is not yet recorded in the database or has no top level source, this will return nothing
-    AZStd::optional<AzToolsFramework::AssetDatabase::SourceDatabaseEntry> GetTopLevelSourceForProduct(AZ::IO::PathView relativePath, AZStd::shared_ptr<AssetProcessor::AssetDatabaseConnection> db);
+    AZStd::optional<AzToolsFramework::AssetDatabase::SourceDatabaseEntry> GetTopLevelSourceForIntermediateAsset(const AssetProcessor::SourceAssetReference& sourceAsset, AZStd::shared_ptr<AssetProcessor::AssetDatabaseConnection> db);
 
     //! Finds all the sources (up and down) in an intermediate output chain
     AZStd::vector<AssetProcessor::SourceAssetReference> GetAllIntermediateSources(