Add new API to convert absolute source paths to relative paths. (#930)
There are already APIs for getting a relative product path from an absolute source path, or getting a relative source path for an *existing* source file, but there were no APIs for getting a relative source path for a *new* source file. Prefabs will need this ability to be able to correctly generate a relative source path inside the prefab file before the file has been saved. The logic for relative source paths is a little bit tricky because the paths are relative to the watch folders, and the watch folders can be nested, with different priorities to explain which should take precedence. The input paths can also include specifiers like "." and "..", which need to be reconciled before creating the final correct relative path. The included unit tests test all of the tricky edge cases that I was able to identify.
This commit is contained in:
@@ -308,6 +308,56 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
GenerateRelativeSourcePathRequest::GenerateRelativeSourcePathRequest(const AZ::OSString& sourcePath)
|
||||
{
|
||||
AZ_Assert(!sourcePath.empty(), "GenerateRelativeSourcePathRequest: asset path is empty");
|
||||
m_sourcePath = sourcePath;
|
||||
}
|
||||
|
||||
unsigned int GenerateRelativeSourcePathRequest::GetMessageType() const
|
||||
{
|
||||
return MessageType;
|
||||
}
|
||||
|
||||
void GenerateRelativeSourcePathRequest::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<GenerateRelativeSourcePathRequest, BaseAssetProcessorMessage>()
|
||||
->Version(1)
|
||||
->Field("SourcePath", &GenerateRelativeSourcePathRequest::m_sourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
GenerateRelativeSourcePathResponse::GenerateRelativeSourcePathResponse(
|
||||
bool resolved, const AZ::OSString& relativeSourcePath, const AZ::OSString& rootFolder)
|
||||
{
|
||||
m_relativeSourcePath = relativeSourcePath;
|
||||
m_resolved = resolved;
|
||||
m_rootFolder = rootFolder;
|
||||
}
|
||||
|
||||
unsigned int GenerateRelativeSourcePathResponse::GetMessageType() const
|
||||
{
|
||||
return GenerateRelativeSourcePathRequest::MessageType;
|
||||
}
|
||||
|
||||
void GenerateRelativeSourcePathResponse::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<GenerateRelativeSourcePathResponse, BaseAssetProcessorMessage>()
|
||||
->Version(1)
|
||||
->Field("RelativeSourcePath", &GenerateRelativeSourcePathResponse::m_relativeSourcePath)
|
||||
->Field("RootFolder", &GenerateRelativeSourcePathResponse::m_rootFolder)
|
||||
->Field("Resolved", &GenerateRelativeSourcePathResponse::m_resolved);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
GetFullSourcePathFromRelativeProductPathRequest::GetFullSourcePathFromRelativeProductPathRequest(const AZ::OSString& relativeProductPath)
|
||||
{
|
||||
|
||||
@@ -288,6 +288,45 @@ namespace AzFramework
|
||||
bool m_resolved;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GenerateRelativeSourcePathRequest : public BaseAssetProcessorMessage
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(GenerateRelativeSourcePathRequest, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(GenerateRelativeSourcePathRequest, "{B3865033-F5A3-4749-8147-7B1AB04D5F6D}",
|
||||
BaseAssetProcessorMessage);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// For people that are debugging the network messages and just see MessageType as a value,
|
||||
// the CRC value below is 739777771 (0x2C181CEB)
|
||||
static constexpr unsigned int MessageType =
|
||||
AZ_CRC_CE("AssetSystem::GenerateRelativeSourcePathRequest");
|
||||
|
||||
GenerateRelativeSourcePathRequest() = default;
|
||||
GenerateRelativeSourcePathRequest(const AZ::OSString& sourcePath);
|
||||
unsigned int GetMessageType() const override;
|
||||
|
||||
AZ::OSString m_sourcePath;
|
||||
};
|
||||
|
||||
class GenerateRelativeSourcePathResponse : public BaseAssetProcessorMessage
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(GenerateRelativeSourcePathResponse, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(GenerateRelativeSourcePathResponse, "{938D33DB-C8F6-4FA4-BC81-2F139A9BE1D7}",
|
||||
BaseAssetProcessorMessage);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
GenerateRelativeSourcePathResponse() = default;
|
||||
GenerateRelativeSourcePathResponse(
|
||||
bool resolved, const AZ::OSString& relativeSourcePath, const AZ::OSString& rootFolder);
|
||||
unsigned int GetMessageType() const override;
|
||||
|
||||
AZ::OSString m_relativeSourcePath;
|
||||
AZ::OSString m_rootFolder; ///< This is the folder it was found in (the watched/scanned folder, such as gems /assets/ folder)
|
||||
bool m_resolved;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GetFullSourcePathFromRelativeProductPathRequest
|
||||
: public BaseAssetProcessorMessage
|
||||
|
||||
@@ -202,6 +202,7 @@ namespace AzFramework
|
||||
// Requests
|
||||
GetUnresolvedDependencyCountsRequest::Reflect(context);
|
||||
GetRelativeProductPathFromFullSourceOrProductPathRequest::Reflect(context);
|
||||
GenerateRelativeSourcePathRequest::Reflect(context);
|
||||
GetFullSourcePathFromRelativeProductPathRequest::Reflect(context);
|
||||
SourceAssetInfoRequest::Reflect(context);
|
||||
AssetInfoRequest::Reflect(context);
|
||||
@@ -234,6 +235,7 @@ namespace AzFramework
|
||||
// Responses
|
||||
GetUnresolvedDependencyCountsResponse::Reflect(context);
|
||||
GetRelativeProductPathFromFullSourceOrProductPathResponse::Reflect(context);
|
||||
GenerateRelativeSourcePathResponse::Reflect(context);
|
||||
GetFullSourcePathFromRelativeProductPathResponse::Reflect(context);
|
||||
SourceAssetInfoResponse::Reflect(context);
|
||||
AssetInfoResponse::Reflect(context);
|
||||
|
||||
@@ -60,10 +60,20 @@ namespace AzToolsFramework
|
||||
//! and is generally checked into source control.
|
||||
virtual const char* GetAbsoluteDevRootFolderPath() = 0;
|
||||
|
||||
/// Convert a full source path like "c:\\dev\gamename\\blah\\test.tga" into a relative product path.
|
||||
/// Convert a full source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative product path.
|
||||
/// asset paths never mention their alias and are relative to the asset cache root
|
||||
virtual bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) = 0;
|
||||
|
||||
/** Convert a source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative source path, like "blah/test.tga".
|
||||
* If no valid relative path could be created, the input source path will be returned in relativePath.
|
||||
* @param sourcePath partial or full path to a source file. (The file doesn't need to exist)
|
||||
* @param relativePath the output relative path for the source file, if a valid one could be created
|
||||
* @param rootFilePath the root path that relativePath is relative to
|
||||
* @return true if a valid relative path was created, false if it wasn't
|
||||
*/
|
||||
virtual bool GenerateRelativeSourcePath(
|
||||
const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& rootFilePath) = 0;
|
||||
|
||||
/// Convert a relative asset path like "blah/test.tga" to a full source path path.
|
||||
/// Once the asset processor has finished building, this function is capable of handling even when the extension changes
|
||||
/// or when the source is in a different folder or in a different location (such as inside gems)
|
||||
|
||||
@@ -265,6 +265,30 @@ namespace AzToolsFramework
|
||||
return response.m_resolved;
|
||||
}
|
||||
|
||||
bool AssetSystemComponent::GenerateRelativeSourcePath(
|
||||
const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& rootFilePath)
|
||||
{
|
||||
AzFramework::SocketConnection* engineConnection = AzFramework::SocketConnection::GetInstance();
|
||||
if (!engineConnection || !engineConnection->IsConnected())
|
||||
{
|
||||
relativePath = sourcePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
AzFramework::AssetSystem::GenerateRelativeSourcePathRequest request(sourcePath);
|
||||
AzFramework::AssetSystem::GenerateRelativeSourcePathResponse response;
|
||||
if (!SendRequest(request, response))
|
||||
{
|
||||
AZ_Error("Editor", false, "Failed to send GenerateRelativeSourcePath request for %s", sourcePath.c_str());
|
||||
relativePath = sourcePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
relativePath = response.m_relativeSourcePath;
|
||||
rootFilePath = response.m_rootFolder;
|
||||
return response.m_resolved;
|
||||
}
|
||||
|
||||
bool AssetSystemComponent::GetFullSourcePathFromRelativeProductPath(const AZStd::string& relPath, AZStd::string& fullPath)
|
||||
{
|
||||
auto foundIt = m_assetSourceRelativePathToFullPathCache.find(relPath);
|
||||
|
||||
@@ -63,6 +63,8 @@ namespace AzToolsFramework
|
||||
const char* GetAbsoluteDevGameFolderPath() override;
|
||||
const char* GetAbsoluteDevRootFolderPath() override;
|
||||
bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& outputPath) override;
|
||||
bool GenerateRelativeSourcePath(
|
||||
const AZStd::string& sourcePath, AZStd::string& outputPath, AZStd::string& watchFolder) override;
|
||||
bool GetFullSourcePathFromRelativeProductPath(const AZStd::string& relPath, AZStd::string& fullPath) override;
|
||||
bool GetAssetInfoById(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, AZStd::string& rootFilePath) override;
|
||||
bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override;
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace UnitTests
|
||||
MOCK_METHOD0(GetAbsoluteDevGameFolderPath, const char* ());
|
||||
MOCK_METHOD0(GetAbsoluteDevRootFolderPath, const char* ());
|
||||
MOCK_METHOD2(GetRelativeProductPathFromFullSourceOrProductPath, bool(const AZStd::string& fullPath, AZStd::string& relativeProductPath));
|
||||
MOCK_METHOD3(GenerateRelativeSourcePath,
|
||||
bool(const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder));
|
||||
MOCK_METHOD2(GetFullSourcePathFromRelativeProductPath, bool(const AZStd::string& relPath, AZStd::string& fullSourcePath));
|
||||
MOCK_METHOD5(GetAssetInfoById, bool(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType, const AZStd::string& platformName, AZ::Data::AssetInfo& assetInfo, AZStd::string& rootFilePath));
|
||||
MOCK_METHOD3(GetSourceInfoBySourcePath, bool(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder));
|
||||
|
||||
+3
@@ -149,6 +149,9 @@ namespace UnitTest
|
||||
const char* GetAbsoluteDevGameFolderPath() override { return ""; }
|
||||
const char* GetAbsoluteDevRootFolderPath() override { return ""; }
|
||||
bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) override { return false; }
|
||||
bool GenerateRelativeSourcePath(
|
||||
[[maybe_unused]] const AZStd::string& sourcePath, [[maybe_unused]] AZStd::string& relativePath,
|
||||
[[maybe_unused]] AZStd::string& watchFolder) override { return false; }
|
||||
bool GetFullSourcePathFromRelativeProductPath([[maybe_unused]] const AZStd::string& relPath, [[maybe_unused]] AZStd::string& fullSourcePath) override { return false; }
|
||||
bool GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& assetId, [[maybe_unused]] const AZ::Data::AssetType& assetType, [[maybe_unused]] const AZStd::string& platformName, [[maybe_unused]] AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] AZStd::string& rootFilePath) override { return false; }
|
||||
bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override;
|
||||
|
||||
Reference in New Issue
Block a user