Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
#Ignore these directories
SDKs
@@ -0,0 +1,29 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/source/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AWSNativeSDKInit STATIC
NAMESPACE AZ
FILES_CMAKE
aws_native_sdk_init_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
include
PRIVATE
${pal_dir}
BUILD_DEPENDENCIES
PRIVATE
3rdParty::AWSNativeSDK::Core
AZ::AzCore
)
@@ -0,0 +1,19 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
include/AWSNativeSDKInit/AWSNativeSDKInit.h
include/AWSNativeSDKInit/AWSMemoryInterface.h
include/AWSNativeSDKInit/AWSLogSystemInterface.h
source/AWSNativeSDKInit.cpp
source/AWSMemoryInterface.cpp
source/AWSLogSystemInterface.cpp
)
@@ -0,0 +1,80 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
#include <AzCore/PlatformDef.h>
AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option")
#include <aws/core/utils/logging/LogSystemInterface.h>
AZ_POP_DISABLE_WARNING
#else
#include <sstream>
namespace Aws
{
using OStringStream = std::basic_ostringstream<char>;
namespace Utils
{
namespace Logging
{
using LogLevel = int;
}
}
}
#endif
namespace AWSNativeSDKInit
{
class AWSLogSystemInterface
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
: public Aws::Utils::Logging::LogSystemInterface
#endif
{
public:
static const char* AWS_API_LOG_PREFIX;
static const int MAX_MESSAGE_LENGTH;
static const char* MESSAGE_FORMAT;
static const char* ERROR_WINDOW_NAME;
static const char* LOG_ENV_VAR;
AWSLogSystemInterface(Aws::Utils::Logging::LogLevel logLevel);
/**
* Gets the currently configured log level for this logger.
*/
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
Aws::Utils::Logging::LogLevel GetLogLevel(void) const override;
#else
Aws::Utils::Logging::LogLevel GetLogLevel(void) const;
#endif
/**
* Does a printf style output to the output stream. Don't use this, it's unsafe. See LogStream
*/
void Log(Aws::Utils::Logging::LogLevel logLevel, const char* tag, const char* formatStr, ...);
/**
* Writes the stream to the output stream.
*/
void LogStream(Aws::Utils::Logging::LogLevel logLevel, const char* tag, const Aws::OStringStream &messageStream);
void Flush();
private:
bool ShouldLog(Aws::Utils::Logging::LogLevel logLevel);
void SetLogLevel(Aws::Utils::Logging::LogLevel newLevel);
void ForwardAwsApiLogMessage(Aws::Utils::Logging::LogLevel logLevel, const char* tag, const char* message);
Aws::Utils::Logging::LogLevel m_logLevel;
};
}
@@ -0,0 +1,73 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
#include <aws/core/utils/memory/MemorySystemInterface.h>
#else
#include <cstddef>
#endif
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h>
namespace AWSNativeSDKInit
{
class AWSNativeSDKAllocator final
: public AZ::SystemAllocator
{
public:
AZ_CLASS_ALLOCATOR(AWSNativeSDKAllocator, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(AWSNativeSDKAllocator, "{8B4DA42F-2507-4A5B-B13C-4B2A72BC161E}");
///////////////////////////////////////////////////////////////////////////////////////////
// IAllocator
const char* GetName() const override
{
return "AWSNativeSDKAllocator";
}
const char* GetDescription() const override
{
return "Allocator used by the AWSNativeSDK";
}
///////////////////////////////////////////////////////////////////////////////////////////
};
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
class MemoryManager : public Aws::Utils::Memory::MemorySystemInterface
{
static const char* AWS_API_ALLOC_TAG;
public:
void Begin() override;
void End() override;
void* AllocateMemory(std::size_t blockSize, std::size_t alignment, const char* allocationTag = nullptr) override;
void FreeMemory(void* memoryPtr) override;
AZ::AllocatorWrapper<AWSNativeSDKAllocator> m_allocator;
bool m_systemAllocatorCreated{ false };
};
#else
class MemoryManager
{
static const char* AWS_API_ALLOC_TAG;
public:
void Begin();
void End();
void* AllocateMemory(std::size_t blockSize, std::size_t alignment, const char* allocationTag = nullptr);
void FreeMemory(void* memoryPtr);
};
#endif
}
@@ -0,0 +1,62 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include <AWSNativeSDKInit/AWSMemoryInterface.h>
#include <AzCore/Module/Environment.h>
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly.
// AWSAllocator.h(70): warning C4996: 'std::allocator<T>::pointer': warning STL4010: Various members of std::allocator are deprecated in C++17.
// Use std::allocator_traits instead of accessing these members directly.
// You can define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning.
AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option")
#include <aws/core/Aws.h>
AZ_POP_DISABLE_WARNING
#endif
namespace AWSNativeSDKInit
{
// Entry point for Lumberyard managing the AWSNativeSDK's initialization and shutdown requirements
// Use an AZ::Environment variable to enforce only one init and shutdown
class InitializationManager
{
public:
static const char* const initializationManagerTag;
InitializationManager();
~InitializationManager();
// Call to guarantee that the API is initialized with proper Lumberyard settings.
// It's fine to call this from every module which needs to use the NativeSDK
// Creates a static shared pointer using the AZ EnvironmentVariable system.
// This will prevent a the AWS SDK from going through the shutdown routine until all references are gone, or
// the AZ::EnvironmentVariable system is brought down.
static void InitAwsApi();
static bool IsInitialized();
// Remove our reference
static void Shutdown();
private:
void InitializeAwsApiInternal();
void ShutdownAwsApiInternal();
MemoryManager m_memoryManager;
static AZ::EnvironmentVariable<InitializationManager> s_initManager;
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
Aws::SDKOptions m_awsSDKOptions;
#endif
};
}
@@ -0,0 +1,162 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <AWSNativeSDKInit/AWSLogSystemInterface.h>
#include <AzCore/base.h>
#include <AzCore/Module/Environment.h>
#include <stdarg.h>
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option")
#include <aws/core/utils/logging/AWSLogging.h>
#include <aws/core/utils/logging/DefaultLogSystem.h>
#include <aws/core/utils/logging/ConsoleLogSystem.h>
AZ_POP_DISABLE_WARNING
#endif
namespace AWSNativeSDKInit
{
const char* AWSLogSystemInterface::AWS_API_LOG_PREFIX = "AwsApi-";
const int AWSLogSystemInterface::MAX_MESSAGE_LENGTH = 4096;
const char* AWSLogSystemInterface::MESSAGE_FORMAT = "[AWS] %s - %s";
const char* AWSLogSystemInterface::ERROR_WINDOW_NAME = "AwsNativeSDK";
AWSLogSystemInterface::AWSLogSystemInterface(Aws::Utils::Logging::LogLevel logLevel)
: m_logLevel(logLevel)
{
}
/**
* Gets the currently configured log level for this logger.
*/
Aws::Utils::Logging::LogLevel AWSLogSystemInterface::GetLogLevel() const
{
Aws::Utils::Logging::LogLevel newLevel = m_logLevel;
static const char* const logLevelEnvVar = "sys_SetLogLevel";
auto logVar = AZ::Environment::FindVariable<int>(logLevelEnvVar);
if (logVar)
{
newLevel = (Aws::Utils::Logging::LogLevel) *logVar;
}
return newLevel != m_logLevel ? newLevel : m_logLevel;
}
/**
* Does a printf style output to the output stream. Don't use this, it's unsafe. See LogStream
*/
void AWSLogSystemInterface::Log(Aws::Utils::Logging::LogLevel logLevel, const char* tag, const char* formatStr, ...)
{
if (!ShouldLog(logLevel))
{
return;
}
char message[MAX_MESSAGE_LENGTH];
va_list mark;
va_start(mark, formatStr);
azvsnprintf(message, MAX_MESSAGE_LENGTH, formatStr, mark);
va_end(mark);
ForwardAwsApiLogMessage(logLevel, tag, message);
}
/**
* Writes the stream to the output stream.
*/
void AWSLogSystemInterface::LogStream(Aws::Utils::Logging::LogLevel logLevel, const char* tag, const Aws::OStringStream &messageStream)
{
if(!ShouldLog(logLevel))
{
return;
}
ForwardAwsApiLogMessage(logLevel, tag, messageStream.str().c_str());
}
bool AWSLogSystemInterface::ShouldLog(Aws::Utils::Logging::LogLevel logLevel)
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
Aws::Utils::Logging::LogLevel newLevel = GetLogLevel();
if (newLevel > Aws::Utils::Logging::LogLevel::Info && newLevel <= Aws::Utils::Logging::LogLevel::Trace && newLevel != m_logLevel)
{
SetLogLevel(newLevel);
}
#endif
return (logLevel <= m_logLevel);
}
void AWSLogSystemInterface::SetLogLevel(Aws::Utils::Logging::LogLevel newLevel)
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
Aws::Utils::Logging::ShutdownAWSLogging();
Aws::Utils::Logging::InitializeAWSLogging(Aws::MakeShared<AWSLogSystemInterface>("AWS", newLevel));
m_logLevel = newLevel;
#endif
}
void AWSLogSystemInterface::ForwardAwsApiLogMessage(Aws::Utils::Logging::LogLevel logLevel, const char* tag, const char* message)
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
switch (logLevel)
{
case Aws::Utils::Logging::LogLevel::Off:
break;
case Aws::Utils::Logging::LogLevel::Fatal:
AZ::Debug::Trace::Instance().Error(__FILE__, __LINE__, AZ_FUNCTION_SIGNATURE, AWSLogSystemInterface::ERROR_WINDOW_NAME, MESSAGE_FORMAT, tag, message);
break;
case Aws::Utils::Logging::LogLevel::Error:
AZ::Debug::Trace::Instance().Warning(__FILE__, __LINE__, AZ_FUNCTION_SIGNATURE, AWSLogSystemInterface::ERROR_WINDOW_NAME, MESSAGE_FORMAT, tag, message);
break;
case Aws::Utils::Logging::LogLevel::Warn:
AZ::Debug::Trace::Instance().Warning(__FILE__, __LINE__, AZ_FUNCTION_SIGNATURE, AWSLogSystemInterface::ERROR_WINDOW_NAME, MESSAGE_FORMAT, tag, message);
break;
case Aws::Utils::Logging::LogLevel::Info:
AZ::Debug::Trace::Instance().Printf(AWSLogSystemInterface::ERROR_WINDOW_NAME, MESSAGE_FORMAT, tag, message);
break;
case Aws::Utils::Logging::LogLevel::Debug:
AZ::Debug::Trace::Instance().Printf(AWSLogSystemInterface::ERROR_WINDOW_NAME, MESSAGE_FORMAT, tag, message);
break;
case Aws::Utils::Logging::LogLevel::Trace:
AZ::Debug::Trace::Instance().Printf(AWSLogSystemInterface::ERROR_WINDOW_NAME, MESSAGE_FORMAT, tag, message);
break;
default:
break;
}
#endif
}
void AWSLogSystemInterface::Flush()
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
// No-op AZ Debug Trace doesn't have a flush API
#endif
}
}
@@ -0,0 +1,53 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <AWSNativeSDKInit/AWSMemoryInterface.h>
namespace AWSNativeSDKInit
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
const char* MemoryManager::AWS_API_ALLOC_TAG = "AwsApi";
void MemoryManager::Begin()
{
// We can't guarantee that all uses cases have/will Create a SystemAllocator which is a dependency of
// the AWSNativeSDKAllocator in SystemAllocator::Create
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
m_systemAllocatorCreated = true;
}
AWSNativeSDKAllocator::Descriptor desc;
m_allocator.Create(desc);
}
void MemoryManager::End()
{
m_allocator.Destroy();
if (m_systemAllocatorCreated)
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
}
void* MemoryManager::AllocateMemory(std::size_t blockSize, std::size_t alignment, const char* allocationTag)
{
return m_allocator->Allocate(blockSize, alignment, 0, allocationTag);
}
void MemoryManager::FreeMemory(void* memoryPtr)
{
m_allocator->DeAllocate(memoryPtr);
}
#endif
}
@@ -0,0 +1,92 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
#include <AzCore/Module/Environment.h>
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
#include <AWSNativeSDKInit/AWSLogSystemInterface.h>
#include <aws/core/Aws.h>
#include <aws/core/utils/logging/AWSLogging.h>
#include <aws/core/utils/logging/DefaultLogSystem.h>
#include <aws/core/utils/logging/ConsoleLogSystem.h>
#endif
namespace AWSNativeSDKInit
{
namespace Platform
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
void CustomizeSDKOptions(Aws::SDKOptions& options);
void CustomizeShutdown();
#endif
}
const char* const InitializationManager::initializationManagerTag = "AWSNativeSDKInitializer";
AZ::EnvironmentVariable<InitializationManager> InitializationManager::s_initManager = nullptr;
InitializationManager::InitializationManager()
{
InitializeAwsApiInternal();
}
InitializationManager::~InitializationManager()
{
ShutdownAwsApiInternal();
}
void InitializationManager::InitAwsApi()
{
s_initManager = AZ::Environment::CreateVariable<InitializationManager>(initializationManagerTag);
}
void InitializationManager::Shutdown()
{
s_initManager = nullptr;
}
bool InitializationManager::IsInitialized()
{
return s_initManager.IsConstructed();
}
void InitializationManager::InitializeAwsApiInternal()
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
Aws::Utils::Logging::LogLevel logLevel;
#ifdef _DEBUG
logLevel = Aws::Utils::Logging::LogLevel::Warn;
#else
logLevel = Aws::Utils::Logging::LogLevel::Warn;
#endif
m_awsSDKOptions.loggingOptions.logLevel = logLevel;
m_awsSDKOptions.loggingOptions.logger_create_fn = [logLevel]()
{
return Aws::MakeShared<AWSLogSystemInterface>("AWS", logLevel);
};
m_awsSDKOptions.memoryManagementOptions.memoryManager = &m_memoryManager;
Platform::CustomizeSDKOptions(m_awsSDKOptions);
Aws::InitAPI(m_awsSDKOptions);
#endif // #if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
}
void InitializationManager::ShutdownAwsApiInternal()
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
Aws::ShutdownAPI(m_awsSDKOptions);
Platform::CustomizeShutdown();
#endif // #if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
}
}
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/Default/AWSNativeSDKInit_Default.cpp
)
@@ -0,0 +1,29 @@
/*
* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
namespace AWSNativeSDKInit
{
namespace Platform
{
#if defined(PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
void CustomizeSDKOptions(Aws::SDKOptions& options)
{
AZ_UNUSED(options);
}
void CustomizeShutdown()
{
}
#endif
}
}
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/Default/AWSNativeSDKInit_Default.cpp
)
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/Default/AWSNativeSDKInit_Default.cpp
)
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/Default/AWSNativeSDKInit_Default.cpp
)
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/Default/AWSNativeSDKInit_Default.cpp
)
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="${ANDROID_PACKAGE}"
android:versionCode="${ANDROID_VERSION_NUMBER}"
android:versionName="${ANDROID_VERSION_NAME}">
<!-- SDK_VERSIONS -->
<!-- OpenGL ES 3.0 -->
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
<!-- Required for Kindle devices, which is based off Android 5.0, to access app specific public storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="21" />
<!-- Allow TCP/IP. Needed for PerfHUD ES -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Required to poll the state of the network connection and respond to changes (Obb Download)-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Required to check whether Wi-Fi is enabled (Obb Download) -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- Required to keep CPU alive while downloading the Obb files (NOT to keep screen awake) -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Required to for IAP -->
<uses-permission android:name="com.android.vending.BILLING" />
<application
android:icon="@mipmap/app_icon"
android:label="@string/app_name"
${ANDROID_MULTI_WINDOW} >
<!-- Our activity loads the generated bootstrapping class in order to prelaod any third party shared libraries -->
<activity
android:name="${ANDROID_PROJECT_ACTIVITY}"
android:screenOrientation="${ANDROID_SCREEN_ORIENTATION}"
android:configChanges="${ANDROID_CONFIG_CHANGES}" >
<!-- Multi-window properties, following line can be blank if not specified -->
${ANDROID_MULTI_WINDOW_PROPERTIES}
<!-- Tell NativeActivity the name of or .so -->
<meta-data android:name="android.app.lib_name"
android:value="${ANDROID_LAUNCHER_NAME}" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.amazon.lumberyard.io.obb.ObbDownloaderActivity"
android:launchMode="singleTask"
android:screenOrientation="${ANDROID_SCREEN_ORIENTATION}"/>
<!-- Services for IAP -->
<service android:name="com.android.vending.billing.InAppBillingService" />
<!-- Services for downloading the Obb -->
<service android:name="com.amazon.lumberyard.io.obb.ObbDownloaderService" />
<receiver android:name="com.amazon.lumberyard.io.obb.ObbDownloaderAlarmReceiver" />
<!-- Samsung DEX specific properties, the following line(s) can be blank if not specified -->
${SAMSUNG_DEX_KEEP_ALIVE}
${SAMSUNG_DEX_LAUNCH_WIDTH}
${SAMSUNG_DEX_LAUNCH_HEIGHT}
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
@@ -0,0 +1,29 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
package ${ANDROID_PACKAGE};
import android.util.Log;
import com.amazon.lumberyard.LumberyardActivity;
////////////////////////////////////////////////////////////////////////////////////////////////////
public class ${ANDROID_PROJECT_ACTIVITY} extends LumberyardActivity
{
// since we are using the NativeActivity, all we need to manually load is the
// shared c++ libray we are using
static
{
Log.d("LMBR", "BootStrap: Starting Library load");
System.loadLibrary("c++_shared");
Log.d("LMBR", "BootStrap: Finished Library load");
}
}
@@ -0,0 +1,88 @@
{
"src" :
{
"main" :
{
"java" :
{
"${ANDROID_PACKAGE_PATH}" :
{
"ProjectActivity.java" : "${ANDROID_PROJECT_ACTIVITY}.java"
}
},
"res" :
{
"values" :
[
"strings.xml",
"bools.xml"
],
"drawable-land-mdpi" :
{
"app_splash-land-mdpi.png" : "app_splash.png"
},
"drawable-land-hdpi" :
{
"app_splash-land-hdpi.png" : "app_splash.png"
},
"drawable-land-xhdpi" :
{
"app_splash-land-xhdpi.png" : "app_splash.png"
},
"drawable-land-xxhdpi" :
{
"app_splash-land-xxhdpi.png" : "app_splash.png"
},
"drawable-port-mdpi" :
{
"app_splash-port-mdpi.png" : "app_splash.png"
},
"drawable-port-hdpi" :
{
"app_splash-port-hdpi.png" : "app_splash.png"
},
"drawable-port-xhdpi" :
{
"app_splash-port-xhdpi.png" : "app_splash.png"
},
"drawable-port-xxhdpi" :
{
"app_splash-port-xxhdpi.png" : "app_splash.png"
},
"layout" :
[
"splash_screen.xml" ,
"obb_downloader.xml"
],
"mipmap-mdpi" :
{
"app_icon-mdpi.png" : "app_icon.png"
},
"mipmap-hdpi" :
{
"app_icon-hdpi.png" : "app_icon.png"
},
"mipmap-xhdpi" :
{
"app_icon-xhdpi.png" : "app_icon.png"
},
"mipmap-xxhdpi" :
{
"app_icon-xxhdpi.png" : "app_icon.png"
},
"mipmap-xxxhdpi" :
{
"app_icon-xxxhdpi.png" : "app_icon.png"
}
},
"" :
[
"AndroidManifest.xml"
]
}
},
"" :
[
"wscript"
]
}
@@ -0,0 +1,81 @@
{
"APKExpansionLibrary": {
"srcDir": ["${ANDROID_SDK_HOME}/extras/google/play_apk_expansion/downloader_library",
"${ANDROID_SDK_HOME}/extras/google/market_apk_expansion/downloader_library"],
"dependencies": [
"LicenseLibrary"
],
"patches": [{
"path": "src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java",
"changes": [
{
"line": 134,
"old": ["mCurrentNotification.tickerText = mLabel + \": \" + mCurrentText;",
"mCurrentNotification.icon = iconResource;",
"mCurrentNotification.setLatestEventInfo(mContext, mCurrentTitle, mCurrentText,",
" mContentIntent);"],
"new": ["mCurrentNotification = createNotification(iconResource);"]
},
{
"line": 156,
"old": ["mNotification.tickerText = mCurrentTitle;",
"mNotification.icon = android.R.drawable.stat_sys_download;",
"mNotification.setLatestEventInfo(mContext, mLabel, mCurrentText, mContentIntent);"],
"new": ["mNotification = createNotification(android.R.drawable.stat_sys_download);"]
},
{
"line": 229,
"old" : [""],
"new": ["",
" private Notification createNotification(int iconRes) {",
" return new Notification.Builder(mContext)",
" .setContentText(mCurrentText)",
" .setContentTitle(mCurrentTitle)",
" .setContentIntent(mContentIntent)",
" .setTicker(mLabel + \": \" + mCurrentText)",
" .setSmallIcon(iconRes)",
" .build();",
" }"]
}]
},
{
"path": "AndroidManifest.xml",
"changes": [
{
"line": 6,
"old": ["<uses-sdk android:minSdkVersion=\"4\" android:targetSdkVersion=\"15\"/>"],
"new": [""]
}]
}],
"launcherDependency": "true"
},
"LicenseLibrary": {
"srcDir": ["${ANDROID_SDK_HOME}/extras/google/play_licensing/library",
"${ANDROID_SDK_HOME}/extras/google/market_licensing/library"],
"buildDependencies": [
"org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2"
],
"libs" : [{
"path" : "${ANDROID_SDK_HOME}/platforms/${ANDROID_SDK_VERSION}/optional/org.apache.http.legacy.jar",
"required" : false
}],
"patches": [{
"path": "src/com/google/android/vending/licensing/LicenseChecker.java",
"changes": [{
"line": 152,
"old": ["Base64.decode(\"Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=\"))),"],
"new": ["Base64.decode(\"Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=\"))).setPackage(\"com.android.vending\"),"]
}]
},
{
"path": "AndroidManifest.xml",
"changes": [
{
"line": 19,
"old": ["<!-- Devices >= 3 have version of Android Market that supports licensing. -->",
"<uses-sdk android:minSdkVersion=\"3\" android:targetSdkVersion=\"15\" />"],
"new": [""]
}]
}]
}
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2505ee83c0e435700601d38c7c4b08b601478c5194a088ff6577e1017731b3ae
size 2368
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:32d4da537649036b18aa116c1337b8b23d1a4536b907034a1262cc6764e65627
size 1615
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6a7f38fe03aba465b65189fdf183281c0d7397962f93168379ebca25f9581a30
size 3362
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:02392ac01615ce21710b8566085941fea67926cab062ac2a4c7cdfc594aff428
size 5482
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3636ef346cf87d2382ed67ef0a7396bfe3b4df13f9ef223b1911e96ef42ae2ec
size 8238
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:df22836ffc2ab5cca07c6e0d152ed8ef01d56d66cdc56435d6b48304753c4990
size 196450
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:70250143d6b53978c7a164330c38cf34777688b92e0def691b68777be111ac75
size 156821
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:80752114b225ad43028278ac8372cbf4543f493a55e5fe05c24ff1e20f9b24b5
size 324436
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:44de927141f19e10672012a8e0675d03fd06e6b20d5a7c759cdc233a1262ef55
size 441038
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d3fb185179d26442087087401dd96443ed094122b8b7a1b7985aae299764bcf6
size 271782
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:04c9bc74b51d3bd7cf85e178b15c631fd78c6251ef014a41506f36852ec4a500
size 209127
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:913fdddb651ff6d74fb0583b06c6f32f6c87bf9eabe4b861d662c9c409cff733
size 461061
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cb9fd81fb4ad83132db7401fe412cce61bf0577e1822653115930f31f3db6241
size 570118
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="use_main_obb">${ANDROID_USE_MAIN_OBB}</bool>
<bool name="use_patch_obb">${ANDROID_USE_PATCH_OBB}</bool>
<bool name="enable_keep_screen_on">${ANDROID_ENABLE_KEEP_SCREEN_ON}</bool>
<bool name="disable_immersive_mode">${ANDROID_DISABLE_IMMERSIVE_MODE}</bool>
</resources>
@@ -0,0 +1,82 @@
//
// All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
// its licensors.
//
// For complete copyright and license terms please see the LICENSE at the root of this
// distribution (the "License"). All use of this software is governed by the License,
// or, if provided, by the license below or the license accompanying this file. Do not
// remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
apply plugin: "com.android.${TARGET_TYPE}"
android {
${SIGNING_CONFIGS}
compileSdkVersion sdkVer
buildToolsVersion buildToolsVer
lintOptions {
abortOnError false
checkReleaseBuilds false
}
defaultConfig {
minSdkVersion ndkPlatformVer
targetSdkVersion sdkVer
${NATIVE_CMAKE_SECTION_DEFAULT_CONFIG}
}
buildTypes {
debug {
debuggable true
${NATIVE_CMAKE_SECTION_DEBUG_CONFIG}
${SIGNING_DEBUG_CONFIG}
}
profile {
debuggable true
${NATIVE_CMAKE_SECTION_PROFILE_CONFIG}
${SIGNING_PROFILE_CONFIG}
}
release {
debuggable false
minifyEnabled false
${NATIVE_CMAKE_SECTION_RELEASE_CONFIG}
${SIGNING_RELEASE_CONFIG}
}
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_7
sourceCompatibility JavaVersion.VERSION_1_7
}
${NATIVE_CMAKE_SECTION_ANDROID}
sourceSets {
main {
${OVERRIDE_JAVA_SOURCESET}
jniLibs {
srcDirs = ["src/main/jniLibs"${OPTIONAL_JNI_SRC_LIB_SET}]
}
}
}
packagingOptions {
pickFirst '**/*.so'
}
}
${PROJECT_DEPENDENCIES}
afterEvaluate {
${CUSTOM_APPLY_ASSET_LAYOUT_DEBUG_TASK}
${CUSTOM_APPLY_ASSET_LAYOUT_PROFILE_TASK}
${CUSTOM_APPLY_ASSET_LAYOUT_RELEASE_TASK}
${CUSTOM_GRADLE_COPY_NATIVE_DEBUG_LIB_TASK}
${CUSTOM_GRADLE_COPY_NATIVE_PROFILE_LIB_TASK}
${CUSTOM_GRADLE_COPY_NATIVE_RELEASE_LIB_TASK}
}
@@ -0,0 +1,30 @@
###
### All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
### its licensors.
###
### For complete copyright and license terms please see the LICENSE at the root of this
### distribution (the "License"). All use of this software is governed by the License,
### or, if provided, by the license below or the license accompanying this file. Do not
### remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
### WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
###
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Android Studio project settings overrides
# Enable Gradle as a daemon to improve the startup and execution time
org.gradle.daemon=true
# Enable parallel execution to improve execution time
org.gradle.parallel=true
# make sure configure-on-demand is disabled as it really only benefits when
# there are a large number of sub-projects
org.gradle.configureondemand=false
# bump the JVM memory limits due to the size of Lumberyard. Defaults: -Xmx1280m -XX:MaxPermSize=256m
org.gradle.jvmargs=
# required to use Android X libraries
android.useAndroidX=true
@@ -0,0 +1,21 @@
###
### All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
### its licensors.
###
### For complete copyright and license terms please see the LICENSE at the root of this
### distribution (the "License"). All use of this software is governed by the License,
### or, if provided, by the license below or the license accompanying this file. Do not
### remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
### WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
###
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
# ${GENERATION_TIMESTAMP}
ndk.dir=${ANDROID_NDK_PATH}
sdk.dir=${ANDROID_SDK_PATH}
${CMAKE_DIR_LINE}
@@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/transparent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="vertical" >
<TextView
android:id="@+id/statusText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/downloaderDashboard"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/statusText"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
<TextView
android:id="@+id/progressAsFraction"
style="@android:style/TextAppearance.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="5dp"
android:text="0MB / 0MB" >
</TextView>
<TextView
android:id="@+id/progressAsPercentage"
style="@android:style/TextAppearance.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/progressBar"
android:text="0%" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/progressAsFraction"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_weight="1" />
<TextView
android:id="@+id/progressAverageSpeed"
style="@android:style/TextAppearance.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/progressBar"
android:layout_marginLeft="5dp" />
<TextView
android:id="@+id/progressTimeRemaining"
style="@android:style/TextAppearance.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/progressBar"
android:layout_below="@+id/progressBar" />
</RelativeLayout>
<LinearLayout
android:id="@+id/downloaderDashboard"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/pauseButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_marginTop="10dp"
android:layout_weight="0"
android:minHeight="40dp"
android:minWidth="94dp"
android:text="@string/text_button_pause" />
<Button
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="10dp"
android:layout_weight="0"
android:minHeight="40dp"
android:minWidth="94dp"
android:text="@string/text_button_cancel"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/approveCellular"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="gone" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:id="@+id/textPausedParagraph1"
android:text="@string/text_paused_cellular" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:id="@+id/textPausedParagraph2"
android:text="@string/text_paused_cellular_2" />
<LinearLayout
android:id="@+id/buttonRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/resumeOverCellular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:text="@string/text_button_resume_cellular" />
<Button
android:id="@+id/wifiSettingsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:text="@string/text_button_wifi_settings" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,44 @@
//
// All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
// its licensors.
//
// For complete copyright and license terms please see the LICENSE at the root of this
// distribution (the "License"). All use of this software is governed by the License,
// or, if provided, by the license below or the license accompanying this file. Do not
// remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
subprojects {
ext {
sdkVer = ${SDK_VER}
ndkPlatformVer = ${NDK_PLATFORM_VER}
buildToolsVer = '${SDK_BUILD_TOOL_VER}'
lyDevRoot = '${LY_DEV_ROOT}'
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
@@ -0,0 +1,15 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".LumberyardActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/splash_image"
android:background="#414141"
android:src="@drawable/app_splash"
android:scaleType="centerCrop" />
</RelativeLayout>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">${ANDROID_APP_NAME}</string>
<string name="public_key">${ANDROID_APP_PUBLIC_KEY}</string>
<string name="obfuscator_salt">${ANDROID_APP_OBFUSCATOR_SALT}</string>
<!-- Strings used for the Obb Downloader Activity -->
<string name="text_paused_cellular">Would you like to enable downloading over cellular connections? Depending on your data plan, this may cost you money.</string>
<string name="text_paused_cellular_2">If you choose not to enable downloading over cellular connections, the download will automatically resume when wi-fi is available.</string>
<string name="text_button_resume_cellular">Resume download</string>
<string name="text_button_wifi_settings">Wi-Fi settings</string>
<string name="text_verifying_download">Verifying Download</string>
<string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string>
<string name="text_validation_failed">XAPK File Validation Failed.</string>
<string name="text_button_pause">Pause Download</string>
<string name="text_button_resume">Resume Download</string>
<string name="text_button_cancel">Cancel</string>
<string name="text_button_cancel_verify">Cancel Verification</string>
<!-- End Obb Downloader strings -->
</resources>
+68
View File
@@ -0,0 +1,68 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
ly_add_target(
NAME AssetBundler.Static STATIC
NAMESPACE AZ
FILES_CMAKE
assetbundlerbatch_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
COMPILE_DEFINITIONS
PRIVATE
METRICS_ENABLED
BUILD_DEPENDENCIES
PUBLIC
AZ::AzToolsFramework
${additional_dependencies}
)
ly_add_target(
NAME AssetBundlerBatch EXECUTABLE
NAMESPACE AZ
FILES_CMAKE
assetbundlerbatch_exe_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AssetBundler.Static
)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AssetBundler.Tests EXECUTABLE
NAMESPACE AZ
FILES_CMAKE
assetbundlerbatch_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
AZ::AssetBundler.Static
AZ::AzFrameworkTestShared
)
ly_add_googletest(
NAME AZ::AssetBundler.Tests
TEST_COMMAND $<TARGET_FILE:AZ::AssetBundler.Tests> --unittest
)
endif()
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
source/main.cpp
)
@@ -0,0 +1,17 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
source/utils/utils.h
source/utils/utils.cpp
source/utils/applicationManager.h
source/utils/applicationManager.cpp
)
@@ -0,0 +1,17 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
tests/applicationManagerTests.cpp
tests/tests_main.cpp
tests/main.h
tests/UtilsTests.cpp
)
+26
View File
@@ -0,0 +1,26 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <source/utils/applicationManager.h>
int main(int argc, char* argv[])
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
int runSuccess = 0;
{
AssetBundler::ApplicationManager applicationManger(&argc, &argv);
applicationManger.Init();
runSuccess = applicationManger.Run() ? 0 : 1;
}
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
return runSuccess;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,305 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Asset/AssetSeedManager.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
#include <AzToolsFramework/Asset/AssetUtils.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <source/utils/utils.h>
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogManager.h>
namespace AssetBundler
{
struct SeedsParams
{
AZ_CLASS_ALLOCATOR(SeedsParams, AZ::SystemAllocator, 0);
FilePath m_seedListFile;
AZStd::vector<AZStd::string> m_addSeedList;
AZStd::vector<AZStd::string> m_removeSeedList;
bool m_addPlatformToAllSeeds = false;
bool m_removePlatformFromAllSeeds = false;
bool m_updateSeedPathHint = false;
bool m_removeSeedPathHint = false;
bool m_ignoreFileCase = false;
bool m_save = false;
bool m_print = false;
AzFramework::PlatformFlags m_platformFlags = AzFramework::PlatformFlags::Platform_NONE;
FilePath m_assetCatalogFile;
};
struct AssetListsParams
{
AZ_CLASS_ALLOCATOR(AssetListsParams, AZ::SystemAllocator, 0);
FilePath m_assetListFile;
AZStd::vector<FilePath> m_seedListFiles;
AZStd::vector<AZStd::string> m_addSeedList;
AZStd::vector<AZStd::string> m_skipList;
bool m_addDefaultSeedListFiles = false;
bool m_print = false;
bool m_dryRun = false;
bool m_generateDebugFile = false;
bool m_allowOverwrites = false;
AzFramework::PlatformFlags m_platformFlags = AzFramework::PlatformFlags::Platform_NONE;
FilePath m_assetCatalogFile;
};
enum ComparisonRulesStepAction
{
Add,
AddToEnd,
Remove,
Move,
Edit,
Default,
};
struct ComparisonRulesParams
{
AZ_CLASS_ALLOCATOR(ComparisonRulesParams, AZ::SystemAllocator, 0);
AZStd::vector<AzToolsFramework::AssetFileInfoListComparison::ComparisonType> m_comparisonTypeList;
AZStd::vector<AZStd::string> m_filePatternList;
AZStd::vector<AzToolsFramework::AssetFileInfoListComparison::FilePatternType> m_filePatternTypeList;
AZStd::vector<AZStd::string> m_tokenNamesList;
AZStd::vector<AZStd::string> m_firstInputList;
AZStd::vector<AZStd::string> m_secondInputList;
FilePath m_comparisonRulesFile;
ComparisonRulesStepAction m_comparisonRulesStepAction = ComparisonRulesStepAction::Default;
size_t m_initialLine = 0;
size_t m_destinationLine = 0;
unsigned int m_intersectionCount = 0;
bool m_print = false;
};
struct ComparisonParams
{
AZ_CLASS_ALLOCATOR(ComparisonParams, AZ::SystemAllocator, 0);
// Comparison input/output
AZStd::vector<AZStd::string> m_firstCompareFile;
AZStd::vector<AZStd::string> m_secondCompareFile;
AZStd::vector<AZStd::string> m_outputs;
AZStd::vector<AZStd::string> m_printComparisons;
bool m_printLast = false;
bool m_allowOverwrites = false;
AzFramework::PlatformFlags m_platformFlags = AzFramework::PlatformFlags::Platform_NONE;
// Comparison definitions
FilePath m_comparisonRulesFile;
ComparisonRulesParams m_comparisonRulesParams;
};
struct BundleSettingsParams
{
AZ_CLASS_ALLOCATOR(BundleSettingsParams, AZ::SystemAllocator, 0);
FilePath m_bundleSettingsFile;
FilePath m_assetListFile;
FilePath m_outputBundlePath;
int m_bundleVersion = -1;
int m_maxBundleSizeInMB = -1;
bool m_print = false;
AzFramework::PlatformFlags m_platformFlags = AzFramework::PlatformFlags::Platform_NONE;
};
struct BundlesParams
{
AZ_CLASS_ALLOCATOR(BundlesParams, AZ::SystemAllocator, 0);
FilePath m_bundleSettingsFile;
FilePath m_assetListFile;
FilePath m_outputBundlePath;
int m_bundleVersion = -1;
int m_maxBundleSizeInMB = -1;
AzFramework::PlatformFlags m_platformFlags = AzFramework::PlatformFlags::Platform_NONE;
bool m_allowOverwrites = false;
};
typedef AZStd::vector<BundlesParams> BundlesParamsList;
struct BundleSeedParams
{
AZ_CLASS_ALLOCATOR(BundleSeedParams, AZ::SystemAllocator, 0);
AZStd::vector<AZStd::string> m_addSeedList;
BundlesParams m_bundleParams;
};
class ApplicationManager
: public AZ::Debug::TraceMessageBus::Handler
, public AzToolsFramework::ToolsApplication
{
public:
explicit ApplicationManager(int* argc, char*** argv);
~ApplicationManager();
void Init();
void DestroyApplication();
bool Run();
////////////////////////////////////////////////////////////////////////////////////////////
// AzFramework::Application overrides
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// TraceMessageBus Interface
bool OnPreError(const char* window, const char* fileName, int line, const char* func, const char* message) override;
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
bool OnPrintf(const char* window, const char* message) override;
////////////////////////////////////////////////////////////////////////////////////////////
AZStd::string GetCurrentProjectName() { return m_currentProjectName; }
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> GetGemInfoList() { return m_gemInfoList; }
protected:
////////////////////////////////////////////////////////////////////////////////////////////
// AzFramework::Application overrides
void SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations) override;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Get Generic Command Info
CommandType GetCommandType(const AzFramework::CommandLine* parser, bool suppressErrors);
bool ShouldPrintHelp(const AzFramework::CommandLine* parser);
bool ShouldPrintVerbose(const AzFramework::CommandLine* parser);
void InitArgValidationLists();
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Store Detailed Command Info and Validate parser input (command correctness)
AZ::Outcome<SeedsParams, AZStd::string> ParseSeedsCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<AssetListsParams, AZStd::string> ParseAssetListsCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<ComparisonRulesParams, AZStd::string> ParseComparisonRulesCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<ComparisonParams, AZStd::string> ParseCompareCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<BundleSettingsParams, AZStd::string> ParseBundleSettingsCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<BundlesParamsList, AZStd::string> ParseBundlesCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<BundleSeedParams, AZStd::string> ParseBundleSeedCommandData(const AzFramework::CommandLine* parser);
AZ::Outcome<void, AZStd::string> ValidateInputArgs(const AzFramework::CommandLine* parser, const AZStd::vector<const char*>& validArgList);
AZ::Outcome<AZStd::string, AZStd::string> GetFilePathArg(const AzFramework::CommandLine* parser, const char* argName, const char* subCommandName, bool isRequired = false);
template <typename T>
AZ::Outcome<AZStd::vector<T>, AZStd::string> GetArgsList(const AzFramework::CommandLine* parser, const char* argName, const char* subCommandName, bool isRequired = false);
AZ::Outcome<AzFramework::PlatformFlags, AZStd::string> GetPlatformArg(const AzFramework::CommandLine* parser);
AzFramework::PlatformFlags GetInputPlatformFlagsOrEnabledPlatformFlags(AzFramework::PlatformFlags inputPlatformFlags);
AZStd::vector<AZStd::string> GetAddSeedArgList(const AzFramework::CommandLine* parser);
AZStd::vector<AZStd::string> GetSkipArgList(const AzFramework::CommandLine* parser);
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Run Commands and Validate param data (value correctness)
bool RunSeedsCommands(const AZ::Outcome<SeedsParams, AZStd::string>& paramsOutcome);
bool RunAssetListsCommands(const AZ::Outcome<AssetListsParams, AZStd::string>& paramsOutcome);
bool RunComparisonRulesCommands(const AZ::Outcome<ComparisonRulesParams, AZStd::string>& paramsOutcome);
bool RunCompareCommand(const AZ::Outcome<ComparisonParams, AZStd::string>& paramsOutcome);
bool RunBundleSettingsCommands(const AZ::Outcome<BundleSettingsParams, AZStd::string>& paramsOutcome);
bool RunBundlesCommands(const AZ::Outcome<BundlesParamsList, AZStd::string>& paramsOutcome);
bool RunBundleSeedCommands(const AZ::Outcome<BundleSeedParams, AZStd::string>& paramsOutcome);
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Helpers
AZ::Outcome<void, AZStd::string> InitAssetCatalog(AzFramework::PlatformFlags platforms, const AZStd::string& assetCatalogFile = AZStd::string());
//! Given a gem seed file, validates whether the seed file is valid for the current project
//! and platform flags specified before loading the file from disk.
//! Does not do any validation on non gem seed files.
AZ::Outcome<void, AZStd::string> LoadSeedListFile(const AZStd::string& seedListFileAbsolutePath, AzFramework::PlatformFlags platformFlags);
AZ::Outcome<void, AZStd::string> LoadProjectDependenciesFile(AzFramework::PlatformFlags platformFlags);
void PrintSeedList(const AZStd::string& seedListFileAbsolutePath);
bool RunPlatformSpecificAssetListCommands(const AssetListsParams& params, AzFramework::PlatformFlags platformFlags);
void PrintAssetLists(const AssetListsParams& params,
const AZStd::fixed_vector<AzFramework::PlatformId, AzFramework::PlatformId::NumPlatformIds>& platformIds,
bool printExistingFiles,
const AZStd::unordered_set<AZ::Data::AssetId>& exclusionList,
const AZStd::vector<AZStd::string>& wildcardPatternExclusionList);
AZStd::vector<FilePath> GetAllPlatformSpecificFilesOnDisk(const FilePath& platformIndependentFilePath, AzFramework::PlatformFlags platformFlags = AzFramework::PlatformFlags::Platform_NONE);
AZ::Outcome<void, AZStd::string> ApplyBundleSettingsOverrides(
AzToolsFramework::AssetBundleSettings& bundleSettings,
const AZStd::string& assetListFilePath,
const AZStd::string& outputBundleFilePath,
int bundleVersion,
int maxBundleSize);
AZ::Outcome<void, AZStd::string> ParseComparisonTypesAndPatterns(const AzFramework::CommandLine* parser, ComparisonRulesParams& params);
AZ::Outcome<void, AZStd::string> ParseComparisonTypesAndPatternsForEditCommand(const AzFramework::CommandLine* parser, ComparisonRulesParams& params);
AZ::Outcome<void, AZStd::string> ParseComparisonRulesFirstAndSecondInputArgs(const AzFramework::CommandLine* parser, ComparisonRulesParams& params);
AZ::Outcome<BundlesParamsList, AZStd::string> ParseBundleSettingsAndOverrides(const AzFramework::CommandLine* parser, const char* commandName);
bool ConvertRulesParamsToComparisonData(const ComparisonRulesParams& params, AzToolsFramework::AssetFileInfoListComparison& assetListComparison, size_t startingIndex);
bool EditComparisonData(const ComparisonRulesParams& params, AzToolsFramework::AssetFileInfoListComparison& assetListComparison, size_t index);
void PrintComparisonRules(const AzToolsFramework::AssetFileInfoListComparison& assetListComparison, const AZStd::string& comparisonRulesAbsoluteFilePath);
bool IsDefaultToken(const AZStd::string& pathOrToken);
void PrintComparisonAssetList(const AzToolsFramework::AssetFileInfoList& infoList, const AZStd::string& resultName);
void AddPlatformToAllComparisonParams(ComparisonParams& params, const AZStd::string& platformName);
void AddPlatformToComparisonParam(AZStd::string& inOut, const AZStd::string& platformName);
//! Error message to display when neither of two optional arguments was found
static AZStd::string GetBinaryArgOptionFailure(const char* arg1, const char* arg2);
bool SeedsOperationRequiresCatalog(const SeedsParams& params);
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Output Help Text
void OutputHelp(CommandType commandType);
void OutputHelpSeeds();
void OutputHelpAssetLists();
void OutputHelpComparisonRules();
void OutputHelpCompare();
void OutputHelpBundleSettings();
void OutputHelpBundles();
void OutputHelpBundleSeed();
////////////////////////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<AzToolsFramework::AssetSeedManager> m_assetSeedManager;
AZStd::unique_ptr<AzToolsFramework::PlatformAddressedAssetCatalogManager> m_platformCatalogManager;
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> m_gemInfoList;
bool m_showVerboseOutput = false;
AZStd::string m_currentProjectName;
CommandType m_commandType = CommandType::Invalid;
AZStd::vector<const char*> m_allSeedsArgs;
AZStd::vector<const char*> m_allAssetListsArgs;
AZStd::vector<const char*> m_allComparisonRulesArgs;
AZStd::vector<const char*> m_allCompareArgs;
AZStd::vector<const char*> m_allBundleSettingsArgs;
AZStd::vector<const char*> m_allBundlesArgs;
AZStd::vector<const char*> m_allBundleSeedArgs;
};
}
@@ -0,0 +1,977 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Asset/AssetSystemComponent.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/FileFunc/FileFunc.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <AzToolsFramework/Asset/AssetSeedManager.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <source/utils/utils.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/string/regex.h>
#include <cctype>
AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option")
#include <QDir>
#include <QString>
#include <QStringList>
AZ_POP_DISABLE_WARNING
namespace AssetBundler
{
// General
const char* AppWindowName = "AssetBundler";
const char* AppWindowNameVerbose = "AssetBundlerVerbose";
const char* HelpFlag = "help";
const char* HelpFlagAlias = "h";
const char* VerboseFlag = "verbose";
const char* SaveFlag = "save";
const char* PlatformArg = "platform";
const char* PrintFlag = "print";
const char* AssetCatalogFileArg = "overrideAssetCatalogFile";
const char* AllowOverwritesFlag = "allowOverwrites";
const char* IgnoreFileCaseFlag = "ignoreFileCase";
const char* ProjectArg = "project";
// Seeds
const char* SeedsCommand = "seeds";
const char* SeedListFileArg = "seedListFile";
const char* AddSeedArg = "addSeed";
const char* RemoveSeedArg = "removeSeed";
const char* AddPlatformToAllSeedsFlag = "addPlatformToSeeds";
const char* RemovePlatformFromAllSeedsFlag = "removePlatformFromSeeds";
const char* UpdateSeedPathArg = "updateSeedPath";
const char* RemoveSeedPathArg = "removeSeedPath";
const char* DefaultProjectTemplatePath = "ProjectTemplates/DefaultTemplate/${ProjectName}";
const char* ProjectName = "${ProjectName}";
const char* DependenciesFileSuffix = "_Dependencies";
const char* DependenciesFileExtension = "xml";
// Asset Lists
const char* AssetListsCommand = "assetLists";
const char* AssetListFileArg = "assetListFile";
const char* AddDefaultSeedListFilesFlag = "addDefaultSeedListFiles";
const char* DryRunFlag = "dryRun";
const char* GenerateDebugFileFlag = "generateDebugFile";
const char* SkipArg = "skip";
// Comparison Rules
const char* ComparisonRulesCommand = "comparisonRules";
const char* ComparisonRulesFileArg = "comparisonRulesFile";
const char* ComparisonTypeArg = "comparisonType";
const char* ComparisonFilePatternArg = "filePattern";
const char* ComparisonFilePatternTypeArg = "filePatternType";
const char* ComparisonTokenNameArg = "tokenName";
const char* ComparisonFirstInputArg = "firstInput";
const char* ComparisonSecondInputArg = "secondInput";
const char* AddComparisonStepArg = "addComparison";
const char* RemoveComparisonStepArg = "removeComparison";
const char* MoveComparisonStepArg = "moveComparison";
const char* EditComparisonStepArg = "editComparison";
// Compare
const char* CompareCommand = "compare";
const char* CompareFirstFileArg = "firstAssetFile";
const char* CompareSecondFileArg = "secondAssetFile";
const char* CompareOutputFileArg = "output";
const char* ComparePrintArg = "print";
const char* IntersectionCountArg = "intersectionCount";
// Bundle Settings
const char* BundleSettingsCommand = "bundleSettings";
const char* BundleSettingsFileArg = "bundleSettingsFile";
const char* OutputBundlePathArg = "outputBundlePath";
const char* BundleVersionArg = "bundleVersion";
const char* MaxBundleSizeArg = "maxSize";
// Bundles
const char* BundlesCommand = "bundles";
// Bundle Seed
const char* BundleSeedCommand = "bundleSeed";
const char* AssetCatalogFilename = "assetcatalog.xml";
char g_cachedEngineRoot[AZ_MAX_PATH_LEN];
const char EngineDirectoryName[] = "Engine";
const char RestrictedDirectoryName[] = "restricted";
const char PlatformsDirectoryName[] = "Platforms";
const char GemsDirectoryName[] = "Gems";
const char GemsAssetsDirectoryName[] = "Assets";
const char GemsSeedFileName[] = "seedList";
const char EngineSeedFileName[] = "SeedAssetList";
namespace Internal
{
const AZ::u32 PlatformFlags_RESTRICTED = aznumeric_cast<AZ::u32>(AzFramework::PlatformFlags::Platform_JASPER | AzFramework::PlatformFlags::Platform_PROVO | AzFramework::PlatformFlags::Platform_SALEM | AzFramework::PlatformFlags::Platform_XENIA);
void AddPlatformSeeds(
AZStd::string rootFolder,
const AZStd::string& rootFolderDisplayName,
AZStd::unordered_map<AZStd::string, AZStd::string>& defaultSeedLists,
AzFramework::PlatformFlags platformFlags)
{
AZ::IO::FixedMaxPath engineRoot(GetEngineRoot());
AZ::IO::FixedMaxPath engineRestrcitedRoot = engineRoot / RestrictedDirectoryName;
AZ::IO::FixedMaxPath inputPath = AZ::IO::FixedMaxPath(rootFolder);
AZ::IO::FixedMaxPath engineLocalPath = inputPath.LexicallyRelative(engineRoot);
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
auto platformsIdxList = AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(platformFlags);
for (const AzFramework::PlatformId& platformId : platformsIdxList)
{
const AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlagFromPlatformIndex(platformId);
const char* platformDirName = AzFramework::PlatformHelper::GetPlatformName(platformId);
AZ::IO::FixedMaxPath platformDirectory;
if (aznumeric_cast<AZ::u32>(platformFlag) & PlatformFlags_RESTRICTED)
{
platformDirectory = engineRestrcitedRoot / platformDirName / engineLocalPath;
}
else
{
platformDirectory = inputPath / PlatformsDirectoryName / platformDirName;
}
if (fileIO->Exists(platformDirectory.c_str()))
{
bool recurse = true;
AZ::Outcome<AZStd::list<AZStd::string>, AZStd::string> result = AzFramework::FileFunc::FindFileList(platformDirectory.String(),
AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(), recurse);
if (result.IsSuccess())
{
AZStd::list<AZStd::string> seedFiles = result.TakeValue();
for (AZStd::string& seedFile : seedFiles)
{
AZStd::string normalizedFilePath = seedFile;
AzFramework::StringFunc::Path::Normalize(seedFile);
defaultSeedLists[seedFile] = AZStd::string::format("%s (%s)", rootFolderDisplayName.c_str(), platformDirName);
}
}
}
}
}
void AddPlatformsDirectorySeeds(
const AZStd::string& rootFolder,
const AZStd::string& rootFolderDisplayName,
AZStd::unordered_map<AZStd::string, AZStd::string>& defaultSeedLists,
AzFramework::PlatformFlags platformFlags)
{
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
AZ_Assert(fileIO, "AZ::IO::FileIOBase must be ready for use.\n");
// Check whether platforms directory exists inside the root, if yes than add
// * All seed files from the platforms directory
// * All platform specific seed files based on the platform flags specified.
AZStd::string platformsDirectory;
AzFramework::StringFunc::Path::Join(rootFolder.c_str(), PlatformsDirectoryName, platformsDirectory);
if (fileIO->Exists(platformsDirectory.c_str()))
{
fileIO->FindFiles(platformsDirectory.c_str(),
AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(),
[&](const char* fileName)
{
AZStd::string normalizedFilePath = fileName;
AzFramework::StringFunc::Path::Normalize(normalizedFilePath);
defaultSeedLists[normalizedFilePath] = rootFolderDisplayName;
return true;
});
}
AddPlatformSeeds(rootFolder, rootFolderDisplayName, defaultSeedLists, platformFlags);
}
}
bool ComputeEngineRoot()
{
if (g_cachedEngineRoot[0])
{
return true;
}
const char* engineRoot = nullptr;
AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot);
if (!engineRoot)
{
AZ_Error(AssetBundler::AppWindowName, false, "Unable to locate engine root.\n");
return false;
}
azstrcpy(g_cachedEngineRoot, AZ_MAX_PATH_LEN, engineRoot);
return true;
}
const char* GetEngineRoot()
{
if (!g_cachedEngineRoot[0])
{
ComputeEngineRoot();
}
return g_cachedEngineRoot;
}
AZ::Outcome<void, AZStd::string> ComputeAssetAliasAndGameName(const AZStd::string& platformIdentifier, const AZStd::string& assetCatalogFile, AZStd::string& assetAlias, AZStd::string& gameName)
{
AZStd::string assetPath;
AZStd::string gameFolder;
if (!ComputeEngineRoot())
{
return AZ::Failure(AZStd::string("Unable to compute engine root.\n"));
}
if (assetCatalogFile.empty())
{
if (gameName.empty())
{
bool checkPlatform = false;
bool result{};
auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName);
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
result = settingsRegistry->Get(gameFolder, gameFolderKey);
}
if (!result)
{
return AZ::Failure(AZStd::string("Unable to locate game name in bootstrap.\n"));
}
gameName = gameFolder;
}
else
{
gameFolder = gameName;
}
// Appending Cache/%gamename%/%platform%/%gameName% to the engine root
bool success = AzFramework::StringFunc::Path::ConstructFull(g_cachedEngineRoot, "Cache", assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), gameFolder.c_str(), assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), platformIdentifier.c_str(), assetPath);
if (success)
{
AZStd::to_lower(gameFolder.begin(), gameFolder.end());
success = AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), gameFolder.c_str(), assetPath); // game name is lowercase
}
if (success)
{
assetAlias = assetPath;
}
}
else if (AzFramework::StringFunc::Path::GetFullPath(assetCatalogFile.c_str(), assetPath))
{
AzFramework::StringFunc::Strip(assetPath, AZ_CORRECT_FILESYSTEM_SEPARATOR, false, false, true);
assetAlias = assetPath;
// 3rd component from reverse should give us the correct case game name because the assetalias directory
// looks like ./Cache/%GameName%/%platform%/%gameName%/assetcatalog.xml
// GetComponent util method returns the component with the separator appended at the end
// therefore we need to strip the separator to get the game name string
gameFolder = AZ::IO::PathView(assetPath).ParentPath().ParentPath().Filename().Native();
if (gameFolder.empty())
{
return AZ::Failure(AZStd::string::format("Unable to retrieve game name from assetCatalog file (%s).\n", assetCatalogFile.c_str()));
}
if (!AzFramework::StringFunc::Strip(gameFolder, AZ_CORRECT_FILESYSTEM_SEPARATOR, false, false, true))
{
return AZ::Failure(AZStd::string::format("Unable to strip separator from game name (%s).\n", gameFolder.c_str()));
}
if (!gameName.empty() && !AzFramework::StringFunc::Equal(gameFolder.c_str(), gameName.c_str()))
{
return AZ::Failure(AZStd::string::format("Game name retrieved from the assetCatalog file (%s) does not match the inputted game name (%s).\n", gameFolder.c_str(), gameName.c_str()));
}
else
{
gameName = gameFolder;
}
}
return AZ::Success();
}
void AddPlatformIdentifier(AZStd::string& filePath, const AZStd::string& platformIdentifier)
{
AZStd::string fileName;
AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName);
AZStd::string extension;
AzFramework::StringFunc::Path::GetExtension(filePath.c_str(), extension);
AZStd::string platformSuffix = AZStd::string::format("_%s", platformIdentifier.c_str());
fileName = AZStd::string::format("%s%s", fileName.c_str(), platformSuffix.c_str());
AzFramework::StringFunc::Path::ReplaceFullName(filePath, fileName.c_str(), extension.c_str());
}
AzFramework::PlatformFlags GetPlatformsOnDiskForPlatformSpecificFile(const AZStd::string& platformIndependentAbsolutePath)
{
AzFramework::PlatformFlags platformFlags = AzFramework::PlatformFlags::Platform_NONE;
auto allPlatformNames = AzFramework::PlatformHelper::GetPlatforms(AzFramework::PlatformFlags::AllNamedPlatforms);
for (const auto& platformName : allPlatformNames)
{
AZStd::string filePath = platformIndependentAbsolutePath;
AddPlatformIdentifier(filePath, platformName);
if (AZ::IO::FileIOBase::GetInstance()->Exists(filePath.c_str()))
{
platformFlags = platformFlags | AzFramework::PlatformHelper::GetPlatformFlag(platformName);
}
}
return platformFlags;
}
AZStd::unordered_map<AZStd::string, AZStd::string> GetDefaultSeedListFiles(const char* root, const char* projectName, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlag)
{
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
AZ_Assert(fileIO, "AZ::IO::FileIOBase must be ready for use.\n");
// Add all seed list files of enabled gems for the given project
AZStd::unordered_map<AZStd::string, AZStd::string> defaultSeedLists = GetGemSeedListFilePathToGemNameMap(gemInfoList, platformFlag);
// Add the engine seed list file
AZStd::string engineDirectory;
AzFramework::StringFunc::Path::Join(root, EngineDirectoryName, engineDirectory);
AZStd::string absoluteEngineSeedFilePath;
AzFramework::StringFunc::Path::ConstructFull(engineDirectory.c_str(), EngineSeedFileName, AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteEngineSeedFilePath, true);
if (fileIO->Exists(absoluteEngineSeedFilePath.c_str()))
{
defaultSeedLists[absoluteEngineSeedFilePath] = EngineDirectoryName;
}
// Add Seed Lists from the Platforms directory
Internal::AddPlatformsDirectorySeeds(engineDirectory, EngineDirectoryName, defaultSeedLists, platformFlag);
AZStd::string absoluteProjectDefaultSeedFilePath;
AzFramework::StringFunc::Path::ConstructFull(root, projectName, EngineSeedFileName, AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteProjectDefaultSeedFilePath, true);
if (fileIO->Exists(absoluteProjectDefaultSeedFilePath.c_str()))
{
defaultSeedLists[absoluteProjectDefaultSeedFilePath] = projectName;
}
return defaultSeedLists;
}
AZStd::vector<AZStd::string> GetDefaultSeeds(const char* root, const char* projectName)
{
AZStd::vector<AZStd::string> defaultSeeds;
defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(root, projectName));
return defaultSeeds;
}
AZStd::string GetProjectDependenciesFile(const char* root, const char* projectName)
{
AZStd::string projectDependenciesFilePath = AZStd::string::format("%s%s", projectName, DependenciesFileSuffix);
AzFramework::StringFunc::Path::ConstructFull(root, projectName, projectDependenciesFilePath.c_str(), DependenciesFileExtension, projectDependenciesFilePath, true);
return projectDependenciesFilePath;
}
AZStd::string GetProjectDependenciesFileTemplate(const char* root)
{
AZStd::string projectDependenciesFileTemplate = ProjectName;
projectDependenciesFileTemplate += DependenciesFileSuffix;
AzFramework::StringFunc::Path::ConstructFull(root, DefaultProjectTemplatePath, projectDependenciesFileTemplate.c_str(), DependenciesFileExtension, projectDependenciesFileTemplate, true);
return projectDependenciesFileTemplate;
}
AZStd::string GetProjectDependenciesAssetPath(const char* root, const char* projectName)
{
AZStd::string projectDependenciesFile = AZStd::move(GetProjectDependenciesFile(root, projectName));
if (!AZ::IO::FileIOBase::GetInstance()->Exists(projectDependenciesFile.c_str()))
{
AZ_TracePrintf(AssetBundler::AppWindowName, "Project dependencies file %s doesn't exist.\n", projectDependenciesFile.c_str());
AZStd::string projectDependenciesFileTemplate = AZStd::move(GetProjectDependenciesFileTemplate(root));
if (AZ::IO::FileIOBase::GetInstance()->Copy(projectDependenciesFileTemplate.c_str(), projectDependenciesFile.c_str()))
{
AZ_TracePrintf(AssetBundler::AppWindowName, "Copied project dependencies file template %s to the current project.\n",
projectDependenciesFile.c_str());
}
else
{
AZ_Error(AppWindowName, false, "Failed to copy project dependencies file template %s from default project"
" template to the current project.\n", projectDependenciesFileTemplate.c_str());
return {};
}
}
// Turn the absolute path into a cache-relative path
AZStd::string relativeProductPath;
AzFramework::StringFunc::Path::GetFullFileName(projectDependenciesFile.c_str(), relativeProductPath);
AZStd::to_lower(relativeProductPath.begin(), relativeProductPath.end());
return relativeProductPath;
}
AZStd::unordered_map<AZStd::string, AZStd::string> GetGemSeedListFilePathToGemNameMap(const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags)
{
AZStd::unordered_map<AZStd::string, AZStd::string> filePathToGemNameMap;
for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : gemInfoList)
{
AZ::IO::Path gemInfoAssetFilePath = gemInfo.m_absoluteFilePath;
gemInfoAssetFilePath /= gemInfo.GetGemAssetFolder();
AZ::IO::Path absoluteGemSeedFilePath = gemInfoAssetFilePath / GemsSeedFileName;
absoluteGemSeedFilePath.ReplaceExtension(AZ::IO::PathView{ AzToolsFramework::AssetSeedManager::GetSeedFileExtension() });
absoluteGemSeedFilePath = absoluteGemSeedFilePath.LexicallyNormal();
AZStd::string gemName = gemInfo.m_gemName + " Gem";
if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteGemSeedFilePath.c_str()))
{
filePathToGemNameMap[absoluteGemSeedFilePath.Native()] = gemName;
}
Internal::AddPlatformsDirectorySeeds(gemInfoAssetFilePath.Native(), gemName, filePathToGemNameMap, platformFlags);
}
return filePathToGemNameMap;
}
bool IsGemSeedFilePathValid(const char* root, AZStd::string seedAbsoluteFilePath, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags)
{
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
AZ_Assert(fileIO, "AZ::IO::FileIOBase must be ready for use.\n");
if (!fileIO->Exists(seedAbsoluteFilePath.c_str()))
{
return false;
}
AZ::IO::Path gemsFolder{ root };
gemsFolder /= GemsDirectoryName;
gemsFolder /= GemsAssetsDirectoryName;
gemsFolder = gemsFolder.LexicallyNormal();
if (!AzFramework::StringFunc::StartsWith(seedAbsoluteFilePath, gemsFolder.Native()))
{
// if we are here it implies that this seed file does not live under the gems directory and
// therefore we do not have to validate it
return true;
}
for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : gemInfoList)
{
// We want to check the path before going through the effort of creating the default Seed List file map
if (!AzFramework::StringFunc::StartsWith(seedAbsoluteFilePath, gemInfo.m_absoluteFilePath))
{
continue;
}
AZStd::unordered_map<AZStd::string, AZStd::string> seeds = GetGemSeedListFilePathToGemNameMap({gemInfo}, platformFlags);
if (seeds.find(seedAbsoluteFilePath) != seeds.end())
{
return true;
}
// If we have not validated the input path yet, we need to keep looking, or we will return false negatives
// for Gems that have the same prefix in their name
}
return false;
}
AzFramework::PlatformFlags GetEnabledPlatformFlags(const char* root, const char* assetRoot, const char* gameName)
{
QStringList configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(root, assetRoot, gameName, true, true);
QStringList enabaledPlatformList = AzToolsFramework::AssetUtils::GetEnabledPlatforms(configFiles);
AzFramework::PlatformFlags platformFlags = AzFramework::PlatformFlags::Platform_NONE;
for (const QString& enabledPlatform : enabaledPlatformList)
{
AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlag(enabledPlatform.toUtf8().data());
if (platformFlag != AzFramework::PlatformFlags::Platform_NONE)
{
platformFlags = platformFlags | platformFlag;
}
else
{
AZ_Warning(AssetBundler::AppWindowName, false, "Platform Helper is not aware of the platform (%s).\n ", enabledPlatform.toUtf8().data());
}
}
return platformFlags;
}
void ValidateOutputFilePath(FilePath filePath, const char* format, ...)
{
if (!filePath.IsValid())
{
char message[MaxErrorMessageLength] = {};
va_list args;
va_start(args, format);
azvsnprintf(message, MaxErrorMessageLength, format, args);
va_end(args);
AZ_Error(AssetBundler::AppWindowName, false, message);
}
}
AZ::Outcome<AZStd::string, AZStd::string> GetCurrentProjectName()
{
AZStd::string gameName;
bool result{ false };
auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName);
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
result = settingsRegistry->Get(gameName, gameFolderKey);
}
if (result)
{
return AZ::Success(gameName);
}
else
{
return AZ::Failure(AZStd::string("Unable to locate current project name in bootstrap.cfg"));
}
}
AZ::Outcome<AZStd::string, AZStd::string> GetProjectFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName)
{
AZStd::string projectFolderPath;
bool success = AzFramework::StringFunc::Path::ConstructFull(engineRoot.c_str(), projectName.c_str(), projectFolderPath);
if (success && AZ::IO::FileIOBase::GetInstance()->Exists(projectFolderPath.c_str()))
{
return AZ::Success(projectFolderPath);
}
else
{
return AZ::Failure(AZStd::string::format( "Unable to locate the current Project folder: %s", projectName.c_str()));
}
}
AZ::Outcome<AZStd::string, AZStd::string> GetProjectCacheFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName)
{
AZStd::string projectCacheFolderPath;
bool success = AzFramework::StringFunc::Path::ConstructFull(engineRoot.c_str(), "Cache", projectCacheFolderPath);
if (!success || !AZ::IO::FileIOBase::GetInstance()->Exists(projectCacheFolderPath.c_str()))
{
return AZ::Failure(AZStd::string::format(
"Unable to locate the Cache in the engine directory: %s. Please run the Lumberyard Asset Processor to generate a Cache and build assets.",
engineRoot.c_str()));
}
success = AzFramework::StringFunc::Path::ConstructFull(projectCacheFolderPath.c_str(), projectName.c_str(), projectCacheFolderPath);
if (success && AZ::IO::FileIOBase::GetInstance()->Exists(projectCacheFolderPath.c_str()))
{
return AZ::Success(projectCacheFolderPath);
}
else
{
return AZ::Failure(AZStd::string::format(
"Unable to locate the current Project in the Cache folder: %s. Please run the Lumberyard Asset Processor to generate a Cache and build assets.",
projectName.c_str()));
}
}
AZ::Outcome<void, AZStd::string> GetPlatformNamesFromCacheFolder(const AZStd::string& projectCacheFolder, AZStd::vector<AZStd::string>& platformNames)
{
QDir projectCacheDir(QString(projectCacheFolder.c_str()));
auto tempPlatformList = projectCacheDir.entryList(QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot);
if (tempPlatformList.empty())
{
return AZ::Failure(AZStd::string("Cache is empty. Please run the Lumberyard Asset Processor to generate a Cache and build assets."));
}
for (const QString& platform : tempPlatformList)
{
platformNames.push_back(AZStd::string(platform.toUtf8().data()));
}
return AZ::Success();
}
AZ::Outcome<AZStd::string, AZStd::string> GetAssetCatalogFilePath(const char* pathToCacheFolder, const char* platformIdentifier, const char* projectName)
{
AZStd::string assetCatalogFilePath;
bool success = AzFramework::StringFunc::Path::ConstructFull(pathToCacheFolder, platformIdentifier, assetCatalogFilePath, true);
if (!success)
{
return AZ::Failure(AZStd::string::format(
"Unable to find platform folder %s in cache found at: %s. Please run the Lumberyard Asset Processor to generate platform-specific cache folders and build assets.",
platformIdentifier,
pathToCacheFolder));
}
// Project name is lower case in the platform-specific cache folder
AZStd::string lowerCaseProjectName = AZStd::string(projectName);
AZStd::to_lower(lowerCaseProjectName.begin(), lowerCaseProjectName.end());
success = AzFramework::StringFunc::Path::ConstructFull(assetCatalogFilePath.c_str(), lowerCaseProjectName.c_str(), assetCatalogFilePath)
&& AzFramework::StringFunc::Path::ConstructFull(assetCatalogFilePath.c_str(), AssetCatalogFilename, assetCatalogFilePath);
if (!success)
{
return AZ::Failure(AZStd::string("Unable to find the asset catalog. Please run the Lumberyard Asset Processor to generate a Cache and build assets."));
}
return AZ::Success(assetCatalogFilePath);
}
AZStd::string GetPlatformSpecificCacheFolderPath(const AZStd::string& projectSpecificCacheFolderAbsolutePath, const AZStd::string& platform, const AZStd::string& projectName)
{
// C:/dev/Cache/ProjectName -> C:/dev/Cache/ProjectName/platform
AZStd::string platformSpecificCacheFolderPath;
AzFramework::StringFunc::Path::ConstructFull(projectSpecificCacheFolderAbsolutePath.c_str(), platform.c_str(), platformSpecificCacheFolderPath, true);
// C:/dev/Cache/ProjectName/platform -> C:/dev/Cache/ProjectName/platform/projectname
AZStd::string lowerCaseProjectName = AZStd::string(projectName);
AZStd::to_lower(lowerCaseProjectName.begin(), lowerCaseProjectName.end());
AzFramework::StringFunc::Path::ConstructFull(platformSpecificCacheFolderPath.c_str(), lowerCaseProjectName.c_str(), platformSpecificCacheFolderPath, true);
return platformSpecificCacheFolderPath;
}
AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath)
{
AZStd::string key(absoluteFilePath);
AzFramework::StringFunc::Path::Normalize(key);
AzFramework::StringFunc::Path::StripDrive(key);
return key;
}
void ConvertToRelativePath(const AZStd::string& parentFolderPath, AZStd::string& absoluteFilePath)
{
// Qt and AZ return different Drive Letter formats, so strip them away before doing a comparison
AZStd::string parentFolderPathWithoutDrive(parentFolderPath);
AzFramework::StringFunc::Path::StripDrive(parentFolderPathWithoutDrive);
AzFramework::StringFunc::Path::Normalize(parentFolderPathWithoutDrive);
AzFramework::StringFunc::Path::StripDrive(absoluteFilePath);
AzFramework::StringFunc::Path::Normalize(absoluteFilePath);
AzFramework::StringFunc::Replace(absoluteFilePath, parentFolderPathWithoutDrive.c_str(), "");
}
AZ::Outcome<void, AZStd::string> MakePath(const AZStd::string& path)
{
// Create the folder if it does not already exist
if (!AZ::IO::FileIOBase::GetInstance()->Exists(path.c_str()))
{
auto result = AZ::IO::FileIOBase::GetInstance()->CreatePath(path.c_str());
if (!result)
{
return AZ::Failure(AZStd::string::format("Path creation failed. Input path: %s \n", path.c_str()));
}
}
return AZ::Success();
}
WarningAbsorber::WarningAbsorber()
{
AZ::Debug::TraceMessageBus::Handler::BusConnect();
}
WarningAbsorber::~WarningAbsorber()
{
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
}
bool WarningAbsorber::OnWarning(const char* window, const char* message)
{
AZ_UNUSED(window);
AZ_UNUSED(message);
return true; // do not forward
}
bool WarningAbsorber::OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message)
{
AZ_UNUSED(window);
AZ_UNUSED(fileName);
AZ_UNUSED(line);
AZ_UNUSED(func);
AZ_UNUSED(message);
return true; // do not forward
}
FilePath::FilePath(const AZStd::string& filePath, AZStd::string platformIdentifier, bool checkFileCase, bool ignoreFileCase)
{
AZStd::string platform = platformIdentifier;
if (!platform.empty())
{
AZStd::string filePlatform = AzToolsFramework::GetPlatformIdentifier(filePath);
if (!filePlatform.empty())
{
// input file path already has a platform, no need to append a platform id
platform = AZStd::string();
if (!AzFramework::StringFunc::Equal(filePlatform.c_str(), platformIdentifier.c_str(), true))
{
// Platform identifier does not match the current platform
return;
}
}
}
if (!filePath.empty())
{
m_validPath = true;
m_originalPath = m_absolutePath = filePath;
AzFramework::StringFunc::Path::Normalize(m_originalPath);
ComputeAbsolutePath(m_absolutePath, platform, checkFileCase, ignoreFileCase);
}
}
FilePath::FilePath(const AZStd::string& filePath, bool checkFileCase, bool ignoreFileCase)
:FilePath(filePath, AZStd::string(), checkFileCase, ignoreFileCase)
{
}
const AZStd::string& FilePath::AbsolutePath() const
{
return m_absolutePath;
}
const AZStd::string& FilePath::OriginalPath() const
{
return m_originalPath;
}
bool FilePath::IsValid() const
{
return m_validPath;
}
AZStd::string FilePath::ErrorString() const
{
return m_errorString;
}
void FilePath::ComputeAbsolutePath(AZStd::string& filePath, const AZStd::string& platformIdentifier, bool checkFileCase, bool ignoreFileCase)
{
if (AzToolsFramework::AssetFileInfoListComparison::IsTokenFile(filePath))
{
return;
}
if (!platformIdentifier.empty())
{
AssetBundler::AddPlatformIdentifier(filePath, platformIdentifier);
}
const char* appRoot = nullptr;
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot);
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
AZStd::string driveString;
AzFramework::StringFunc::Path::GetDrive(appRoot, driveString);
if (AzFramework::StringFunc::FirstCharacter(filePath.c_str()) == AZ_CORRECT_FILESYSTEM_SEPARATOR)
{
AzFramework::StringFunc::Path::ConstructFull(driveString.c_str(), filePath.c_str(), filePath, true);
}
#endif
if (!AzFramework::StringFunc::Path::IsRelative(filePath.c_str()))
{
// it is already an absolute path
AzFramework::StringFunc::Path::Normalize(filePath);
}
else
{
AzFramework::StringFunc::Path::ConstructFull(appRoot, m_absolutePath.c_str(), m_absolutePath, true);
}
if (checkFileCase)
{
QDir rootDir(appRoot);
QString relFilePath = rootDir.relativeFilePath(m_absolutePath.c_str());
if (AzToolsFramework::AssetUtils::UpdateFilePathToCorrectCase(QString(appRoot), relFilePath))
{
if (ignoreFileCase)
{
AzFramework::StringFunc::Path::ConstructFull(appRoot, relFilePath.toUtf8().data(), m_absolutePath, true);
}
else
{
AZStd::string absfilePath(rootDir.filePath(relFilePath).toUtf8().data());
AzFramework::StringFunc::Path::Normalize(absfilePath);
if (!AZ::StringFunc::Equal(absfilePath.c_str(), m_absolutePath.c_str(), true))
{
m_errorString = AZStd::string::format("File case mismatch, file ( %s ) does not exist on disk, did you mean file ( %s ). \
Please run the command again with the correct file path or use ( --%s ) arg if you want to allow case insensitive file match.\n",
m_absolutePath.c_str(), rootDir.filePath(relFilePath.toUtf8().data()).toUtf8().data(), IgnoreFileCaseFlag);
m_validPath = false;
}
}
}
}
}
ScopedTraceHandler::ScopedTraceHandler()
{
BusConnect();
}
ScopedTraceHandler::~ScopedTraceHandler()
{
BusDisconnect();
}
bool ScopedTraceHandler::OnError(const char* window, const char* message)
{
AZ_UNUSED(window);
if (m_reportingError)
{
// if we are reporting error than we dont want to store errors again.
return false;
}
m_errors.emplace_back(message);
return true;
}
int ScopedTraceHandler::GetErrorCount() const
{
return static_cast<int>(m_errors.size());
}
void ScopedTraceHandler::ReportErrors()
{
m_reportingError = true;
for (const AZStd::string& error : m_errors)
{
AZ_Error(AssetBundler::AppWindowName, false, error.c_str());
}
ClearErrors();
m_reportingError = false;
}
void ScopedTraceHandler::ClearErrors()
{
m_errors.clear();
m_errors.swap(AZStd::vector<AZStd::string>());
}
AZ::Outcome<AzToolsFramework::AssetFileInfoListComparison::ComparisonType, AZStd::string> ParseComparisonType(const AZStd::string& comparisonType)
{
using namespace AzToolsFramework;
const size_t numTypes = AZ_ARRAY_SIZE(AssetFileInfoListComparison::ComparisonTypeNames);
int comparisonTypeIndex = 0;
if (AzFramework::StringFunc::LooksLikeInt(comparisonType.c_str(), &comparisonTypeIndex))
{
// User passed in a number
if (comparisonTypeIndex < numTypes)
{
return AZ::Success(static_cast<AssetFileInfoListComparison::ComparisonType>(comparisonTypeIndex));
}
}
else
{
// User passed in the name of a ComparisonType
for (size_t i = 0; i < numTypes; ++i)
{
if (AzFramework::StringFunc::Equal(comparisonType.c_str(), AssetFileInfoListComparison::ComparisonTypeNames[i]))
{
return AZ::Success(static_cast<AssetFileInfoListComparison::ComparisonType>(i));
}
}
}
// Failure case
AZStd::string failureMessage = AZStd::string::format("Invalid Comparison Type ( %s ). Valid types are: ", comparisonType.c_str());
for (size_t i = 0; i < numTypes - 1; ++i)
{
failureMessage.append(AZStd::string::format("%s, ", AssetFileInfoListComparison::ComparisonTypeNames[i]));
}
failureMessage.append(AZStd::string::format("and %s.", AssetFileInfoListComparison::ComparisonTypeNames[numTypes - 1]));
return AZ::Failure(failureMessage);
}
AZ::Outcome<AzToolsFramework::AssetFileInfoListComparison::FilePatternType, AZStd::string> ParseFilePatternType(const AZStd::string& filePatternType)
{
using namespace AzToolsFramework;
const size_t numTypes = AZ_ARRAY_SIZE(AssetFileInfoListComparison::FilePatternTypeNames);
int filePatternTypeIndex = 0;
if (AzFramework::StringFunc::LooksLikeInt(filePatternType.c_str(), &filePatternTypeIndex))
{
// User passed in a number
if (filePatternTypeIndex < numTypes)
{
return AZ::Success(static_cast<AssetFileInfoListComparison::FilePatternType>(filePatternTypeIndex));
}
}
else
{
// User passed in the name of a FilePatternType
for (size_t i = 0; i < numTypes; ++i)
{
if (AzFramework::StringFunc::Equal(filePatternType.c_str(), AssetFileInfoListComparison::FilePatternTypeNames[i]))
{
return AZ::Success(static_cast<AssetFileInfoListComparison::FilePatternType>(i));
}
}
}
// Failure case
AZStd::string failureMessage = AZStd::string::format("Invalid File Pattern Type ( %s ). Valid types are: ", filePatternType.c_str());
for (size_t i = 0; i < numTypes - 1; ++i)
{
failureMessage.append(AZStd::string::format("%s, ", AssetFileInfoListComparison::FilePatternTypeNames[i]));
}
failureMessage.append(AZStd::string::format("and %s.", AssetFileInfoListComparison::FilePatternTypeNames[numTypes - 1]));
return AZ::Failure(failureMessage);
}
bool LooksLikePath(const AZStd::string& inputString)
{
for (auto thisChar : inputString)
{
if (thisChar == '.' || thisChar == AZ_CORRECT_FILESYSTEM_SEPARATOR || thisChar == AZ_WRONG_FILESYSTEM_SEPARATOR)
{
return true;
}
}
return false;
}
bool LooksLikeWildcardPattern(const AZStd::string& inputPattern)
{
for (auto thisChar : inputPattern)
{
if (thisChar == '*' || thisChar == '?')
{
return true;
}
}
return false;
}
}
@@ -0,0 +1,309 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/std/string/string.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzCore/IO/SystemFile.h> //AZ_MAX_PATH_LEN
#include <AzCore/Outcome/Outcome.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
#include <AzToolsFramework/Asset/AssetUtils.h>
namespace AssetBundler
{
enum CommandType
{
Invalid,
Seeds,
AssetLists,
ComparisonRules,
Compare,
BundleSettings,
Bundles,
BundleSeed
};
////////////////////////////////////////////////////////////////////////////////////////////
// General
extern const char* AppWindowName;
extern const char* AppWindowNameVerbose;
extern const char* HelpFlag;
extern const char* HelpFlagAlias;
extern const char* VerboseFlag;
extern const char* SaveFlag;
extern const char* PlatformArg;
extern const char* PrintFlag;
extern const char* AssetCatalogFileArg;
extern const char* AllowOverwritesFlag;
extern const char* IgnoreFileCaseFlag;
extern const char* ProjectArg;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Seeds
extern const char* SeedsCommand;
extern const char* SeedListFileArg;
extern const char* AddSeedArg;
extern const char* RemoveSeedArg;
extern const char* AddPlatformToAllSeedsFlag;
extern const char* RemovePlatformFromAllSeedsFlag;
extern const char* UpdateSeedPathArg;
extern const char* RemoveSeedPathArg;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Asset Lists
extern const char* AssetListsCommand;
extern const char* AssetListFileArg;
extern const char* AddDefaultSeedListFilesFlag;
extern const char* DryRunFlag;
extern const char* GenerateDebugFileFlag;
extern const char* SkipArg;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Comparison Rules
extern const char* ComparisonRulesCommand;
extern const char* ComparisonRulesFileArg;
extern const char* ComparisonTypeArg;
extern const char* ComparisonFilePatternArg;
extern const char* ComparisonFilePatternTypeArg;
extern const char* ComparisonTokenNameArg;
extern const char* ComparisonFirstInputArg;
extern const char* ComparisonSecondInputArg;
extern const char* AddComparisonStepArg;
extern const char* RemoveComparisonStepArg;
extern const char* MoveComparisonStepArg;
extern const char* EditComparisonStepArg;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Compare
extern const char* CompareCommand;
extern const char* CompareFirstFileArg;
extern const char* CompareSecondFileArg;
extern const char* CompareOutputFileArg;
extern const char* ComparePrintArg;
extern const char* IntersectionCountArg;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Bundle Settings
extern const char* BundleSettingsCommand;
extern const char* BundleSettingsFileArg;
extern const char* OutputBundlePathArg;
extern const char* BundleVersionArg;
extern const char* MaxBundleSizeArg;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Bundles
extern const char* BundlesCommand;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Bundle Seed
extern const char* BundleSeedCommand;
////////////////////////////////////////////////////////////////////////////////////////////
extern const char* AssetCatalogFilename;
extern char g_cachedEngineRoot[AZ_MAX_PATH_LEN];
static const size_t MaxErrorMessageLength = 4096;
//! This struct stores gem related information
struct GemInfo
{
AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0);
GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath);
GemInfo() = default;
AZStd::string m_gemName;
AZStd::string m_relativeFilePath;
AZStd::string m_absoluteFilePath;
};
// The Warning Absorber is used to absorb warnings
// One case that this is being used is during loading of the asset catalog.
// During loading the asset catalog tries to communicate to the AP which is not required for this application.
class WarningAbsorber
: public AZ::Debug::TraceMessageBus::Handler
{
public:
WarningAbsorber();
~WarningAbsorber();
bool OnWarning(const char* window, const char* message) override;
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
};
// computes the asset alias and game name either through the asset catalog file provided by the user or using the platform and game folder
AZ::Outcome<void, AZStd::string> ComputeAssetAliasAndGameName(const AZStd::string& platformIdentifier, const AZStd::string& assetCatalogFile, AZStd::string& assetAlias, AZStd::string& gameName);
// Computes the engine root and cache it locally
bool ComputeEngineRoot();
// Retrurns the engine root
const char* GetEngineRoot();
/**
* Determines the name of the currently enabled game project
* @return Current Project name on success, error message on failure
*/
AZ::Outcome<AZStd::string, AZStd::string> GetCurrentProjectName();
/**
* Constructs an absolute path to the project folder found at: dev/ProjectName
* @param engineRoot The absolute path of the dev/ folder
* @param projectName A project present in the dev/ folder
* @return Absolute path of the Project Folder on success, error message on failure
*/
AZ::Outcome<AZStd::string, AZStd::string> GetProjectFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName);
/**
* Constructs an absolute path to the project-specific cache folder found at: dev/Cache/ProjectName
* @param engineRoot The absolute path of the dev/ folder
* @param projectName A project present in the dev/ folder
* @return Absolute path of the project-specific cache folder on success, error message on failure
*/
AZ::Outcome<AZStd::string, AZStd::string> GetProjectCacheFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName);
/**
* Calculates the list of enabled platforms for the input project by reading the folder names inside the project-specific cache folder.
* If the Asset Processor has not been run yet, or has not been run since the enabled platform list inside AssetProcessorPlatformConfig.ini
* was changed, the output of this function will be incorrect.
*
* @param projectCacheFolder The directory of a project-specific cache folder: dev/Cache/ProjectName
* @param platformNames [out] The list of platforms enabled in the project
* @return void on success, error message on failure
*/
AZ::Outcome<void, AZStd::string> GetPlatformNamesFromCacheFolder(const AZStd::string& projectCacheFolder, AZStd::vector<AZStd::string>& platformNames);
/**
* Computes the absolute path to the Asset Catalog file for a specified project and platform.
* With platform set as "pc" and project as "ProjectName", the path will resemble: C:/dev/Cache/ProjectName/pc/projectname/assetcatalog.xml
*
* @param pathToCacheFolder The absolute path to the Cache folder. ex: C:/dev/Cache
* @param platformIdentifier The platform identifier of the desired Asset Catalog. Valid inputs can be found by reading the folder names
* found inside dev/Cache/ProjectName
* @param projectName The name of the project you want to search
* @return Absolute Path to the Asset Catalog file on success, error message on failure
*/
AZ::Outcome<AZStd::string, AZStd::string> GetAssetCatalogFilePath(const char* pathToCacheFolder, const char* platformIdentifier, const char* projectName);
/**
* Computes the absolute path to the platform-specific Cache folder where product assets are stored.
* With platform set as "pc" and project as "ProjectName", the path will resemble: C:/dev/Cache/ProjectName/pc/projectname/
*
* @param projectSpecificCacheFolderAbsolutePath The absolute path to the Cache folder. Example: C:/dev/Cache/ProjectName
* @param platform the platform of the desired cache location
* @param projectName The name of the current project
* @return Absolute path to the platform-specific Cache folder where product assets are stored
*/
AZStd::string GetPlatformSpecificCacheFolderPath(const AZStd::string& projectSpecificCacheFolderAbsolutePath, const AZStd::string& platform, const AZStd::string& projectName);
AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath);
void ConvertToRelativePath(const AZStd::string& parentFolderPath, AZStd::string& absoluteFilePath);
AZ::Outcome<void, AZStd::string> MakePath(const AZStd::string& path);
//! Add the specified platform identifier to the filename
void AddPlatformIdentifier(AZStd::string& filePath, const AZStd::string& platformIdentifier);
//! Returns the list of platforms that exist on-disk for the input file path.
AzFramework::PlatformFlags GetPlatformsOnDiskForPlatformSpecificFile(const AZStd::string& platformIndependentAbsolutePath);
//! Returns a map of <absolute file path, source folder display name> of all default Seed List files for the current game project.
AZStd::unordered_map<AZStd::string, AZStd::string> GetDefaultSeedListFiles(const char* root, const char* projectName, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
//! Returns a vector of relative paths to Assets that should be included as default Seeds, but are not already in a Seed List file.
AZStd::vector<AZStd::string> GetDefaultSeeds(const char* root, const char* projectName);
//! Returns the absolute path of {ProjectName}_Dependencies.xml
AZStd::string GetProjectDependenciesFile(const char* root, const char* projectName);
//! Returns the absolute path of the project dependencies file in the default project template
AZStd::string GetProjectDependenciesFileTemplate(const char* root);
//! Creates the ProjectName_Dependencies.xml file if it does not exist, and adds returns the relative path to the asset in the Cache.
AZStd::string GetProjectDependenciesAssetPath(const char* root, const char* projectName);
//! Returns the map from gem seed list file path to gem name
AZStd::unordered_map<AZStd::string, AZStd::string> GetGemSeedListFilePathToGemNameMap(const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
//! Given an absolute gem seed file path determines whether the file is valid for the current game project.
//! This method is for validating gem seed list files only.
bool IsGemSeedFilePathValid(const char* root, AZStd::string seedAbsoluteFilePath, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
//! Returns platformFlags of all enabled platforms by parsing all the asset processor config files.
//! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param.
AzFramework::PlatformFlags GetEnabledPlatformFlags(const char* root, const char* assetRoot, const char* gameName);
//! Filepath is a helper class that is used to find the absolute path of a file
//! if the inputted file path is an absolute path than it does nothing
//! if the inputted file path is a relative path than based on whether the user
//! also inputted a root directory it computes the absolute path,
//! if root directory is provided it uses that otherwise it uses the engine root as the default root folder.
class FilePath
{
public:
AZ_CLASS_ALLOCATOR(FilePath, AZ::SystemAllocator, 0);
explicit FilePath(const AZStd::string& filePath, AZStd::string platformIdentifier = AZStd::string(), bool checkFileCase = false, bool ignoreFileCase = false);
explicit FilePath(const AZStd::string& filePath, bool checkFileCase, bool ignoreFileCase);
FilePath() = default;
const AZStd::string& AbsolutePath() const;
const AZStd::string& OriginalPath() const;
AZStd::string ErrorString() const;
bool IsValid() const;
private:
void ComputeAbsolutePath(AZStd::string& filePath, const AZStd::string& platformIdentifier, bool checkFileCase, bool ignoreFileCase);
AZStd::string m_absolutePath;
AZStd::string m_originalPath;
AZStd::string m_errorString;
bool m_validPath = false;
};
void ValidateOutputFilePath(FilePath filePath, const char* format, ...);
//! ScopedTraceHandler can be used to handle and report errors
class ScopedTraceHandler : public AZ::Debug::TraceMessageBus::Handler
{
public:
ScopedTraceHandler();
~ScopedTraceHandler();
//! TraceMessageBus Interface
bool OnError(const char* /*window*/, const char* /*message*/) override;
//////////////////////////////////////////////////////////
//! Returns the error count
int GetErrorCount() const;
//! Report all the errors
void ReportErrors();
//! Clear all the errors
void ClearErrors();
private:
AZStd::vector<AZStd::string> m_errors;
bool m_reportingError = false;
};
AZ::Outcome<AzToolsFramework::AssetFileInfoListComparison::ComparisonType, AZStd::string> ParseComparisonType(const AZStd::string& comparisonType);
AZ::Outcome<AzToolsFramework::AssetFileInfoListComparison::FilePatternType, AZStd::string> ParseFilePatternType(const AZStd::string& filePatternType);
bool LooksLikePath(const AZStd::string& inputString);
bool LooksLikeWildcardPattern(const AZStd::string& inputPattern);
}
@@ -0,0 +1,10 @@
[Platforms]
;pc=enabled
es3=enabled
;ios=enabled
;osx_gl=enabled
;xenia=enabled
;provo=enabled
;server=enabled
@@ -0,0 +1,8 @@
[Platforms]
;pc=enabled
;es3=enabled
ios=enabled
;osx_gl=enabled
;xenia=enabled
;provo=enabled
;server=enabled
@@ -0,0 +1,4 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}"/>
</ObjectStream>
@@ -0,0 +1,25 @@
{
"GemListFormatVersion": 2,
"Gems": [
{
"Path": "Gems/GemA",
"Uuid": "044a63ea67d04479aa5daf62ded9d9cb",
"Version": "0.1.0",
"_comment": "GemA"
},
{
"Path": "Gems/GemB",
"Uuid": "07375b61b1a2424bb03088bbdf28b2c9",
"Version": "0.1.0",
"_comment": "GemB"
},
{
"Path": "Gems/GemC",
"Uuid": "0945e21b7ae848ac80b4ec1f34c459cd",
"Version": "0.1.0",
"_comment": "GemC"
}
]
}
@@ -0,0 +1,14 @@
{
"project_name": "DummyProject",
"product_name": "DummyProject",
"executable_name": "DummyProjectLauncher",
"modules" : [],
"project_id": "{91FB81A1-072C-4A80-8FCC-7E2C4C767B4D}",
"android_settings" : {
"package_name" : "com.lumberyard.yourgame",
"version_number" : 1,
"version_name" : "1.0.0.0",
"orientation" : "landscape"
}
}
@@ -0,0 +1,5 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
</Class>
</ObjectStream>
@@ -0,0 +1,10 @@
[Platforms]
;pc=enabled
;es3=enabled
;ios=enabled
;osx_gl=enabled
;xenia=enabled
provo=enabled
;server=enabled
@@ -0,0 +1,5 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
</Class>
</ObjectStream>
@@ -0,0 +1,11 @@
{
"GemFormatVersion": 4,
"Uuid": "044A63EA67D04479AA5DAF62DED9D9CB",
"Name": "GemA",
"DisplayName": "GemA",
"Version": "0.1.0",
"Summary": "Only for unit test purposes.",
"Tags": ["Foo"],
"IconPath": "preview.png",
"EditorModule": true
}
@@ -0,0 +1,5 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
</Class>
</ObjectStream>
@@ -0,0 +1,5 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
</Class>
</ObjectStream>
@@ -0,0 +1,5 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
</Class>
</ObjectStream>
@@ -0,0 +1,11 @@
{
"GemFormatVersion": 4,
"Uuid": "07375B61B1A2424BB03088BBDF28B2C9",
"Name": "GemB",
"DisplayName": "GemB",
"Version": "0.1.0",
"Summary": "Only for unit test purposes.",
"Tags": ["Foo"],
"IconPath": "preview.png",
"EditorModule": true
}
@@ -0,0 +1,11 @@
{
"GemFormatVersion": 4,
"Uuid": "0945E21B7AE848AC80B4EC1F34C459CD",
"Name": "GemC",
"DisplayName": "GemC",
"Version": "0.1.0",
"Summary": "Only for unit test purposes.",
"Tags": ["Foo"],
"IconPath": "preview.png",
"EditorModule": true
}
@@ -0,0 +1,147 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/API/ApplicationAPI.h>
#include <source/utils/utils.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <Utils/Utils.h>
#include <AzFramework/IO/LocalFileIO.h>
namespace AssetBundler
{
class MockUtilsTest
: public UnitTest::ScopedAllocatorSetupFixture
, public AzFramework::ApplicationRequests::Bus::Handler
{
public:
void SetUp() override
{
ScopedAllocatorSetupFixture::SetUp();
AzFramework::ApplicationRequests::Bus::Handler::BusConnect();
m_localFileIO = aznew AZ::IO::LocalFileIO();
m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
// we need to set it to nullptr first because otherwise the
// underneath code assumes that we might be leaking the previous instance
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_localFileIO);
m_tempDir = new UnitTest::ScopedTemporaryDirectory();
}
void TearDown() override
{
delete m_tempDir;
AZ::IO::FileIOBase::SetInstance(nullptr);
delete m_localFileIO;
AZ::IO::FileIOBase::SetInstance(m_priorFileIO);
AzFramework::ApplicationRequests::Bus::Handler::BusDisconnect();
ScopedAllocatorSetupFixture::TearDown();
}
// AzFramework::ApplicationRequests::Bus::Handler interface
void NormalizePath(AZStd::string& /*path*/) override {}
void NormalizePathKeepCase(AZStd::string& /*path*/) override {}
void CalculateBranchTokenForAppRoot(AZStd::string& /*token*/) const override {}
const char* GetAppRoot() const override
{
return m_tempDir->GetDirectory();
}
AZ::IO::FileIOBase* m_priorFileIO = nullptr;
AZ::IO::FileIOBase* m_localFileIO = nullptr;
UnitTest::ScopedTemporaryDirectory* m_tempDir = nullptr;
};
TEST_F(MockUtilsTest, DISABLED_TestFilePath_StartsWithAFileSeparator_Valid)
{
AZStd::string relFilePath = "Foo/foo.xml";
AzFramework::StringFunc::Prepend(relFilePath, AZ_CORRECT_FILESYSTEM_SEPARATOR);
AZStd::string absoluteFilePath;
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
AZStd::string driveString;
AzFramework::StringFunc::Path::GetDrive(GetAppRoot(), driveString);
AzFramework::StringFunc::Path::ConstructFull(driveString.c_str(), relFilePath.c_str(), absoluteFilePath, true);
#else
absoluteFilePath = relFilePath;
#endif
FilePath filePath(relFilePath);
EXPECT_STREQ(filePath.AbsolutePath().c_str(), absoluteFilePath.c_str());
}
TEST_F(MockUtilsTest, TestFilePath_RelativePath_Valid)
{
AZStd::string relFilePath = "Foo\\foo.xml";
AZStd::string absoluteFilePath;
AzFramework::StringFunc::Path::ConstructFull(GetAppRoot(), relFilePath.c_str(), absoluteFilePath, true);
FilePath filePath(relFilePath);
EXPECT_EQ(filePath.AbsolutePath(), absoluteFilePath);
}
TEST_F(MockUtilsTest, TestFilePath_CasingMismatch_Error_valid)
{
AZStd::string relFilePath = "Foo\\Foo.xml";
AZStd::string wrongCaseRelFilePath = "Foo\\foo.xml";
AZStd::string correctAbsoluteFilePath;
AZStd::string wrongCaseAbsoluteFilePath;
AzFramework::StringFunc::Path::ConstructFull(GetAppRoot(), relFilePath.c_str(), correctAbsoluteFilePath, true);
AzFramework::StringFunc::Path::ConstructFull(GetAppRoot(), wrongCaseRelFilePath.c_str(), wrongCaseAbsoluteFilePath, true);
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ::IO::FileIOBase::GetInstance()->Open(correctAbsoluteFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath, fileHandle);
FilePath filePath(wrongCaseAbsoluteFilePath, true, false);
EXPECT_FALSE(filePath.IsValid());
EXPECT_TRUE(filePath.ErrorString().find("File case mismatch") != AZStd::string::npos);
}
TEST_F(MockUtilsTest, TestFilePath_NoFileExists_NoError_valid)
{
AZStd::string relFilePath = "Foo\\Foo.xml";
AZStd::string absoluteFilePath;
AzFramework::StringFunc::Path::ConstructFull(GetAppRoot(), relFilePath.c_str(), absoluteFilePath, true);
FilePath filePath(absoluteFilePath, true, false);
EXPECT_TRUE(filePath.IsValid());
EXPECT_TRUE(filePath.ErrorString().empty());
}
TEST_F(MockUtilsTest, TestFilePath_CasingMismatch_Ignore_Filecase_valid)
{
AZStd::string relFilePath = "Foo\\Foo.xml";
AZStd::string wrongCaseRelFilePath = "Foo\\foo.xml";
AZStd::string correctAbsoluteFilePath;
AZStd::string wrongCaseAbsoluteFilePath;
AzFramework::StringFunc::Path::ConstructFull(GetAppRoot(), relFilePath.c_str(), correctAbsoluteFilePath, true);
AzFramework::StringFunc::Path::ConstructFull(GetAppRoot(), wrongCaseRelFilePath.c_str(), wrongCaseAbsoluteFilePath, true);
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ::IO::FileIOBase::GetInstance()->Open(correctAbsoluteFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath, fileHandle);
FilePath filePath(wrongCaseAbsoluteFilePath, true, true);
EXPECT_TRUE(filePath.IsValid());
EXPECT_STREQ(filePath.AbsolutePath().c_str(), correctAbsoluteFilePath.c_str());
}
TEST_F(MockUtilsTest, LooksLikeWildcardPattern_IsWildcardPattern_ExpectTrue)
{
EXPECT_TRUE(LooksLikeWildcardPattern("*"));
EXPECT_TRUE(LooksLikeWildcardPattern("?"));
EXPECT_TRUE(LooksLikeWildcardPattern("*/*"));
EXPECT_TRUE(LooksLikeWildcardPattern("*/test?/*.xml"));
}
TEST_F(MockUtilsTest, LooksLikeWildcardPattern_IsNotWildcardPattern_ExpectFalse)
{
EXPECT_FALSE(LooksLikeWildcardPattern(""));
EXPECT_FALSE(LooksLikeWildcardPattern("test"));
EXPECT_FALSE(LooksLikeWildcardPattern("test/path.xml"));
}
}
@@ -0,0 +1,240 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <source/utils/utils.h>
#include <source/utils/applicationManager.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <tests/main.h>
namespace AssetBundler
{
const char DummyProjectName[] = "DummyProject";
class MockApplicationManagerTest
: public AssetBundler::ApplicationManager
{
public:
friend class GTEST_TEST_CLASS_NAME_(ApplicationManagerTest, ValidatePlatformFlags_ReadConfigFiles_OK);
explicit MockApplicationManagerTest(int* argc, char*** argv)
: ApplicationManager(argc, argv)
{
}
};
class BasicApplicationManagerTest
: public UnitTest::ScopedAllocatorSetupFixture
{
};
class ApplicationManagerTest
: public UnitTest::ScopedAllocatorSetupFixture
{
public:
void SetUp() override
{
UnitTest::ScopedAllocatorSetupFixture::SetUp();
m_data = AZStd::make_unique<StaticData>();
m_data->m_applicationManager.reset(aznew MockApplicationManagerTest(0, 0));
m_data->m_applicationManager->Start(AzFramework::Application::Descriptor());
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
const char* engineRoot = nullptr;
AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot);
ASSERT_TRUE(engineRoot) << "Unable to locate engine root.\n";
AzFramework::StringFunc::Path::Join(engineRoot, RelativeTestFolder, m_data->m_testEngineRoot);
m_data->m_localFileIO = aznew AZ::IO::LocalFileIO();
m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
// we need to set it to nullptr first because otherwise the
// underneath code assumes that we might be leaking the previous instance
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO);
}
void TearDown() override
{
AZ::IO::FileIOBase::SetInstance(nullptr);
delete m_data->m_localFileIO;
AZ::IO::FileIOBase::SetInstance(m_data->m_priorFileIO);
m_data->m_applicationManager->Stop();
m_data->m_applicationManager.reset();
m_data.reset();
UnitTest::ScopedAllocatorSetupFixture::TearDown();
}
struct StaticData
{
AZStd::unique_ptr<MockApplicationManagerTest> m_applicationManager = {};
AZ::IO::FileIOBase* m_priorFileIO = nullptr;
AZ::IO::FileIOBase* m_localFileIO = nullptr;
AZStd::string m_testEngineRoot;
};
AZStd::unique_ptr<StaticData> m_data;
};
TEST_F(ApplicationManagerTest, ValidatePlatformFlags_ReadConfigFiles_OK)
{
AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
ASSERT_NE(nullptr, settingsRegistry);
AZStd::unordered_set<AZStd::string> gemsNameMap{ "GemA", "GemB", "GemC" };
for (AZStd::string& gemName : gemsNameMap)
{
auto gemSourcePathKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/Gems/%s/SourcePaths/0",
AZ::SettingsRegistryMergeUtils::OrganizationRootKey, gemName.c_str());
auto gemSourcePath = AZ::IO::Path(m_data->m_testEngineRoot) / "Gems" / gemName;
settingsRegistry->Set(gemSourcePathKey, gemSourcePath.Native());
}
AzToolsFramework::AssetUtils::GetGemsInfo(m_data->m_testEngineRoot.c_str(), m_data->m_testEngineRoot.c_str(), DummyProjectName, m_data->m_applicationManager->m_gemInfoList);
EXPECT_GE(m_data->m_applicationManager->m_gemInfoList.size(), 3);
for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : m_data->m_applicationManager->m_gemInfoList)
{
gemsNameMap.erase(gemInfo.m_gemName);
}
EXPECT_EQ(0, gemsNameMap.size());
AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(m_data->m_testEngineRoot.c_str(), m_data->m_testEngineRoot.c_str(), DummyProjectName);
AzFramework::PlatformFlags hostPlatformFlag = AzFramework::PlatformHelper::GetPlatformFlag(AzToolsFramework::AssetSystem::GetHostAssetPlatform());
AzFramework::PlatformFlags expectedFlags = AzFramework::PlatformFlags::Platform_ES3 | AzFramework::PlatformFlags::Platform_IOS | AzFramework::PlatformFlags::Platform_PROVO | hostPlatformFlag;
ASSERT_EQ(platformFlags, expectedFlags);
}
TEST_F(BasicApplicationManagerTest, ComputeComparisonTypeFromString_InvalidString_Fails)
{
auto invalidResult = AssetBundler::ParseComparisonType("notacomparisontype");
EXPECT_EQ(invalidResult.IsSuccess(), false);
}
TEST_F(BasicApplicationManagerTest, ComputeComparisonTypeFromString_ValidString_Success)
{
using namespace AzToolsFramework;
auto deltaResult = AssetBundler::ParseComparisonType(AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::Delta)]);
EXPECT_EQ(deltaResult.IsSuccess(), true);
EXPECT_EQ(deltaResult.GetValue(), AssetFileInfoListComparison::ComparisonType::Delta);
auto unionResult = AssetBundler::ParseComparisonType(AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::Union)]);
EXPECT_EQ(unionResult.IsSuccess(), true);
EXPECT_EQ(unionResult.GetValue(), AssetFileInfoListComparison::ComparisonType::Union);
auto intersectionResult = AssetBundler::ParseComparisonType(AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::Intersection)]);
EXPECT_EQ(intersectionResult.IsSuccess(), true);
EXPECT_EQ(intersectionResult.GetValue(), AssetFileInfoListComparison::ComparisonType::Intersection);
auto complementResult = AssetBundler::ParseComparisonType(AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::Complement)]);
EXPECT_EQ(complementResult.IsSuccess(), true);
EXPECT_EQ(complementResult.GetValue(), AssetFileInfoListComparison::ComparisonType::Complement);
auto filePatternResult = AssetBundler::ParseComparisonType(AssetFileInfoListComparison::ComparisonTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::ComparisonType::FilePattern)]);
EXPECT_EQ(filePatternResult.IsSuccess(), true);
EXPECT_EQ(filePatternResult.GetValue(), AssetFileInfoListComparison::ComparisonType::FilePattern);
}
TEST_F(BasicApplicationManagerTest, ComputeComparisonTypeFromInt_InvalidInt_Fails)
{
auto invalidResult = AssetBundler::ParseComparisonType("999");
EXPECT_EQ(invalidResult.IsSuccess(), false);
}
TEST_F(BasicApplicationManagerTest, ComputeComparisonTypeFromInt_ValidInt_Success)
{
int unionIndex(aznumeric_cast<int>(AzToolsFramework::AssetFileInfoListComparison::ComparisonType::Union));
auto unionResult = AssetBundler::ParseComparisonType(AZStd::string::format("%i", unionIndex));
EXPECT_TRUE(unionResult.IsSuccess());
EXPECT_EQ(unionResult.GetValue(), AzToolsFramework::AssetFileInfoListComparison::ComparisonType::Union);
}
TEST_F(BasicApplicationManagerTest, ComputeFilePatternTypeFromString_InvalidString_Fails)
{
auto invalidResult = AssetBundler::ParseFilePatternType("notafilepatterntype");
EXPECT_EQ(invalidResult.IsSuccess(), false);
}
TEST_F(BasicApplicationManagerTest, ComputeFilePatternTypeFromString_ValidString_Success)
{
using namespace AzToolsFramework;
auto wildcardResult = AssetBundler::ParseFilePatternType(AssetFileInfoListComparison::FilePatternTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::FilePatternType::Wildcard)]);
EXPECT_TRUE(wildcardResult.IsSuccess());
EXPECT_EQ(wildcardResult.GetValue(), AssetFileInfoListComparison::FilePatternType::Wildcard);
auto regexResult = AssetBundler::ParseFilePatternType(AssetFileInfoListComparison::FilePatternTypeNames[aznumeric_cast<AZ::u8>(AssetFileInfoListComparison::FilePatternType::Regex)]);
EXPECT_TRUE(regexResult.IsSuccess());
EXPECT_EQ(regexResult.GetValue(), AssetFileInfoListComparison::FilePatternType::Regex);
}
TEST_F(BasicApplicationManagerTest, ComputeFilePatternTypeFromInt_InvalidInt_Fails)
{
auto invalidResult = AssetBundler::ParseFilePatternType("555");
EXPECT_EQ(invalidResult.IsSuccess(), false);
}
TEST_F(BasicApplicationManagerTest, IsTokenFile_Empty_ReturnsFalse)
{
EXPECT_FALSE(AzToolsFramework::AssetFileInfoListComparison::IsTokenFile(""));
}
TEST_F(BasicApplicationManagerTest, IsTokenFile_NonToken_ReturnsFalse)
{
EXPECT_FALSE(AzToolsFramework::AssetFileInfoListComparison::IsTokenFile("Somefile"));
}
TEST_F(BasicApplicationManagerTest, IsTokenFile_Token_ReturnsTrue)
{
EXPECT_TRUE(AzToolsFramework::AssetFileInfoListComparison::IsTokenFile("$SomeToken"));
}
TEST_F(BasicApplicationManagerTest, IsOutputPath_Empty_ReturnsFalse)
{
EXPECT_FALSE(AzToolsFramework::AssetFileInfoListComparison::IsOutputPath(""));
}
TEST_F(BasicApplicationManagerTest, IsOutputPath_NonToken_ReturnsTrue)
{
EXPECT_TRUE(AzToolsFramework::AssetFileInfoListComparison::IsOutputPath("Somefile"));
}
TEST_F(BasicApplicationManagerTest, IsOutputPath_Token_ReturnsFalse)
{
EXPECT_FALSE(AzToolsFramework::AssetFileInfoListComparison::IsOutputPath("$SomeToken"));
}
TEST_F(BasicApplicationManagerTest, ComputeFilePatternTypeFromInt_ValidInt_Success)
{
int regexIndex(aznumeric_cast<int>(AzToolsFramework::AssetFileInfoListComparison::FilePatternType::Regex));
auto regexResult = AssetBundler::ParseFilePatternType(AZStd::string::format("%i", regexIndex));
EXPECT_TRUE(regexResult.IsSuccess());
EXPECT_EQ(regexResult.GetValue(), AzToolsFramework::AssetFileInfoListComparison::FilePatternType::Regex);
}
}
+16
View File
@@ -0,0 +1,16 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AssetBundler
{
extern const char RelativeTestFolder[];
}
@@ -0,0 +1,412 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/FileFunc/FileFunc.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <source/utils/utils.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <tests/main.h>
#include <source/utils/applicationManager.h>
extern char g_cachedEngineRoot[AZ_MAX_PATH_LEN];
namespace AssetBundler
{
class AssetBundlerBatchUtilsTest
: public UnitTest::ScopedAllocatorSetupFixture
{
};
TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_MacFile_OutputBaseNameAndPlatform)
{
AZStd::string filePath = "assetInfoFile_osx_gl.xml";
AZStd::string baseFilename;
AZStd::string platformIdentifier;
AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
ASSERT_EQ(baseFilename, "assetInfoFile");
ASSERT_EQ(platformIdentifier, "osx_gl");
}
TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_PcFile_OutputBaseNameAndPlatform)
{
AZStd::string filePath = "assetInfoFile_pc.xml";
AZStd::string baseFilename;
AZStd::string platformIdentifier;
AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
ASSERT_EQ(baseFilename, "assetInfoFile");
ASSERT_EQ(platformIdentifier, "pc");
}
TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_MacFileWithUnderScoreInFileName_OutputBaseNameAndPlatform)
{
AZStd::string filePath = "assetInfoFile_test_osx_gl.xml";
AZStd::string baseFilename;
AZStd::string platformIdentifier;
AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
ASSERT_EQ(baseFilename, "assetInfoFile_test");
ASSERT_EQ(platformIdentifier, "osx_gl");
}
TEST_F(AssetBundlerBatchUtilsTest, SplitFilename_PcFileWithUnderScoreInFileName_OutputBaseNameAndPlatform)
{
AZStd::string filePath = "assetInfoFile_test_pc.xml";
AZStd::string baseFilename;
AZStd::string platformIdentifier;
AzToolsFramework::SplitFilename(filePath, baseFilename, platformIdentifier);
ASSERT_EQ(baseFilename, "assetInfoFile_test");
ASSERT_EQ(platformIdentifier, "pc");
}
const char RelativeTestFolder[] = "Code/Tools/AssetBundler/tests";
const char GemsFolder[] = "Gems";
const char EngineFolder[] = "Engine";
const char PlatformsFolder[] = "Platforms";
const char DummyProjectFolder[] = "DummyProject";
class AssetBundlerGemsUtilTest
: public UnitTest::ScopedAllocatorSetupFixture
{
public:
void SetUp() override
{
m_data = AZStd::make_unique<StaticData>();
m_data->m_application.reset(aznew AzToolsFramework::ToolsApplication());
m_data->m_application.get()->Start(AzFramework::Application::Descriptor());
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
if (!AZ::SettingsRegistry::Get())
{
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(m_registry);
AZ::SettingsRegistry::Register(&m_registry);
}
const char* engineRoot = nullptr;
AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot);
if (!engineRoot)
{
GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to locate engine root.\n").c_str());
}
AzFramework::StringFunc::Path::Join(engineRoot, RelativeTestFolder, m_data->m_testEngineRoot);
m_data->m_localFileIO = aznew AZ::IO::LocalFileIO();
m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
// we need to set it to nullptr first because otherwise the
// underneath code assumes that we might be leaking the previous instance
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO);
AddGemData(m_data->m_testEngineRoot.c_str(), "GemA");
AddGemData(m_data->m_testEngineRoot.c_str(), "GemB");
AZStd::string absoluteEngineSeedFilePath;
AzFramework::StringFunc::Path::ConstructFull(m_data->m_testEngineRoot.c_str(), EngineFolder, "SeedAssetList", AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteEngineSeedFilePath, true);
m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(absoluteEngineSeedFilePath, true));
AddGemData(m_data->m_testEngineRoot.c_str(), "GemC", false);
AZStd::string absoluteProjectSeedFilePath;
AzFramework::StringFunc::Path::ConstructFull(m_data->m_testEngineRoot.c_str(), DummyProjectFolder, "SeedAssetList", AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteProjectSeedFilePath, true);
m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(absoluteProjectSeedFilePath, true));
}
void TearDown() override
{
AZ::IO::FileIOBase::SetInstance(nullptr);
delete m_data->m_localFileIO;
AZ::IO::FileIOBase::SetInstance(m_data->m_priorFileIO);
m_data->m_gemInfoList.set_capacity(0);
m_data->m_gemSeedFilePairList.set_capacity(0);
m_data->m_application.get()->Stop();
m_data->m_application.reset();
}
void AddGemData(const char* engineRoot, const char* gemName, bool seedFileExists = true)
{
AZ::IO::Path relativeGemPath{ GemsFolder };
relativeGemPath /= gemName;
AZ::IO::Path absoluteGemPath{ engineRoot };
absoluteGemPath /= relativeGemPath;
AZ::IO::Path absoluteGemSeedFilePath = absoluteGemPath;
absoluteGemSeedFilePath /= "Assets/seedList";
absoluteGemSeedFilePath.ReplaceExtension(AZ::IO::PathView{ AzToolsFramework::AssetSeedManager::GetSeedFileExtension() });
absoluteGemSeedFilePath = absoluteGemSeedFilePath.LexicallyNormal();
m_data->m_gemSeedFilePairList.emplace_back(absoluteGemSeedFilePath, seedFileExists);
m_data->m_gemInfoList.emplace_back(AzToolsFramework::AssetUtils::GemInfo(gemName, relativeGemPath.Native(), absoluteGemPath.Native(), AZ::Uuid::CreateRandom().ToString<AZStd::string>().c_str(), false, false));
AZ::IO::Path platformsDirectory = absoluteGemPath / "Assets" / PlatformsFolder;
if (m_data->m_localFileIO->Exists(platformsDirectory.c_str()))
{
m_data->m_localFileIO->FindFiles(platformsDirectory.c_str(),
AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(),
[&](const char* fileName)
{
AZStd::string normalizedFilePath = fileName;
AzFramework::StringFunc::Path::Normalize(normalizedFilePath);
m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(normalizedFilePath, seedFileExists));
return true;
});
}
AZ::IO::Path iosDirectory = platformsDirectory / AzFramework::PlatformIOS;
if (m_data->m_localFileIO->Exists(iosDirectory.c_str()))
{
bool recurse = true;
AZ::Outcome<AZStd::list<AZStd::string>, AZStd::string> result = AzFramework::FileFunc::FindFileList(iosDirectory.Native(),
AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(), recurse);
if (result.IsSuccess())
{
AZStd::list<AZStd::string> seedFiles = result.TakeValue();
for(AZStd::string& seedFile : seedFiles)
{
AZStd::string normalizedFilePath = seedFile;
AzFramework::StringFunc::Path::Normalize(normalizedFilePath);
m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(normalizedFilePath, seedFileExists));
}
}
}
}
struct StaticData
{
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> m_gemInfoList;
AZStd::vector<AZStd::pair<AZStd::string, bool>> m_gemSeedFilePairList;
AZStd::unique_ptr<AzToolsFramework::ToolsApplication> m_application = {};
AZ::IO::FileIOBase* m_priorFileIO = nullptr;
AZ::IO::FileIOBase* m_localFileIO = nullptr;
AZStd::string m_testEngineRoot;
};
const int GemAIndex = 0;
const int GemBIndex = 1;
const int GemBSharedFileIndex = 2;
const int GemBIosFileIndex = 3;
const int EngineIndex = 4;
const int GemCIndex = 5;
const int ProjectIndex = 6;
AZStd::unique_ptr<StaticData> m_data;
AZ::SettingsRegistryImpl m_registry;
};
TEST_F(AssetBundlerGemsUtilTest, GetDefaultSeedFiles_AllSeedFiles_Found)
{
// DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/
auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), DummyProjectFolder, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC);
ASSERT_EQ(defaultSeedList.size(), 5); //adding one for the engine seed file and one for the project file
// Validate whether both GemA and GemB seed file are present
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemAIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBSharedFileIndex].first), defaultSeedList.end());
// Validate that the engine seed file is present
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[EngineIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[ProjectIndex].first), defaultSeedList.end());
}
TEST_F(AssetBundlerGemsUtilTest, GetDefaultSeedFilesForMultiplePlatforms_AllSeedFiles_Found)
{
// DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/
auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), DummyProjectFolder, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS);
ASSERT_EQ(defaultSeedList.size(), 6); //adding one for the engine seed file and one for the project file
// Validate whether both GemA and GemB seed file are present
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemAIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBSharedFileIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIosFileIndex].first), defaultSeedList.end());
// Validate that the engine seed file is present
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[EngineIndex].first), defaultSeedList.end());
EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[ProjectIndex].first), defaultSeedList.end());
}
TEST_F(AssetBundlerGemsUtilTest, IsSeedFileValid_Ok)
{
for (const auto& pair : m_data->m_gemSeedFilePairList)
{
bool result = IsGemSeedFilePathValid(m_data->m_testEngineRoot.c_str(), pair.first, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS);
EXPECT_EQ(result,pair.second);
}
}
const char TestProject[] = "TestProject";
const char TestProjectLowerCase[] = "testproject";
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
const char TestRoot[] = "D:\\Dummy\\Test\\dev\\";
#else
const char TestRoot[] = "/Dummy/Test/dev/";
#endif
class MockApplication
: public AzFramework::ApplicationRequests::Bus::Handler
{
public:
MockApplication()
{
// ensure the cached engine root from previous tests is cleared
// so the mock application behaves properly
g_cachedEngineRoot[0] = 0;
if (AZ::SettingsRegistry::Get() == nullptr)
{
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
AZ::SettingsRegistry::Register(m_settingsRegistry.get());
auto gameProjectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "sys_game_folder");
m_settingsRegistry->Set(gameProjectKey, TestProject);
}
AzFramework::ApplicationRequests::Bus::Handler::BusConnect();
}
~MockApplication()
{
AzFramework::ApplicationRequests::Bus::Handler::BusDisconnect();
if (m_settingsRegistry.get() == AZ::SettingsRegistry::Get())
{
AZ::SettingsRegistry::Unregister(m_settingsRegistry.get());
}
}
// AzFramework::ApplicationRequests::Bus::Handler interface
void NormalizePath(AZStd::string& /*path*/) override {};
void NormalizePathKeepCase(AZStd::string& /*path*/) override {};
void CalculateBranchTokenForAppRoot(AZStd::string& /*token*/) const override {};
const char* GetEngineRoot() const { return TestRoot; }
private:
AZStd::unique_ptr<AZ::SettingsRegistryInterface> m_settingsRegistry;
};
class AssetBundlerPathUtilTest
: public UnitTest::ScopedAllocatorSetupFixture
{
public:
void SetUp() override
{
UnitTest::ScopedAllocatorSetupFixture::SetUp();
m_data = AZStd::make_unique<StaticData>();
}
void TearDown() override
{
m_data.reset();
UnitTest::ScopedAllocatorSetupFixture::TearDown();
}
struct StaticData
{
MockApplication m_mockApplication;
};
AZStd::unique_ptr<StaticData> m_data;
};
TEST_F(AssetBundlerPathUtilTest, ComputeAssetAliasAndGameName_AssetCatalogPathNotProvided_Valid)
{
AZStd::string platformIdentifier = "pc";
AZStd::string assetCatalogFile;
AZStd::string assetAlias;
AZStd::string gameName;
EXPECT_TRUE(ComputeAssetAliasAndGameName(platformIdentifier, assetCatalogFile, assetAlias, gameName).IsSuccess());
EXPECT_TRUE(gameName == TestProject);
AZStd::string assetPath;
bool success = AzFramework::StringFunc::Path::ConstructFull(TestRoot, "Cache", assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), TestProject, assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), platformIdentifier.c_str(), assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), TestProjectLowerCase, assetPath);
EXPECT_EQ(assetAlias, assetPath);
}
TEST_F(AssetBundlerPathUtilTest, ComputeAssetAliasAndGameName_AssetCatalogPathProvided_Valid)
{
AZStd::string platformIdentifier = "pc";
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
AZStd::string assetCatalogFile = "D:\\Dummy\\Test\\dev\\Cache\\TestProject1\\pc\\testproject1\\assetcatalog.xml";
#else
AZStd::string assetCatalogFile = "/Dummy/Test/dev/Cache/TestProject1/pc/testproject1/assetcatalog.xml";
#endif
AZStd::string assetAlias;
AZStd::string gameName;
EXPECT_TRUE(ComputeAssetAliasAndGameName(platformIdentifier, assetCatalogFile, assetAlias, gameName).IsSuccess());
EXPECT_EQ(gameName, "TestProject1");
AZStd::string assetPath;
bool success = AzFramework::StringFunc::Path::ConstructFull(TestRoot, "Cache", assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), "TestProject1", assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), platformIdentifier.c_str(), assetPath) &&
AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), "testproject1", assetPath);
EXPECT_EQ(assetAlias, assetPath);
}
TEST_F(AssetBundlerPathUtilTest, ComputeAssetAliasAndGameName_GameNameMismatch_Failure)
{
AZStd::string platformIdentifier = "pc";
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
AZStd::string assetCatalogFile = "D:\\Dummy\\Cache\\TestProject1\\pc\\testproject1\\assetcatalog.xml";
#else
AZStd::string assetCatalogFile = "/Dummy/Cache/TestProject1/pc/testproject1/assetcatalog.xml";
#endif
AZStd::string assetAlias;
AZStd::string gameName="SomeOtherGamename";
EXPECT_FALSE(ComputeAssetAliasAndGameName(platformIdentifier, assetCatalogFile, assetAlias, gameName).IsSuccess());
}
}
int main(int argc, char* argv[])
{
INVOKE_AZ_UNIT_TEST_MAIN();
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
int runSuccess = 0;
{
AssetBundler::ApplicationManager applicationManger(&argc, &argv);
applicationManger.Init();
runSuccess = applicationManger.Run() ? 0 : 1;
}
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
return runSuccess;
}
@@ -0,0 +1,301 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Debug/Trace.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzCore/Slice/SliceSystemComponent.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Asset/AssetCatalogComponent.h>
#include <AzFramework/Asset/AssetSystemComponent.h>
#include <AzFramework/Input/System/InputSystemComponent.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Asset/AssetSystemComponent.h>
#include <AzToolsFramework/Component/EditorComponentAPIComponent.h>
#include <AzToolsFramework/Entity/EditorEntityActionComponent.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
#include <AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AssetBuilderApplication.h>
#include <AssetBuilderComponent.h>
#include <AssetBuilderInfo.h>
#include <AzCore/Interface/Interface.h>
namespace AssetBuilder
{
//! This function returns the build system target name
AZStd::string_view GetBuildTargetName()
{
#if !defined (LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
return AZStd::string_view{ LY_CMAKE_TARGET };
}
}
AZ::ComponentTypeList AssetBuilderApplication::GetRequiredSystemComponents() const
{
AZ::ComponentTypeList components = AzFramework::Application::GetRequiredSystemComponents();
for (auto iter = components.begin(); iter != components.end();)
{
if (*iter == azrtti_typeid<AZ::UserSettingsComponent>()
|| *iter == azrtti_typeid<AzFramework::InputSystemComponent>()
|| *iter == azrtti_typeid<AzFramework::AssetCatalogComponent>()
)
{
iter = components.erase(iter);
}
else
{
++iter;
}
}
components.insert(components.end(), {
azrtti_typeid<AZ::SliceSystemComponent>(),
azrtti_typeid<AzToolsFramework::SliceMetadataEntityContextComponent>(),
azrtti_typeid<AssetBuilderComponent>(),
azrtti_typeid<AssetProcessor::ToolsAssetCatalogComponent>(),
azrtti_typeid<AzToolsFramework::AssetSystem::AssetSystemComponent>(),
azrtti_typeid<AzToolsFramework::Components::EditorComponentAPIComponent>(),
azrtti_typeid<AzToolsFramework::Components::EditorEntityActionComponent>(),
azrtti_typeid<AzToolsFramework::Components::EditorEntitySearchComponent>(),
azrtti_typeid<AzToolsFramework::Components::EditorEntityModelComponent>(),
azrtti_typeid<AzToolsFramework::EditorEntityContextComponent>(),
});
return components;
}
AssetBuilderApplication::AssetBuilderApplication(int* argc, char*** argv)
: AzToolsFramework::ToolsApplication(argc, argv)
, m_qtApplication(*argc, *argv)
{
// The settings registry has been created at this point
auto settingsRegistry = AZ::SettingsRegistry::Get();
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
*settingsRegistry, AssetBuilder::GetBuildTargetName());
// Override the /Amazon/AzCore/Bootstrap/sys_game_folder entry in the Settings Registry using the -gameName parameter
if (m_commandLine.GetNumSwitchValues("gameName") > 0)
{
const AZStd::string& gameFolderOverride = m_commandLine.GetSwitchValue("gameName", 0);
auto gameFolderCommandLineOverride = AZStd::string::format("--regset=%s/sys_game_folder=%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey,
gameFolderOverride.c_str());
AZ::CommandLine::ParamContainer commandLineArgs;
m_commandLine.Dump(commandLineArgs);
commandLineArgs.emplace_back(gameFolderCommandLineOverride);
m_commandLine.Parse(commandLineArgs);
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, m_commandLine, false);
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry);
}
AZ::Interface<IBuilderApplication>::Register(this);
}
AssetBuilderApplication::~AssetBuilderApplication()
{
AZ::Interface<IBuilderApplication>::Unregister(this);
}
void AssetBuilderApplication::RegisterCoreComponents()
{
AzToolsFramework::ToolsApplication::RegisterCoreComponents();
RegisterComponentDescriptor(AssetBuilderComponent::CreateDescriptor());
RegisterComponentDescriptor(AssetProcessor::ToolsAssetCatalogComponent::CreateDescriptor());
}
void AssetBuilderApplication::StartCommon(AZ::Entity* systemEntity)
{
InstallCtrlHandler();
// Merge in the SettingsRegistry for the game being processed. This does not
// necessarily correspond to the project name in the bootstrap.cfg since it
// the AssetBuilder supports overriding the gameName on the command line
AZ::SettingsRegistryInterface& registry = *AZ::SettingsRegistry::Get();
AZ::SettingsRegistryInterface::FixedValueString gameName;
if (m_commandLine.GetNumSwitchValues("gameName") > 0)
{
gameName = AZStd::string_view(m_commandLine.GetSwitchValue("gameName", 0));
}
// Add the supplied gameName to the specialization key in the registry
if (!gameName.empty())
{
auto gameNameSpecialization = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%.*s",
AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, aznumeric_cast<int>(gameName.size()), gameName.data());
registry.Set(gameNameSpecialization, true);
}
else
{
// Add the project name as a registry specialization
auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey);
if (AZ::SettingsRegistryInterface::FixedValueString bootstrapGameName; registry.Get(bootstrapGameName, projectKey) && !bootstrapGameName.empty())
{
registry.Set(AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, bootstrapGameName.c_str()),
true);
}
}
// Retrieve specializations from the Settings Registry and ComponentApplication derived classes
AZ::SettingsRegistryInterface::Specializations specializations;
SetSettingsRegistrySpecializations(specializations);
// Merge the SettingsRegistry file again using gameName as an additional specialization
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry,
AZ_TRAIT_OS_PLATFORM_CODENAME, specializations);
AzToolsFramework::ToolsApplication::StartCommon(systemEntity);
#if defined(AZ_PLATFORM_MAC)
// The asset builder needs to start astcenc as a child process to compress textures.
// astcenc is started by the PVRTexLib dynamic library. In order for it to be able to find
// the executable, we need to set the PATH environment variable.
AZStd::string exeFolder;
AZ::ComponentApplicationBus::BroadcastResult(exeFolder, &AZ::ComponentApplicationBus::Events::GetExecutableFolder);
setenv("PATH", exeFolder.c_str(), 1);
#endif // AZ_PLATFORM_MAC
AZStd::string gameRoot;
if (m_commandLine.GetNumSwitchValues("gameRoot") > 0)
{
gameRoot = m_commandLine.GetSwitchValue("gameRoot", 0);
}
if (gameRoot.empty())
{
if (IsInDebugMode())
{
if (!AZ::SettingsRegistry::Get()->Get(gameRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder))
{
AZ_Error("AssetBuilder", false, "Unable to determine the game root automatically. "
"Make sure a default project has been set or provide a default option on the command line. (See -help for more info.)");
return;
}
}
else
{
AZ_Printf(AssetBuilderSDK::InfoWindow, "gameRoot not specified on the command line, assuming current directory.\n");
AZ_Printf(AssetBuilderSDK::InfoWindow, "gameRoot is best specified as the full path to the game's asset folder.");
}
}
if (!gameRoot.empty())
{
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
if (fileIO)
{
fileIO->SetAlias("@devassets@", gameRoot.c_str());
}
}
// Loads dynamic modules and registers any component descriptors populated into the AZ::Module m_descriptor list
// for each instantiated module class
LoadDynamicModules();
AssetBuilderSDK::InitializeSerializationContext();
AssetBuilderSDK::InitializeBehaviorContext();
// the asset builder app never writes source files, only assets, so there is no need to do any kind of asset upgrading
AZ::Data::AssetManager::Instance().SetAssetInfoUpgradingEnabled(false);
// Disable parallel dependency loads since the builders can't count on all other assets and their info being ready.
// Specifically, asset builders can trigger asset loads during the building process. The ToolsAssetCatalog doesn't
// implement the dependency APIs, so the asset loads will fail to load any dependent assets.
//
// NOTE: The ToolsAssetCatalog could *potentially* implement the dependency APIs by querying the live Asset Processor instance,
// but this will return incomplete dependency information based on the subset of assets that have already processed.
// In theory, if the Asset Builder dependencies are set up correctly, the needed subset should always be processed first,
// but the one edge case that can't be handled is the case where the Asset Builder intends to filter out the dependent load,
// but needs to query enough information about the asset (specifically asset type) to know that it can filter it out. Since
// the assets are being filtered out, they aren't dependencies, might not be built yet, and so might not have asset type available.
AZ::Data::AssetManager::Instance().SetParallelDependentLoadingEnabled(false);
}
bool AssetBuilderApplication::IsInDebugMode() const
{
return AssetBuilderComponent::IsInDebugMode(m_commandLine);
}
bool AssetBuilderApplication::GetOptionalAppRootArg(char destinationRootArgBuffer[], size_t destinationRootArgBufferSize) const
{
// Only continue if the application received any arguments from the command line
if ((!this->m_argC) || (!this->m_argV))
{
return false;
}
int argc = this->m_argC;
char** argv = this->m_argV;
// Search for the app root argument (-approot=<PATH>) where <PATH> is the app root path to set for the application
const static char* appRootArgPrefix = "-approot=";
size_t appRootArgPrefixLen = strlen(appRootArgPrefix);
const char* appRootArg = nullptr;
for (int index = 0; index < argc; index++)
{
if (strncmp(appRootArgPrefix, argv[index], appRootArgPrefixLen) == 0)
{
appRootArg = &argv[index][appRootArgPrefixLen];
break;
}
}
if (appRootArg)
{
AZStd::string_view appRootArgView = appRootArg;
size_t afterStartQuotes = appRootArgView.find_first_not_of(R"(")");
if (afterStartQuotes != AZStd::string_view::npos)
{
appRootArgView.remove_prefix(afterStartQuotes);
}
size_t beforeEndQuotes = appRootArgView.find_last_not_of(R"(")");
if (beforeEndQuotes != AZStd::string_view::npos)
{
appRootArgView.remove_suffix(appRootArgView.size() - (beforeEndQuotes + 1));
}
appRootArgView.copy(destinationRootArgBuffer, destinationRootArgBufferSize);
destinationRootArgBuffer[appRootArgView.size()] = '\0';
const char lastChar = destinationRootArgBuffer[strlen(destinationRootArgBuffer) - 1];
bool needsTrailingPathDelim = (lastChar != AZ_CORRECT_FILESYSTEM_SEPARATOR) && (lastChar != AZ_WRONG_FILESYSTEM_SEPARATOR);
if (needsTrailingPathDelim)
{
azstrncat(destinationRootArgBuffer, destinationRootArgBufferSize, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING, 1);
}
return true;
}
else
{
return false;
}
}
void AssetBuilderApplication::InitializeBuilderComponents()
{
CreateAndAddEntityFromComponentTags(AZStd::vector<AZ::Crc32>({ AssetBuilderSDK::ComponentTags::AssetBuilder }), "AssetBuilders Entity");
}
@@ -0,0 +1,56 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/std/string/string.h>
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include "AssetBuilderInfo.h"
#include <QCoreApplication>
struct IBuilderApplication
{
AZ_RTTI(IBuilderApplication, "{FEDD188E-D5FF-4852-B945-F82F7CC1CA5F}");
IBuilderApplication() = default;
virtual ~IBuilderApplication() = default;
virtual void InitializeBuilderComponents() = 0;
AZ_DISABLE_COPY_MOVE(IBuilderApplication);
};
class AssetBuilderApplication
: public AzToolsFramework::ToolsApplication
, public IBuilderApplication
{
public:
AssetBuilderApplication(int* argc, char*** argv);
~AssetBuilderApplication();
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
void RegisterCoreComponents() override;
void StartCommon(AZ::Entity* systemEntity) override;
bool IsInDebugMode() const;
bool GetOptionalAppRootArg(char destinationRootArgBuffer[], size_t destinationRootArgBufferSize) const;
void InitializeBuilderComponents() override;
private:
void InstallCtrlHandler();
QCoreApplication m_qtApplication;
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,169 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AzCore/Component/Component.h>
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzFramework/Network/SocketConnection.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/API/AssetDatabaseBus.h>
#include "AssetBuilderInfo.h"
//! This bus is used to signal to the AssetBuilderComponent to start up and execute while providing a return code
class BuilderBusTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
typedef AZStd::recursive_mutex MutexType;
virtual ~BuilderBusTraits() = default;
virtual bool Run() = 0;
};
typedef AZ::EBus<BuilderBusTraits> BuilderBus;
//! Main component of the AssetBuilder that handles interfacing with the AssetProcessor and the Builder module(s)
//! In resident mode, the component will keep the application up and running indefinitely while accepting job requests from the AP network connection
//! The other mods (create, process) will read a job from an `input` file and write the response to the `output` file and then terminate
class AssetBuilderComponent
: public AZ::Component,
public BuilderBus::Handler,
public AssetBuilderSDK::AssetBuilderBus::Handler,
public AzFramework::EngineConnectionEvents::Bus::Handler,
public AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler
{
public:
AZ_COMPONENT(AssetBuilderComponent, "{04332899-5d73-4d41-86b7-b1017d349673}")
static void Reflect(AZ::ReflectContext* context);
AssetBuilderComponent() = default;
~AssetBuilderComponent() override = default;
void PrintHelp();
// AZ::Component overrides
void Activate() override;
void Deactivate() override;
// BuilderBus Handler
bool Run() override;
// AssetBuilderBus Handler
bool FindBuilderInformation(const AZ::Uuid& builderGuid, AssetBuilderSDK::AssetBuilderDesc& descriptionOut) override;
void RegisterBuilderInformation(const AssetBuilderSDK::AssetBuilderDesc& builderDesc) override;
void RegisterComponentDescriptor(AZ::ComponentDescriptor* descriptor) override;
//EngineConnectionEvents Handler
void Disconnected(AzFramework::SocketConnection* connection) override;
static bool IsInDebugMode(const AzFramework::CommandLine& commandLine);
//AssetDatabaseRequestsBus Handler
bool GetAssetDatabaseLocation(AZStd::string& location) override;
protected:
AZ_DISABLE_COPY_MOVE(AssetBuilderComponent);
enum class JobType
{
Create,
Process
};
//! Describes a job request that came in from the network connection
struct Job
{
JobType m_jobType;
AZ::u32 m_requestSerial;
AZStd::unique_ptr<AzFramework::AssetSystem::BaseAssetProcessorMessage> m_netRequest;
AZStd::unique_ptr<AzFramework::AssetSystem::BaseAssetProcessorMessage> m_netResponse;
};
//! Reads a command line parameter and places it in the outValue parameter. Returns false if the value is empty, true otherwise
//! If required is true, an AZ_Error message is output
bool GetParameter(const char* paramName, AZStd::string& outValue, bool required = true) const;
//! Returns the platform specific extension for dynamic libraries
static const char* GetLibraryExtension();
bool ConnectToAssetProcessor();
bool LoadBuilders(const AZStd::string& builderFolder);
bool LoadBuilder(const AZStd::string& filePath);
void UnloadBuilders();
//! Hooks up net job request handling and keeps the AssetBuilder running indefinitely
bool RunInResidentMode();
bool RunDebugTask(AZStd::string&& debugFile, bool runCreateJobs, bool runProcessJob);
bool RunOneShotTask(const AZStd::string& task);
template<typename TNetRequest, typename TNetResponse>
void ResidentJobHandler(AZ::u32 serial, const void* data, AZ::u32 dataLength, JobType jobType);
void CreateJobsResidentHandler(AZ::u32 typeId, AZ::u32 serial, const void* data, AZ::u32 dataLength);
void ProcessJobResidentHandler(AZ::u32 typeId, AZ::u32 serial, const void* data, AZ::u32 dataLength);
bool IsBuilderForFile(const AZStd::string& filePath, const AssetBuilderSDK::AssetBuilderDesc& builderDescription) const;
//! Run by a separate thread to avoid blocking the net recv thread
//! Handles calling the appropriate builder job function for the incoming job
void JobThread();
void ProcessJob(const AssetBuilderSDK::ProcessJobFunction& job, const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& outResponse);
//! Handles a builder registration request
bool HandleRegisterBuilder(const AZStd::string& inputFilePath, const AZStd::string& outputFilePath) const;
//! If needed looks at collected data and updates the result code from the job accordingly.
void UpdateResultCode(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) const;
//! Handles reading the request from file, passing it to the specified function and writing the response to file
template<typename TRequest, typename TResponse>
bool HandleTask(const AZStd::string& inputFilePath, const AZStd::string& outputFilePath, const AZStd::function<void(const TRequest& request, TResponse& response)>& handlerFunc);
//! Flush the File Streamer cache to ensure that there aren't stale file handles or data between asset job runs.
void FlushFileStreamerCache();
//! Map used to look up the asset builder to handle a request
AZStd::unordered_map<AZ::Uuid, AZStd::unique_ptr<AssetBuilderSDK::AssetBuilderDesc>> m_assetBuilderDescMap;
//! List of loaded builders
AZStd::vector<AZStd::unique_ptr<AssetBuilder::ExternalModuleAssetBuilderInfo>> m_assetBuilderInfoList;
//! Currently loading builder
AssetBuilder::ExternalModuleAssetBuilderInfo* m_currentAssetBuilder = nullptr;
//! Thread for running a job, so we don't block the network thread while doing work
AZStd::thread_desc m_jobThreadDesc;
AZStd::thread m_jobThread;
//! Indicates if resident mode is up and running
AZStd::atomic<bool> m_running{};
//! Main thread will wait on this event in resident mode. Releasing it will shut down the application
AZStd::binary_semaphore m_mainEvent;
//! Use to signal a new job is ready to be processed
AZStd::binary_semaphore m_jobEvent;
//! Lock for m_queuedJob
AZStd::mutex m_jobMutex;
//! Stored job that is waiting to be picked up for processing by the job thread
AZStd::unique_ptr<Job> m_queuedJob;
AZStd::string m_gameName;
AZStd::string m_gameCache;
};
@@ -0,0 +1,193 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
#include <AssetBuilderInfo.h>
#include <AssetBuilderApplication.h>
namespace AssetBuilder
{
ExternalModuleAssetBuilderInfo::ExternalModuleAssetBuilderInfo(const QString& modulePath)
: m_builderName(modulePath)
, m_entity(nullptr)
, m_componentDescriptorList()
, m_initializeModuleFunction(nullptr)
, m_moduleRegisterDescriptorsFunction(nullptr)
, m_moduleAddComponentsFunction(nullptr)
, m_uninitializeModuleFunction(nullptr)
, m_modulePath(modulePath)
, m_library(modulePath)
{
Load();
}
ExternalModuleAssetBuilderInfo::~ExternalModuleAssetBuilderInfo()
{
Unload();
}
const QString& ExternalModuleAssetBuilderInfo::GetName() const
{
return m_builderName;
}
//! Sanity check for the module's status
bool ExternalModuleAssetBuilderInfo::IsLoaded() const
{
return m_library.isLoaded();
}
void ExternalModuleAssetBuilderInfo::Initialize()
{
AZ_Error("AssetBuilder", IsLoaded(), "External module %s not loaded.", m_builderName.toUtf8().data());
m_initializeModuleFunction(AZ::Environment::GetInstance());
m_moduleRegisterDescriptorsFunction();
AZStd::string entityName = AZStd::string::format("%s Entity", GetName().toUtf8().data());
m_entity = aznew AZ::Entity(entityName.c_str());
m_moduleAddComponentsFunction(m_entity);
AZ_TracePrintf("AssetBuilder", "Init Entity %s\n", GetName().toUtf8().data());
m_entity->Init();
//Activate all the components
m_entity->Activate();
}
void ExternalModuleAssetBuilderInfo::UnInitialize()
{
AZ_Error("AssetBuilder", IsLoaded(), "External module %s not loaded.", m_builderName.toUtf8().data());
AZ_TracePrintf("AssetBuilder", "Uninitializing builder: %s\n", m_modulePath.toUtf8().data());
if (m_entity)
{
m_entity->Deactivate();
delete m_entity;
m_entity = nullptr;
}
for (AZ::ComponentDescriptor* componentDesc : m_componentDescriptorList)
{
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::UnregisterComponentDescriptor, componentDesc);
componentDesc->ReleaseDescriptor(); // this kills the descriptor.
}
m_componentDescriptorList.clear();
m_registeredBuilderDescriptorIDs.clear();
m_uninitializeModuleFunction();
}
AssetBuilderType ExternalModuleAssetBuilderInfo::GetAssetBuilderType()
{
QStringList missingFunctionsList;
ResolveModuleFunction<QFunctionPointer>("IsAssetBuilder", missingFunctionsList);
InitializeModuleFunction initializeModuleAddress = ResolveModuleFunction<InitializeModuleFunction>("InitializeModule", missingFunctionsList);
ModuleRegisterDescriptorsFunction moduleRegisterDescriptorsAddress = ResolveModuleFunction<ModuleRegisterDescriptorsFunction>("ModuleRegisterDescriptors", missingFunctionsList);
ModuleAddComponentsFunction moduleAddComponentsAddress = ResolveModuleFunction<ModuleAddComponentsFunction>("ModuleAddComponents", missingFunctionsList);
UninitializeModuleFunction uninitializeModuleAddress = ResolveModuleFunction<UninitializeModuleFunction>("UninitializeModule", missingFunctionsList);
if (missingFunctionsList.empty())
{
// a valid builder
m_initializeModuleFunction = initializeModuleAddress;
m_moduleRegisterDescriptorsFunction = moduleRegisterDescriptorsAddress;
m_moduleAddComponentsFunction = moduleAddComponentsAddress;
m_uninitializeModuleFunction = uninitializeModuleAddress;
return AssetBuilderType::Valid;
}
else if (missingFunctionsList.size() > 0 && missingFunctionsList.contains("IsAssetBuilder"))
{
// This DLL is not a builder and should be ignored.
return AssetBuilderType::None;
}
else
{
// This is supposed to be a builder but is invalid
QString errorMessage = QString("Builder library %1 is missing one or more exported functions: %2").arg(QString(GetName()), missingFunctionsList.join(','));
AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "One or more builder functions is missing in the library: %s\n", errorMessage.toUtf8().data());
return AssetBuilderType::Invalid;
}
}
AssetBuilderType ExternalModuleAssetBuilderInfo::Load()
{
if (IsLoaded())
{
AZ_Warning("AssetBuilder", false, "External module %s already loaded.", m_builderName.toUtf8().data());
return AssetBuilderType::None;
}
m_library.setFileName(m_modulePath);
if (!m_library.load())
{
AZ_TracePrintf("AssetBuilder", "Unable to load builder : %s\n", GetName().toUtf8().data());
return AssetBuilderType::Invalid;
}
return GetAssetBuilderType();
}
void ExternalModuleAssetBuilderInfo::Unload()
{
if (IsLoaded())
{
m_library.unload();
}
m_initializeModuleFunction = nullptr;
m_moduleRegisterDescriptorsFunction = nullptr;
m_moduleAddComponentsFunction = nullptr;
m_uninitializeModuleFunction = nullptr;
}
void ExternalModuleAssetBuilderInfo::RegisterBuilderDesc(const AZ::Uuid& builderDescID)
{
if (m_registeredBuilderDescriptorIDs.find(builderDescID) != m_registeredBuilderDescriptorIDs.end())
{
AZ_Warning(AssetBuilderSDK::InfoWindow,
false,
"Builder description id '%s' already registered to external builder module %s",
builderDescID.ToString<AZStd::string>().c_str(),
m_builderName.toUtf8().data());
return;
}
m_registeredBuilderDescriptorIDs.insert(builderDescID);
}
void ExternalModuleAssetBuilderInfo::RegisterComponentDesc(AZ::ComponentDescriptor* descriptor)
{
m_componentDescriptorList.push_back(descriptor);
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::RegisterComponentDescriptor, descriptor);
}
template<typename T>
T ExternalModuleAssetBuilderInfo::ResolveModuleFunction(const char* functionName, QStringList& missingFunctionsList)
{
T functionAddr = reinterpret_cast<T>(m_library.resolve(functionName));
if (!functionAddr)
{
missingFunctionsList.append(QString(functionName));
}
return functionAddr;
}
}
@@ -0,0 +1,96 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
class QString;
class QStringList;
#include <QLibrary>
#include <QVector>
#include <AzCore/std/containers/set.h>
#include <AzCore/Math/Uuid.h>
namespace AZ
{
class ComponentDescriptor;
class Entity;
namespace Internal
{
class EnvironmentInterface;
}
typedef Internal::EnvironmentInterface* EnvironmentInstance;
}
namespace AssetBuilder
{
enum class AssetBuilderType
{
Invalid, Valid, None
};
/**
* Class to manage external module builders for AssetBuilder. Note that this is similar
* to a class in Asset Processor, because both AssetProcessor.exe and AssetBuilder.exe both load builders in a similar manner.
* The implementation details differ.
*/
class ExternalModuleAssetBuilderInfo
{
public:
ExternalModuleAssetBuilderInfo(const QString& modulePath);
virtual ~ExternalModuleAssetBuilderInfo();
const QString& GetName() const;
//! Sanity check for the module's status
bool IsLoaded() const;
//! Perform the module initialization for the external builder
void Initialize();
//! Perform the necessary process of uninitializing an external builder
void UnInitialize();
//! Register a builder descriptor ID to track as part of this builders lifecycle management
void RegisterBuilderDesc(const AZ::Uuid& builderDesc);
//! Register a component descriptor to track as part of this builders lifecycle management
void RegisterComponentDesc(AZ::ComponentDescriptor* descriptor);
//! Check to see if the builder has the required functions defined.
AssetBuilder::AssetBuilderType GetAssetBuilderType();
protected:
AssetBuilderType Load();
void Unload();
AZStd::set<AZ::Uuid> m_registeredBuilderDescriptorIDs;
typedef void(* InitializeModuleFunction)(AZ::EnvironmentInstance sharedEnvironment);
typedef void(* ModuleRegisterDescriptorsFunction)(void);
typedef void(* ModuleAddComponentsFunction)(AZ::Entity* entity);
typedef void(* UninitializeModuleFunction)(void);
template<typename T>
T ResolveModuleFunction(const char* functionName, QStringList& missingFunctionsList);
InitializeModuleFunction m_initializeModuleFunction;
ModuleRegisterDescriptorsFunction m_moduleRegisterDescriptorsFunction;
ModuleAddComponentsFunction m_moduleAddComponentsFunction;
UninitializeModuleFunction m_uninitializeModuleFunction;
AZStd::vector<AZ::ComponentDescriptor*> m_componentDescriptorList;
AZ::Entity* m_entity = nullptr;
QString m_builderName;
QString m_modulePath;
QLibrary m_library;
};
} // AssetBuilder
@@ -0,0 +1,53 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_add_target(
NAME AssetBuilder EXECUTABLE
NAMESPACE AZ
FILES_CMAKE
asset_builder_files.cmake
Platform/${PAL_PLATFORM_NAME}/asset_builder_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
BUILD_DEPENDENCIES
PRIVATE
3rdParty::Qt::Core
3rdParty::Qt::Gui
3rdParty::Qt::Network
AZ::AzCore
AZ::AssetBuilderSDK
AZ::AzToolsFramework
)
# Aggregates all combined AssetBuilders into a single LY_ASSET_BUILDERS #define
get_property(asset_builders GLOBAL PROPERTY LY_ASSET_BUILDERS)
string (REPLACE ";" "," asset_builders "${asset_builders}")
ly_add_source_properties(
SOURCES AssetBuilderComponent.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES LY_ASSET_BUILDERS="${asset_builders}"
)
if(TARGET AssetBuilder)
# Adds the AssetBuilder target as a C preprocessor define so that it can be used as a Settings Registry
# specialization in order to look up the generated .setreg which contains the dependencies
# specified for the AssetBuilder in the <Project>/Gem/Code/CMakeLists via ly_add_project_dependencies
ly_add_source_properties(
SOURCES AssetBuilderApplication.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES LY_CMAKE_TARGET="AssetBuilder"
)
else()
message(FATAL_ERROR "Cannot set LY_CMAKE_TARGET define to AssetBuilder as the target doesn't exist anymore."
" Perhaps it has been renamed")
endif()
@@ -0,0 +1,17 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AssetBuilderApplication.h>
void AssetBuilderApplication::InstallCtrlHandler()
{
}
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
AssetBuilderApplication_linux.cpp
)
@@ -0,0 +1,17 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AssetBuilderApplication.h>
void AssetBuilderApplication::InstallCtrlHandler()
{
}
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
AssetBuilderApplication_mac.cpp
)
@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AssetBuilderApplication.h>
#include "shlobj.h"
namespace AssetBuilderApplicationPrivate
{
BOOL WINAPI CtrlHandlerRoutine(DWORD dwCtrlType)
{
(void)dwCtrlType;
// Terminate the process when CTRL+C is pressed
// Builder processes load user-code and we couldn't expect that every single gem
// written by every single external developer be able to shut down cleanly.
TerminateProcess(GetCurrentProcess(), UINT(-1)); // dont ever return a success error code from a terminated process.
return TRUE;
}
}
void AssetBuilderApplication::InstallCtrlHandler()
{
::SetConsoleCtrlHandler(AssetBuilderApplicationPrivate::CtrlHandlerRoutine, TRUE);
}
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
AssetBuilderApplication_windows.cpp
)
@@ -0,0 +1,180 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AssetBuilderApplication.h>
#include <TraceMessageHook.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzToolsFramework/Component/EditorComponentAPIComponent.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
namespace AssetBuilder
{
using namespace UnitTest;
using AssetBuilderAppTest = AllocatorsFixture;
TEST_F(AssetBuilderAppTest, GetAppRootArg_AssetBuilderAppNoArgs_NoExtraction)
{
AssetBuilderApplication app(nullptr, nullptr);
char appRootBuffer[AZ_MAX_PATH_LEN];
ASSERT_FALSE(app.GetOptionalAppRootArg(appRootBuffer, AZ_MAX_PATH_LEN));
}
TEST_F(AssetBuilderAppTest, GetAppRootArg_AssetBuilderAppQuotedAppRoot_Success)
{
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
const char* appRootArg = R"str(-approot="C:\path\to\app\root\")str";
const char* expectedResult = R"str(C:\path\to\app\root\)str";
#else
const char* appRootArg = R"str(-approot="/path/to/app/root")str";
const char* expectedResult = R"str(/path/to/app/root/)str";
#endif
const char* argArray[] = {
appRootArg
};
int argc = AZ_ARRAY_SIZE(argArray);
char** argv = const_cast<char**>(argArray); // this is unfortunately necessary to get around osx's strict non-const string literal stance
AssetBuilderApplication app(&argc, &argv);
char appRootBuffer[AZ_MAX_PATH_LEN] = { 0 };
ASSERT_TRUE(app.GetOptionalAppRootArg(appRootBuffer, AZ_ARRAY_SIZE(appRootBuffer)));
ASSERT_STREQ(appRootBuffer, expectedResult);
}
TEST_F(AssetBuilderAppTest, GetAppRootArg_AssetBuilderAppNoQuotedAppRoot_Success)
{
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
const char* appRootArg = R"str(-approot=C:\path\to\app\root\)str";
const char* expectedResult = R"str(C:\path\to\app\root\)str";
#else
const char* appRootArg = R"str(-approot=/path/to/app/root)str";
const char* expectedResult = R"str(/path/to/app/root/)str";
#endif
const char* argArray[] = {
appRootArg
};
int argc = AZ_ARRAY_SIZE(argArray);
char** argv = const_cast<char**>(argArray); // this is unfortunately necessary to get around osx's strict non-const string literal stance
AssetBuilderApplication app(&argc, &argv);
char appRootBuffer[AZ_MAX_PATH_LEN] = { 0 };
ASSERT_TRUE(app.GetOptionalAppRootArg(appRootBuffer, AZ_ARRAY_SIZE(appRootBuffer)));
ASSERT_STREQ(appRootBuffer, expectedResult);
}
TEST_F(AssetBuilderAppTest, AssetBuilder_EditorScriptingComponents_Exists)
{
AssetBuilderApplication app(nullptr, nullptr);
AZ::ComponentTypeList systemComponents = app.GetRequiredSystemComponents();
auto searchFor = [&systemComponents](const AZ::Uuid& typeId) -> bool
{
auto entry = AZStd::find(systemComponents.begin(), systemComponents.end(), typeId);
return systemComponents.end() != entry;
};
EXPECT_TRUE(searchFor(azrtti_typeid<AzToolsFramework::SliceMetadataEntityContextComponent>()));
EXPECT_TRUE(searchFor(azrtti_typeid<AzToolsFramework::Components::EditorComponentAPIComponent>()));
EXPECT_TRUE(searchFor(azrtti_typeid<AzToolsFramework::Components::EditorEntitySearchComponent>()));
EXPECT_TRUE(searchFor(azrtti_typeid<AzToolsFramework::Components::EditorEntityModelComponent>()));
EXPECT_TRUE(searchFor(azrtti_typeid<AzToolsFramework::EditorEntityContextComponent>()));
}
void VerifyOutput(const AZStd::string& output)
{
ASSERT_FALSE(output.empty());
AZStd::vector<AZStd::string> tokens;
AZ::StringFunc::Tokenize(output, tokens, "\n", false, false);
// There should be an even number of lines since every line has a context line printed before it
ASSERT_GT(tokens.size(), 0);
ASSERT_EQ(tokens.size() % 2, 0);
for (int i = 0; i < tokens.size(); i += 2)
{
ASSERT_STREQ(tokens[0].c_str(), "C: [Source] = Test");
}
}
struct LoggingTest
: ScopedAllocatorSetupFixture
{
void SetUp() override
{
m_messageHook.EnableTraceContext(true);
}
TraceMessageHook m_messageHook;
};
TEST_F(LoggingTest, TracePrintf_ContainsContextOnEachLine)
{
testing::internal::CaptureStdout();
AZ_TraceContext("Source", "Test");
AZ_TracePrintf("window", "line1\nline2\nline3");
auto output = testing::internal::GetCapturedStdout();
VerifyOutput(output.c_str());
}
TEST_F(LoggingTest, Warning_ContainsContextOnEachLine)
{
testing::internal::CaptureStdout();
AZ_TraceContext("Source", "Test");
AZ_Warning("window", false, "line1\nline2\nline3");
auto output = testing::internal::GetCapturedStdout();
VerifyOutput(output.c_str());
}
TEST_F(LoggingTest, Error_ContainsContextOnEachLine)
{
testing::internal::CaptureStderr();
AZ_TraceContext("Source", "Test");
AZ_TEST_START_TRACE_SUPPRESSION;
AZ_Error("window", false, "line1\nline2\nline3");
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
auto output = testing::internal::GetCapturedStderr();
VerifyOutput(output.c_str());
}
TEST_F(LoggingTest, Assert_ContainsContextOnEachLine)
{
testing::internal::CaptureStderr();
AZ_TraceContext("Source", "Test");
AZ_TEST_START_TRACE_SUPPRESSION;
AZ_Assert(false, "line1\nline2\nline3");
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
auto output = testing::internal::GetCapturedStderr();
VerifyOutput(output.c_str());
}
} // namespace AssetBuilder
@@ -0,0 +1,268 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <TraceMessageHook.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContextLogFormatter.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/PlatformIncl.h>
namespace AssetBuilder
{
constexpr int MaxMessageLength = 4096;
TraceMessageHook::TraceMessageHook()
: m_stacks(nullptr)
, m_inDebugMode(false)
, m_skipErrorsCount(0)
, m_skipWarningsCount(0)
, m_skipPrintfsCount(0)
, m_totalWarningCount(0)
, m_totalErrorCount(0)
{
AssetBuilderSDK::AssetBuilderTraceBus::Handler::BusConnect();
AZ::Debug::TraceMessageBus::Handler::BusConnect();
}
TraceMessageHook::~TraceMessageHook()
{
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
AssetBuilderSDK::AssetBuilderTraceBus::Handler::BusDisconnect();
delete m_stacks;
m_stacks = nullptr;
}
void TraceMessageHook::EnableTraceContext(bool enable)
{
if (enable)
{
if (!m_stacks)
{
m_stacks = new AzToolsFramework::Debug::TraceContextMultiStackHandler();
}
}
else
{
delete m_stacks;
m_stacks = nullptr;
}
}
void TraceMessageHook::EnableDebugMode(bool enable)
{
m_inDebugMode = enable;
}
bool TraceMessageHook::OnAssert(const char* message)
{
if (m_skipErrorsCount == 0)
{
CleanMessage(stderr, "E", message, true);
std::fflush(stderr);
++m_totalErrorCount;
}
else
{
--m_skipErrorsCount;
}
return !m_inDebugMode;
}
bool TraceMessageHook::OnPreError(const char* window, const char* fileName, int line, const char* func, const char* message)
{
if(m_skipErrorsCount == 0)
{
char header[MaxMessageLength];
azsnprintf(header, MaxMessageLength, "%s: Trace::Error\n>\t%s(%d): '%s'\n", window, fileName, line, func);
CleanMessage(stderr, "E", header, false);
CleanMessage(stderr, "E", message, true, ">\t");
++m_totalErrorCount;
}
else
{
--m_skipErrorsCount;
}
return !m_inDebugMode;
}
bool TraceMessageHook::OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message)
{
if (m_skipWarningsCount == 0)
{
char header[MaxMessageLength];
azsnprintf(header, MaxMessageLength, "%s: Trace::Warning\n>\t%s(%d): '%s'\n", window, fileName, line, func);
CleanMessage(stdout, "W", header, false);
CleanMessage(stdout, "W", message, true, ">\t");
++m_totalWarningCount;
}
else
{
--m_skipWarningsCount;
}
return !m_inDebugMode;
}
bool TraceMessageHook::OnException(const char* message)
{
m_isInException = true;
CleanMessage(stderr, "E", message, true);
++m_totalErrorCount;
AZ::Debug::Trace::HandleExceptions(false);
AZ::Debug::Trace::PrintCallstack("", 3); // Skip all the Trace.cpp function calls
// note that the above call ultimately results in a whole bunch of TracePrint/Outputs, which will end up in OnOutput below.
std::fflush(stderr);
std::fflush(stdout);
// if we don't terminate here, the user may get a dialog box from the OS saying that the program crashed.
// we don't want this, because in this case, the program is one of potentially many, many background worker processes
// that are continuously starting/stopping and they'd get flooded by those message boxes.
AZ::Debug::Trace::Terminate(1);
return false;
}
bool TraceMessageHook::OnOutput(const char* /*window*/, const char* message)
{
if (m_isInException) // all messages that occur during an exception should be considered an error.
{
CleanMessage(stderr, "E", message, true);
return true;
}
return false;
}
bool TraceMessageHook::OnPrintf(const char* window, const char* message)
{
if (m_skipPrintfsCount == 0)
{
CleanMessage(stdout, window, message, false);
}
else
{
--m_skipPrintfsCount;
}
return true;
}
void TraceMessageHook::IgnoreNextErrors(AZ::u32 count)
{
m_skipErrorsCount += count;
}
void TraceMessageHook::IgnoreNextWarning(AZ::u32 count)
{
m_skipWarningsCount += count;
}
void TraceMessageHook::IgnoreNextPrintf(AZ::u32 count)
{
m_skipPrintfsCount += count;
}
void TraceMessageHook::ResetWarningCount()
{
m_totalWarningCount = 0;
}
void TraceMessageHook::ResetErrorCount()
{
m_totalErrorCount = 0;
}
AZ::u32 TraceMessageHook::GetWarningCount()
{
return m_totalWarningCount;
}
AZ::u32 TraceMessageHook::GetErrorCount()
{
return m_totalErrorCount;
}
void TraceMessageHook::DumpTraceContext(FILE* stream) const
{
if (m_stacks)
{
AZStd::shared_ptr<const AzToolsFramework::Debug::TraceContextStack> stack = m_stacks->GetCurrentStack();
if (stack)
{
AZStd::string line;
size_t stackSize = stack->GetStackCount();
for (size_t i = 0; i < stackSize; ++i)
{
line.clear();
AzToolsFramework::Debug::TraceContextLogFormatter::PrintLine(line, *stack, i);
CleanMessage(stream, "C", line.c_str(), false, nullptr, false);
}
}
}
}
void TraceMessageHook::CleanMessage(FILE* stream, const char* prefix, const char* message, bool forceFlush, const char* extraPrefix, bool includeTraceContext) const
{
if (message && message[0])
{
AZStd::vector<AZStd::string> lines;
AzFramework::StringFunc::Tokenize(message, lines, '\n', true, true); // Make sure to keep empty lines because it could be intentional blank lines someone has added for formatting reasons
// If the message ended with a newline, remove it, we're adding newlines to each line already
if(lines.back().empty())
{
lines.pop_back();
}
for (const AZStd::string& line : lines)
{
if(includeTraceContext)
{
DumpTraceContext(stream);
}
if (prefix && prefix[0])
{
fprintf(stream, "%s: ", prefix);
}
if(extraPrefix && extraPrefix[0])
{
fprintf(stream, "%s", extraPrefix);
}
fprintf(stream, "%s\n", line.c_str());
}
// Make sure the message ends with a newline
if (message[AZStd::char_traits<char>::length(message) - 1] != '\n')
{
fprintf(stream, "\n");
}
if (forceFlush)
{
fflush(stream);
}
}
}
} // namespace AssetBuilder
@@ -0,0 +1,65 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzToolsFramework/Debug/TraceContextMultiStackHandler.h>
#include <AssetBuilderSDK/AssetBuilderBusses.h>
namespace AssetBuilder
{
class TraceMessageHook
: public AZ::Debug::TraceMessageBus::Handler
, public AssetBuilderSDK::AssetBuilderTraceBus::Handler
{
public:
TraceMessageHook();
~TraceMessageHook() override;
void EnableTraceContext(bool enable);
void EnableDebugMode(bool enable);
bool OnAssert(const char* message) override;
bool OnPreError(const char* window, const char* fileName, int line, const char* func, const char* message);
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message);
bool OnException(const char* message) override;
bool OnPrintf(const char* window, const char* message) override;
bool OnOutput(const char* window, const char* message) override;
void IgnoreNextErrors(AZ::u32 count) override;
void IgnoreNextWarning(AZ::u32 count) override;
void IgnoreNextPrintf(AZ::u32 count) override;
void ResetWarningCount() override;
void ResetErrorCount() override;
AZ::u32 GetWarningCount() override;
AZ::u32 GetErrorCount() override;
void DumpTraceContext(FILE* stream) const;
void CleanMessage(FILE* stream, const char* prefix, const char* message, bool forceFlush, const char* extraPrefix = nullptr, bool includeTraceContext = true) const;
protected:
AzToolsFramework::Debug::TraceContextMultiStackHandler* m_stacks;
AZ::u32 m_skipErrorsCount;
AZ::u32 m_skipWarningsCount;
AZ::u32 m_skipPrintfsCount;
AZ::u32 m_totalWarningCount;
AZ::u32 m_totalErrorCount;
bool m_inDebugMode;
// once we're in an exception, we accept all log data as error, since we will terminate
// this ensures that call stack info (which is 'traced', not 'exceptioned') is present.
bool m_isInException = false;
};
} // namespace AssetBuilder
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Platform/AssetBuilderApplication_darwin.cpp
)
@@ -0,0 +1,22 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
AssetBuilderApplication.h
AssetBuilderApplication.cpp
AssetBuilderComponent.h
AssetBuilderComponent.cpp
main.cpp
AssetBuilderInfo.h
AssetBuilderInfo.cpp
TraceMessageHook.h
TraceMessageHook.cpp
)
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "AssetBuilderApplication.h"
#include "TraceMessageHook.h"
#include "AssetBuilderComponent.h"
int main(int argc, char** argv)
{
AssetBuilderApplication app(&argc, &argv);
AssetBuilder::TraceMessageHook traceMessageHook; // Hook AZ Debug messages and redirect them to stdout
traceMessageHook.EnableTraceContext(true);
AZ::Debug::Trace::HandleExceptions(true);
// Perform an additional check for an override app root argument, and set it in the startup params if appropriate
char destinationRootArgBuffer[AZ_MAX_PATH_LEN];
AZ::ComponentApplication::StartupParameters startupParams;
if (app.GetOptionalAppRootArg(destinationRootArgBuffer, AZ_MAX_PATH_LEN))
{
startupParams.m_appRootOverride = destinationRootArgBuffer;
}
startupParams.m_loadDynamicModules = false;
app.Start(AzFramework::Application::Descriptor(), startupParams);
traceMessageHook.EnableDebugMode(app.IsInDebugMode());
bool result = false;
BuilderBus::BroadcastResult(result, &BuilderBus::Events::Run);
traceMessageHook.EnableTraceContext(false);
app.Stop();
return result ? 0 : 1;
}
@@ -0,0 +1,120 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Math/Uuid.h>
namespace AssetBuilderSDK
{
struct CreateJobsRequest;
struct CreateJobsResponse;
struct ProcessJobRequest;
struct ProcessJobResponse;
struct AssetBuilderDesc;
//! This EBUS is used to send commands from the assetprocessor to the builder
//! Every new builder should implement a listener for this bus and implement the CreateJobs, Shutdown and ProcessJobs functions.
class AssetBuilderCommandBusTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
typedef AZ::Uuid BusIdType;
virtual ~AssetBuilderCommandBusTraits() {};
//! Shutdown() REQUIRED - Handle the message indicating shutdown. Cancel all your tasks and get them stopped ASAP
//! this message will come in from a different thread than your ProcessJob() thread.
//! failure to terminate promptly can cause a hangup on AP shutdown and restart.
virtual void ShutDown() = 0;
};
typedef AZ::EBus<AssetBuilderCommandBusTraits> AssetBuilderCommandBus;
//!This EBUS is used to send information from the builder to the AssetProcessor
class AssetBuilderBusTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
typedef AZStd::recursive_mutex MutexType;
virtual ~AssetBuilderBusTraits() {}
virtual bool FindBuilderInformation(const AZ::Uuid& /*builderGuid*/, AssetBuilderDesc& /*descriptionOut*/) { return false; }
// Use this function to send AssetBuilderDesc info to the assetprocessor
virtual void RegisterBuilderInformation(const AssetBuilderDesc& /*builderDesc*/) {}
// Use this function to register all the component descriptors
virtual void RegisterComponentDescriptor(AZ::ComponentDescriptor* /*descriptor*/) {}
// Log functions to report general builder related messages/error.
virtual void BuilderLog(const AZ::Uuid& /*builderId*/, const char* /*message*/, ...) {}
virtual void BuilderLogV(const AZ::Uuid& /*builderId*/, const char* /*message*/, va_list /*list*/) {}
};
typedef AZ::EBus<AssetBuilderBusTraits> AssetBuilderBus;
//! This EBus provides builders access to the Asset Builders issue tracking facilities.
class AssetBuilderTraceTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual ~AssetBuilderTraceTraits() = default;
//! The next <count> requests that the Asset Builder gets to forward errors to the console
//! will be ignored.
virtual void IgnoreNextErrors(AZ::u32 count) = 0;
//! The next <count> requests that the Asset Builder gets to forward warnings to the console
//! will be ignored.
virtual void IgnoreNextWarning(AZ::u32 count) = 0;
//! The next <count> requests that the Asset Builder gets to forward prints to the console
//! will be ignored.
virtual void IgnoreNextPrintf(AZ::u32 count) = 0;
virtual void ResetWarningCount() = 0;
virtual void ResetErrorCount() = 0;
virtual AZ::u32 GetWarningCount() = 0;
virtual AZ::u32 GetErrorCount() = 0;
};
typedef AZ::EBus<AssetBuilderTraceTraits> AssetBuilderTraceBus;
//! This EBUS is used to send commands from the assetprocessor to a specific job
class JobCommandTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
typedef AZStd::recursive_mutex MutexType;
typedef AZ::s64 BusIdType;
virtual ~JobCommandTraits() {}
//! Handle the message indicating that the specific job needs to cancel.
virtual void Cancel() {}
};
typedef AZ::EBus<JobCommandTraits> JobCommandBus;
}
@@ -0,0 +1,71 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#ifndef ASSETBUILDERUTILEBUSHELPER_H
#define ASSETBUILDERUTILEBUSHELPER_H
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Uuid.h>
namespace AssetBuilderSDK
{
//!This EBUS is used to send commands from the assetprocessor to the builder
class AssetBuilderCommandBusTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
typedef AZ::Uuid BusIdType;
typedef AZStd::recursive_mutex MutexType;
virtual ~AssetBuilderCommandBusTraits() {}
//Shutdown the builder.
virtual void ShutDown() {}
};
typedef AZ::EBus<AssetBuilderCommandBusTraits> AssetBuilderCommandBus;
//!Information that builders will send to the assetprocessor
struct AssetBuilderDesc
{
AZStd::string m_name;//builder name
AZStd::string m_regex;//builder regex
AZ::Uuid m_busId;// builder id
};
//!This EBUS is used to send information from the builder to the AssetProcessor
class AssetBuilderBusTraits
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
typedef AZStd::recursive_mutex MutexType;
virtual ~AssetBuilderBusTraits() {}
//Use this function to send AssetBuilderDesc info to the assetprocessor
virtual void RegisterBuilderInformation(AssetBuilderDesc builderDesc) {}
//Use this function to register all the component descriptors
virtual void RegisterComponentDescriptor(AZ::ComponentDescriptor* descriptor) {}
};
typedef AZ::EBus<AssetBuilderBusTraits> AssetBuilderBus;
}
#endif //ASSETBUILDERUTILEBUSHELPER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,964 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzCore/std/string/regex.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/parallel/atomic.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/containers/bitset.h>
#include <AzFramework/Asset/AssetProcessorMessages.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/std/string/string_view.h>
#include "AssetBuilderBusses.h"
/**
* this define exists to turn on and off the support for legacy m_platformFlags and the concept of platforms as an enum
* If you want to upgrade your system to use the new platform tag system, you can turn this define off in order to strip out
* any references to the old stuff and cause compile-time errors anywhere your code tries to use the legacy API.
* It is recommended that you leave this on so that code besides your own code (for example, in 3rd-party gems) continues to function
* until the responsible party upgrades that code also.
*/
#define ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT
namespace AZ
{
class ComponentDescriptor;
class Entity;
}
// This needs to be up here because it needs to be defined before the hash definition, and the hash needs to be defined before the first use (which occurs further down in this file)
namespace AssetBuilderSDK
{
enum class ProductPathDependencyType : AZ::u32
{
SourceFile,
ProductFile
};
/**
* Product dependency information that the builder will send to the assetprocessor
* Indicates a product asset that depends on another product based on the path
* Should only be used by legacy systems. Prefer ProductDependencies whenever possible
*/
struct ProductPathDependency
{
AZ_CLASS_ALLOCATOR(ProductPathDependency, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ProductPathDependency, "{2632bfae-7490-476f-9214-a6d1f02e6085}");
//! Relative path to the asset dependency
AZStd::string m_dependencyPath;
/**
* Indicates if the dependency path points to a source file or a product file
* A dependency on a source file will be converted into dependencies on all product files produced from the source
* It is preferable to depend on product files whenever possible to avoid introducing unintended dependencies
*/
ProductPathDependencyType m_dependencyType = ProductPathDependencyType::ProductFile;
ProductPathDependency() = default;
ProductPathDependency(AZStd::string_view dependencyPath, ProductPathDependencyType dependencyType);
bool operator==(const ProductPathDependency& rhs) const;
static void Reflect(AZ::ReflectContext* context);
};
}
namespace AZStd
{
template<>
struct hash<AssetBuilderSDK::ProductPathDependency>
{
using argument_type = AssetBuilderSDK::ProductPathDependency;
using result_type = size_t;
result_type operator() (const argument_type& dependency) const
{
size_t h = 0;
hash_combine(h, dependency.m_dependencyPath);
hash_combine(h, dependency.m_dependencyType);
return h;
}
};
} // namespace AZStd
namespace AssetBuilderSDK
{
namespace ComponentTags
{
//! Components with the AssetBuilder tag in their reflect data's attributes as AZ::Edit::Attributes::SystemComponetTags will automatically be created on AssetBuilder startup
const static AZ::Crc32 AssetBuilder = AZ_CRC("AssetBuilder", 0xc739c7d7);
}
extern const char* const ErrorWindow; //Use this window name to log error messages.
extern const char* const WarningWindow; //Use this window name to log warning messages.
extern const char* const InfoWindow; //Use this window name to log info messages.
extern const char* const s_processJobRequestFileName; //!< File name for having job requests send from the Asset Processor.
extern const char* const s_processJobResponseFileName; //!< File name for having job responses returned to the Asset Processor.
// SubIDs uniquely identify a particular output product of a specific source asset
// currently we use a scheme where various bits of the subId (which is a 32 bit unsigned) are used to designate different things.
// we may expand this into a 64-bit "namespace" by adding additional 32 bits at the front at some point, if it becomes necessary.
extern const AZ::u32 SUBID_MASK_ID; //!< mask is 0xFFFF - so you can have up to 64k subids from a single asset before you start running into the upper bits which are used for other reasons.
extern const AZ::u32 SUBID_MASK_LOD_LEVEL; //!< the LOD level can be masked up to 15 LOD levels (it also represents the MIP level). note that it starts at 1.
extern const AZ::u32 SUBID_LOD_LEVEL_SHIFT; //!< the shift to move the LOD level in its expected bits.
extern const AZ::u32 SUBID_FLAG_DIFF; //!< this is a 'diff' map. It may have the alpha, and lod set too if its an alpha of a diff
extern const AZ::u32 SUBID_FLAG_ALPHA; //!< this is an alpha mip or alpha channel.
//! extract only the ID using the above masks
AZ::u32 GetSubID_ID(AZ::u32 packedSubId);
//! extract only the LOD using the above masks. note that it starts at 1, not 0. 0 would be the base asset.
AZ::u32 GetSubID_LOD(AZ::u32 packedSubId);
//! create a subid using the above masks. Note that if you want to add additional bits such as DIFF or ALPHA, you must add them afterwards.
//! fromsubindex contains an existing subindex to replace the LODs and SUBs but no other bits with.
AZ::u32 ConstructSubID(AZ::u32 subIndex, AZ::u32 lodLevel, AZ::u32 fromSubIndex = 0);
//! Initializes the serialization context with all the reflection information for AssetBuilderSDK structures
//! Should be called on startup by standalone builders. Builders run by AssetBuilder will have this set up already
void InitializeSerializationContext();
void InitializeBehaviorContext();
//! This method is used for logging builder related messages/error
//! Do not use this inside ProcessJob, use AZ_TracePrintF instead. This is only for general messages about your builder, not for job-specific messages
extern void BuilderLog(AZ::Uuid builderId, const char* message, ...);
#if defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
/**
* DEPRECATED - LEGACY - this is retained for code compatbility with previous versions. Please just use the m_enabledPlatforms
* structure in all new code.
**/
enum Platform : AZ::u32
{
Platform_NONE = 0x00,
Platform_PC = 0x01,
Platform_ES3 = 0x02,
Platform_IOS = 0x04,
Platform_OSX = 0x08,
Platform_XENIA = 0x10,
Platform_PROVO = 0x20,
Platform_SALEM = 0x40,
Platform_JASPER = 0x80,
//! if you add a new platform entry to this enum, you must add it to allplatforms as well otherwise that platform would not be considered valid.
AllPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_XENIA | Platform_PROVO | Platform_SALEM | Platform_JASPER
};
#endif // defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
//! Map data structure to holder parameters that are passed into a job for ProcessJob requests.
//! These parameters can optionally be set during the create job function of the builder so that they are passed along
//! to the ProcessJobFunction. The values (key and value) are arbitrary and is up to the builder on how to use them
typedef AZStd::unordered_map<AZ::u32, AZStd::string> JobParameterMap;
//! Callback function type for creating jobs from job requests
typedef AZStd::function<void(const CreateJobsRequest& request, CreateJobsResponse& response)> CreateJobFunction;
//! Callback function type for processing jobs from process job requests
typedef AZStd::function<void(const ProcessJobRequest& request, ProcessJobResponse& response)> ProcessJobFunction;
//! Structure defining the type of pattern to use to apply
struct AssetBuilderPattern
{
AZ_CLASS_ALLOCATOR(AssetBuilderPattern, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(AssetBuilderPattern, "{A8818121-D106-495E-9776-11F59E897BAD}");
enum PatternType
{
//! The pattern is a file wildcard pattern (glob)
Wildcard,
//! The pattern is a regular expression pattern
Regex
};
AZStd::string m_pattern;
PatternType m_type;
AssetBuilderPattern() = default;
AssetBuilderPattern(const AssetBuilderPattern& src) = default;
AssetBuilderPattern(const AZStd::string& pattern, PatternType type);
AZStd::string ToString() const;
static void Reflect(AZ::ReflectContext* context);
};
//! This class represents a matching pattern that is based on AssetBuilderSDK::AssetBuilderPattern::PatternType, which can either be a regex
//! pattern or a wildcard (glob) pattern
class FilePatternMatcher
{
public:
FilePatternMatcher() = default;
explicit FilePatternMatcher(const AssetBuilderSDK::AssetBuilderPattern& pattern);
FilePatternMatcher(const AZStd::string& pattern, AssetBuilderSDK::AssetBuilderPattern::PatternType type);
FilePatternMatcher(const FilePatternMatcher& copy);
typedef AZStd::regex RegexType;
FilePatternMatcher& operator=(const FilePatternMatcher& copy);
bool MatchesPath(const AZStd::string& assetPath) const;
bool IsValid() const;
AZStd::string GetErrorString() const;
const AssetBuilderSDK::AssetBuilderPattern& GetBuilderPattern() const;
protected:
static bool ValidatePatternRegex(const AZStd::string& pattern);
AssetBuilderSDK::AssetBuilderPattern m_pattern;
RegexType m_regex;
AZStd::string m_errorString;
bool m_isRegex;
bool m_isValid;
};
//!Information that builders will send to the assetprocessor
struct AssetBuilderDesc
{
AZ_CLASS_ALLOCATOR(AssetBuilderDesc, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(AssetBuilderDesc, "{7778EB3D-7B3B-4231-80C0-94C4226309AF}");
enum class AssetBuilderType
{
Internal, //! Internal Recognizer builders for example. Internal Builders are created and run inside the AP.
External //! External builders are those located within gems that run inside an AssetBuilder application.
};
// you don't have to set any flags but they are used for optimization.
enum BuilderFlags : AZ::u8
{
BF_None = 0,
BF_EmitsNoDependencies = 1<<0, // if you set this flag, dependency-related parts in the code will be skipped
BF_DeleteLastKnownGoodProductOnFailure = 1<<1, // if processing fails, delete previous successful product if it exists
};
//! The name of the Builder
AZStd::string m_name;
//! The collection of asset builder patterns that the builder will use to
//! determine if a file will be processed by that builder
AZStd::vector<AssetBuilderPattern> m_patterns;
//! The builder unique ID
AZ::Uuid m_busId;
//! Changing this version number will cause all your assets to be re-submitted to the builder for job creation and rebuilding.
int m_version = 0;
//! The required create job function callback that the asset processor will call during the job creation phase
CreateJobFunction m_createJobFunction;
//! The required process job function callback that the asset processor will call during the job processing phase
ProcessJobFunction m_processJobFunction;
//! The builder type. We set this to External by default, as that is the typical set up for custom builders (builders in gems and legacy dll builders).
AssetBuilderType m_builderType = AssetBuilderType::External;
/** Analysis Fingerprint
* you can optionally emit an analysis fingerprint, or leave this empty.
* The Analysis Fingerprint, used to quickly skip analysis if the source files modtime has not changed.
* If your analysis fingerprint DOES change, then all source files will be sent to your CreateJobs function regardless of modtime changes.
* This does not necessarily mean that the jobs will need doing, just that CreateJobs will be called.
* For best results, make sure your analysis fingerprint only changes when its likely that you need to re-analyze source files for changes, which
* may result in job fingerprints to be diffent (for example, if you have changed your logic inside your builder).
**/
AZStd::string m_analysisFingerprint;
//! You don't have to set any flags, but if you do, it can improve speed.
//! If you change your flags, bump the version number of your builder, too.
AZ::u8 m_flags = 0;
AZStd::unordered_map<AZStd::string, AZ::u8> m_flagsByJobKey;
void AddFlags(AZ::u8 flag, const AZStd::string& jobKey);
bool HasFlag(AZ::u8 flag, const AZStd::string& jobKey) const;
bool IsExternalBuilder() const;
// Note that we don't serialize the function pointer fields as part of the registration since they should not be
// sent over the wire.
static void Reflect(AZ::ReflectContext* context);
};
//! Source file dependency information that the builder will send to the assetprocessor
//! It is important to note that the builder do not need to provide both the sourceFileDependencyUUID or sourceFileDependencyPath info to the asset processor,
//! any one of them should be sufficient
struct SourceFileDependency
{
AZ_CLASS_ALLOCATOR(SourceFileDependency, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(SourceFileDependency, "{d3c055d8-b5e8-44ab-a6ce-1ecb0da091ec}");
// Corresponds to SourceFileDependencyEntry TypeOfDependency Values
enum class SourceFileDependencyType : AZ::u32
{
Absolute, // Corresponds to DEP_SourceToSource
Wildcards // DEP_SourceLikeMatch
};
/** Filepath on which the source file depends, it can be either be a relative path from the assets folder, or an absolute path.
* if it's relative, the asset processor will check every watched folder in the order specified in the assetprocessor config file until it finds that file.
* For example if the builder sends a SourceFileDependency with m_sourceFileDependencyPath = "texture/blah.tif" to the asset processor,
* it will check all watch folders for a file whose relative path with regard to it is "texture/blah.tif".
* and supposing it finds it in "C:/dev/gamename/texture/blah.tif", it will use that as the dependency.
* You can also send absolute path, which will obey the usual overriding rules.
* @note You must EITHER provide the m_sourceFileDependencyPath OR the m_sourceFileDependencyUUID.
**/
AZStd::string m_sourceFileDependencyPath;
/** UUID of the file on which the source file depends.
* @note You must EITHER provide the m_sourceFileDependencyPath OR the m_sourceFileDependencyUUID if you have that instead.
*/
AZ::Uuid m_sourceFileDependencyUUID = AZ::Uuid::CreateNull();
SourceFileDependencyType m_sourceDependencyType{ SourceFileDependencyType::Absolute };
SourceFileDependency() = default;
SourceFileDependency(const AZStd::string& sourceFileDependencyPath, AZ::Uuid sourceFileDependencyUUID, SourceFileDependencyType sourceDependencyType = SourceFileDependencyType::Absolute)
: m_sourceFileDependencyPath(sourceFileDependencyPath)
, m_sourceFileDependencyUUID(sourceFileDependencyUUID)
, m_sourceDependencyType(sourceDependencyType)
{
}
SourceFileDependency(AZStd::string&& sourceFileDependencyPath, AZ::Uuid sourceFileDependencyUUID, SourceFileDependencyType sourceDependencyType = SourceFileDependencyType::Absolute)
: m_sourceFileDependencyPath(AZStd::move(sourceFileDependencyPath))
, m_sourceFileDependencyUUID(sourceFileDependencyUUID)
, m_sourceDependencyType(sourceDependencyType)
{
}
AZStd::string ToString() const;
static void Reflect(AZ::ReflectContext* context);
};
enum class JobDependencyType : AZ::u32
{
//! This implies that the dependent job should get processed by the assetprocessor, if the fingerprint of job it depends on changes.
Fingerprint,
//! This implies that the dependent job should only run after the job it depends on is processed by the assetprocessor.
Order,
//! This is similiar to Order where the dependent job should only run after all the jobs it depends on are processed by the assetprocessor.
//! The difference is that here only those dependent jobs matter that have never been processed by the asset processor.
//! Also important to note is the fingerprint of the dependent jobs will not alter the the fingerprint of the job.
OrderOnce,
};
//! Job dependency information that the builder will send to the assetprocessor.
struct JobDependency
{
AZ_CLASS_ALLOCATOR(JobDependency, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(JobDependency, "{93A9D915-8C9E-4588-8D86-578C01EEA388}");
//! Source file dependency information that the builder will send to the assetprocessor
//! It is important to note that the builder do not need to provide both the sourceFileDependencyUUID or sourceFileDependencyPath info to the asset processor,
//! any one of them should be sufficient
SourceFileDependency m_sourceFile;
//! JobKey of the dependent job
AZStd::string m_jobKey;
//! Platform Identifier of the dependent job
AZStd::string m_platformIdentifier;
//! Type of Job Dependency (order or fingerprint)
JobDependencyType m_type;
JobDependency() = default;
JobDependency(const AZStd::string& jobKey, const AZStd::string& platformIdentifier, const JobDependencyType& type, const SourceFileDependency& sourceFile);
static void Reflect(AZ::ReflectContext* context);
};
//! JobDescriptor is used by the builder to store job related information
struct JobDescriptor
{
AZ_CLASS_ALLOCATOR(JobDescriptor, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(JobDescriptor, "{bd0472a4-7634-41f3-97ef-00f3b239bae2}");
//! Any builder specific parameters to pass to the Process Job Request
JobParameterMap m_jobParameters;
//! Any additional info that should be taken into account during fingerprinting for this job
AZStd::string m_additionalFingerprintInfo;
//! Job specific key, e.g. TIFF Job, etc
AZStd::string m_jobKey;
#if defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
/**
* DEPRECATED - this remains only for backward compatiblity with older modules
* consider using m_platformIdentifier (via getter/setter) instead. This will still work but as new platforms are added
* using the data-driven approach, your enum will no longer be sufficient.
*/
int m_platform = Platform_NONE;
#endif // defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
//! Priority value for the jobs within the job queue. If less than zero, than the priority of this job is not considered or or is lowest priority.
//! If zero or greater, the value is prioritized by this number (the higher the number, the higher priority). Note: priorities are set within critical
//! and non-critical job separately.
int m_priority = -1;
//! Flag to determine if this is a critical job or not. Critical jobs are given the higher priority in the processing queue than non-critical jobs
bool m_critical = false;
//! Flag to determine whether we need to check the input file for exclusive lock before we process the job
bool m_checkExclusiveLock = false;
//! Flag to determine whether we need to check the server for the outputs of this job
//! before we start processing the job locally.
//! If the asset processor is running in server mode then this will be used to determine whether we need
//! to store the outputs of this jobs in the server.
bool m_checkServer = false;
//! This is required for jobs that want to declare job dependency on other jobs.
AZStd::vector<JobDependency> m_jobDependencyList;
//! If set to true, reported errors, asserts and exceptions will automatically cause the job to fail even is ProcessJobResult_Success is the result code.
bool m_failOnError = false;
/**
* construct using a platformIdentifier from your CreateJobsRequest. it is the m_identifier member of the PlatformInfo.
*/
JobDescriptor(const AZStd::string& additionalFingerprintInfo, AZStd::string jobKey, const char* platformIdentifier);
#if defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
/**
* DEPRECATED - please use the above constructor
* This is retained for backward compatiblity only
* Construct a JobDescriptor using the platform index from the Platform enum.
*/
JobDescriptor(AZStd::string additionalFingerprintInfo, int platform, const AZStd::string& jobKey);
#endif // defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
JobDescriptor() = default;
static void Reflect(AZ::ReflectContext* context);
/** Use this to set the platform identifier. it knows when it needs to retroactively compute
* the old m_platform flag when that code is enabled.
*/
void SetPlatformIdentifier(const char* platformIdentifier);
const AZStd::string& GetPlatformIdentifier() const;
protected:
/**
* This describes which platform its for. It should match one of the enabled platforms passed into CreateJobs.
* It is the identifier of the platform from that PlatformInfo struct.
*/
AZStd::string m_platformIdentifier;
};
//! RegisterBuilderRequest contains input data that will be sent by the AssetProcessor to the builder during the startup registration phase
struct RegisterBuilderRequest
{
AZ_CLASS_ALLOCATOR(RegisterBuilderRequest, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(RegisterBuilderRequest, "{7C6C5198-4766-42B8-9A1E-48479CE2F5EA}");
AZStd::string m_filePath;
RegisterBuilderRequest() {}
explicit RegisterBuilderRequest(const AZStd::string& filePath)
: m_filePath(filePath)
{
}
static void Reflect(AZ::ReflectContext* context);
};
//! INTERNAL USE ONLY - RegisterBuilderResponse contains registration data that will be sent by the builder to the AssetProcessor in response to RegisterBuilderRequest
struct RegisterBuilderResponse
{
AZ_CLASS_ALLOCATOR(RegisterBuilderResponse, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(RegisterBuilderResponse, "{0AE5583F-C763-410E-BA7F-78BD90546C01}");
AZStd::vector<AssetBuilderDesc> m_assetBuilderDescList;
static void Reflect(AZ::ReflectContext* context);
};
/**
* This tells you about a platform in your CreateJobsRequest or your ProcessJobRequest
*/
struct PlatformInfo
{
AZ_CLASS_ALLOCATOR(PlatformInfo, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(PlatformInfo, "{F7DA39A5-C319-4552-954B-3479E2454D3F}");
AZStd::string m_identifier; ///< like "pc" or "es3" or "ios"...
AZStd::unordered_set<AZStd::string> m_tags; ///< The tags like "console" or "tools" on that platform
PlatformInfo() = default;
PlatformInfo(const char* identifier, const AZStd::unordered_set<AZStd::string>& tags);
bool operator==(const PlatformInfo& other);
///! utility function. It just searches the set for you:
bool HasTag(const char* tag) const;
static void Reflect(AZ::ReflectContext* context);
static AZStd::string PlatformVectorAsString(const AZStd::vector<PlatformInfo>& platforms);
};
//! CreateJobsRequest contains input job data that will be send by the AssetProcessor to the builder for creating jobs
struct CreateJobsRequest
{
AZ_CLASS_ALLOCATOR(CreateJobsRequest, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(CreateJobsRequest, "{02d470fb-4cb6-4cd7-876f-f0652910ff75}");
//! The builder id to identify which builder will process this job request
AZ::Uuid m_builderid; // builder id
//! m_watchFolder contains the subfolder that the sourceFile came from, out of all the folders being watched by the Asset Processor.
//! If you combine the Watch Folder with the Source File (m_sourceFile), you will result in the full absolute path to the file.
AZStd::string m_watchFolder;
//! The source file path that is relative to the watch folder (m_watchFolder)
AZStd::string m_sourceFile;
AZ::Uuid m_sourceFileUUID; ///< each source file has a unique UUID.
//! Information about each platform you are expected to build is stored here.
//! You can emit any number of jobs to produce some or all of the assets for each of these platforms.
AZStd::vector<PlatformInfo> m_enabledPlatforms;
CreateJobsRequest();
CreateJobsRequest(AZ::Uuid builderid, AZStd::string sourceFile, AZStd::string watchFolder, const AZStd::vector<PlatformInfo>& enabledPlatforms, const AZ::Uuid& sourceFileUuid);
/**
* New Data-driven platform API - will return true if the m_enabledPlatforms contains
* a platform with that identifier
*/
bool HasPlatform(const char* platformIdentifier) const;
/**
* New Data-driven platform API - will return true if the m_enabledPlatforms contains
* a platform which itself contains that tag. Note that multiple platforms may match this tag.
*/
bool HasPlatformWithTag(const char* platformTag) const;
#if defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
/**
* Legacy - DEPRECATED - use m_enabledPlatforms instead.
* returns the number of platforms that are enabled for the source file
*/
size_t GetEnabledPlatformsCount() const;
/***
* Legacy - DEPRECATED - use m_enabledPlatforms instead.
* returns the enabled platform by index, if no platform is found then we will return Platform_NONE.
*/
AssetBuilderSDK::Platform GetEnabledPlatformAt(size_t index) const;
/***
* Legacy - DEPRECATED - use m_enabledPlatforms instead.
* determine whether the platform is enabled or not, returns true if enabled otherwise false
*/
bool IsPlatformEnabled(AZ::u32 platform) const;
/***
* Legacy - DEPRECATED - use m_enabledPlatforms instead.
* determine whether the inputted platform is valid or not, returns true if valid otherwise false
*/
bool IsPlatformValid(AZ::u32 platform) const;
/**
* Legacy - deprecated! Only here for backward compatibility. Will not support new platforms - please use the m_enabledPlatform APIs going forward
* Platform flags informs the builder which platforms the AssetProcessor is interested in. Its the platforms enum as bitmasks
*/
int m_platformFlags = 0;
#endif // defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
static void Reflect(AZ::ReflectContext* context);
};
//! Possible result codes from CreateJobs requests
enum class CreateJobsResultCode
{
//! Jobs were created successfully
Success,
//! Jobs failed to be created
Failed,
//! The builder is in the process of shutting down
ShuttingDown
};
//! CreateJobsResponse contains job data that will be send by the builder to the assetProcessor in response to CreateJobsRequest
struct CreateJobsResponse
{
AZ_CLASS_ALLOCATOR(CreateJobsResponse, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(CreateJobsResponse, "{32a27d68-25bc-4425-a12b-bab961d6afcd}");
CreateJobsResultCode m_result = CreateJobsResultCode::Failed; // The result code from the create jobs request
AZStd::vector<SourceFileDependency> m_sourceFileDependencyList; // This is required for source files that want to declare dependencies on other source files.
AZStd::vector<JobDescriptor> m_createJobOutputs;
bool Succeeded() const;
static void Reflect(AZ::ReflectContext* context);
};
//! Product dependency information that the builder will send to the assetprocessor
//! Indicates a product asset that depends on another product asset
struct ProductDependency
{
AZ_CLASS_ALLOCATOR(ProductDependency, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ProductDependency, "{54338921-b437-4f39-a0da-b1d0d1ee7b57}");
//! ID of the asset dependency
AZ::Data::AssetId m_dependencyId;
AZ::Data::ProductDependencyInfo::ProductDependencyFlags m_flags;
// By default, initialize the dependency flags to "NoLoad" so that dependent assets aren't triggered to load.
// Only set dependent assets to load if the creation of a product dependency explicitly requests it. This makes it
// more likely to prevent accidental loads when creating dependencies based solely on IDs or other implicit asset
// references.
ProductDependency()
: m_flags(AZ::Data::ProductDependencyInfo::CreateFlags(AZ::Data::AssetLoadBehavior::NoLoad))
{
}
ProductDependency(AZ::Data::AssetId dependencyId, const AZStd::bitset<64>& flags);
static void Reflect(AZ::ReflectContext* context);
};
using ProductPathDependencySet = AZStd::unordered_set<AssetBuilderSDK::ProductPathDependency>;
//! JobProduct is used by the builder to store job product information
struct JobProduct
{
AZ_CLASS_ALLOCATOR(JobProduct, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(JobProduct, "{d1d35d2c-3e4a-45c6-a13a-e20056344516}");
AZStd::string m_productFileName; // relative or absolute product file path
AZ::Data::AssetType m_productAssetType = AZ::Data::AssetType::CreateNull(); // the type of asset this is
AZ::u32 m_productSubID; ///< a stable product identifier - see note below.
/// LegacySUBIds are other names for the same product for legacy compatibility.
/// if you ever referred to this product by a different sub-id previously but have decided to change your numbering scheme
/// You should emit the prior sub ids into this array. If we ever go looking for an asset and we fail to find it under a
/// canonical product SubID, the system will attempt to look it up in the list of "previously known as..." legacy subIds in case
/// the source data it is reading is old. This allows you to change your subID scheme at any time as long as you include
/// the old scheme in the legacySubIDs list.
AZStd::vector<AZ::u32> m_legacySubIDs;
// SUB ID context: A Stable sub id means a few things. Products (game ready assets) are identified in the engine by AZ::Data::AssetId, which is a combination of source guid which is random and this product sub id. AssetType is currently NOT USED to differentiate assets by the system. So if two or more products of the same source are for the same platform they can not generate the same sub id!!! If they did this would be a COLLISION!!! which would not allow the rngine to access one or more of the products!!! Not using asset type in the differentiation may change in the future, but it is the way it is done for now.
// SUB ID RULES:
// 1. The builder alone is responsible for determining asset type and sub id.
// 2. The sub id has to be build run stable, meaning if the builder were to run again for the same source the same sub id would be generated by the builder to identify this product.
// 3. The sub id has to be location stable, meaning they can not be based on the location of the source or product, so if the source was moved to a different location it should still produce the same sub id for the same product.
// 4. The sub id has to be platform stable, meaning if the builder were to make the equivalent product for a different platform the sub id for the equivalent product on the other platform should be the same.
// 5. The sub id has to be multi output stable and mutually exclusive, meaning if your builder outputs multiple products from a source, the product sub id for each product must be different from one another and reproducible. So if you use an incrementing number scheme to differentiate products, that must also be stable, even when the source changes. So if a change occurs to the source, it gets rebuilt and the sub ids must still be the same. Put another way, if your builder outputs multiple product files, and produces the number and order and type of product, no matter what change to the source is made, then you're good. However, if changing the source may result in less or more products than last time, you may have a problem. The same products this time must have the same sub id as last time and can not have shifted up or down. Its ok if the extra product has the next new number, or if one less product is produced doesn't effect the others, in short they can never shift ids which would be the case for incrementing ids if one should no longer be produced. Note that the builder has no other information from run to run than the source data, it can not access any other data, source, product, database or otherwise receive data from any previous run. If the builder used an enumerated value for different outputs, that would work, say if he diffuse output always uses the enumerated value sub id 2 and the alpha always used 6, that should be fine, even if the source is modified such that it no longer outputs an alpha, the diffuse would still always map to 2.
// SUGGESTIONS:
// 1. If your builder only ever has one product for a source then we recommend that sub id be set to 0, this should satisfy all the above rules.
// 2. Do not base sub id on file paths, if the location of source or destination changes the sub id will not be stable.
// 3. Do not base sub id on source or product file name, extensions usually differ per platform and across platform they should be the stable.
// 4. It might be ok to base sub id on extension-less product file name. It seems likely it would be stable as the product name would most likely be the same no matter its location as the path to the file and files extension could be different per platform and thus using only the extension-less file name would mostly likely be the same across platform. Be careful though, because if you output many same named files just with different extensions FOR THE SAME PLATFORM you will have collision problems.
// 5. Basing the sub id on a simple incrementing number may be reasonable ONLY if order can never change, or the order if changed it would not matter. This may make sense for mip levels of textures if produced as separate products such that the sub id is equal to mip level, or lods for a mesh such that the sub id is the lod level.
// 6. Think about using some other encoding scheme like using enumerations or using flag bits. If we do then we might be able to guess the sub id at runtime, that could be useful. Name spacing using the upper bits might be useful for final determination of product. This could be part of a localization scheme, or user settings options like choosing green blood via upper bits, or switching between products built by different builders which have stable lower bits and different name space upper bits. I am not currently convinced that encoding information into the sub id like this is a really great idea, however if it does not violate the rules, it is allowed, and it may solve a problem or two for specific systems.
// 7. A Tagging system for products (even sources?) that allows the builder to add any tag it want to a product that would be available at tool time (and at runtime?) might be a better way than trying to encode that kind of data in product sub id's.
//! Product assets this asset depends on
AZStd::vector<ProductDependency> m_dependencies;
/// Dependencies specified by relative path in the resource
/// Paths should only be used in legacy systems, put ProductDependency objects in m_dependencies wherever possible.
ProductPathDependencySet m_pathDependencies;
/// Indicate to Asset Processor that the builder has output any possible dependencies (including if there are none).
/// This should only be set if the builder really does take care of outputting its dependencies OR the output product never has dependencies.
/// When false, AP will emit a warning that dependencies have not been handled.
bool m_dependenciesHandled{ false };
JobProduct() = default;
JobProduct(const AZStd::string& productName, AZ::Data::AssetType productAssetType = AZ::Data::AssetType::CreateNull(), AZ::u32 productSubID = 0);
JobProduct(AZStd::string&& productName, AZ::Data::AssetType productAssetType = AZ::Data::AssetType::CreateNull(), AZ::u32 productSubID = 0);
//////////////////////////////////////////////////////////////////////////
// Legacy compatibility
// when builders output asset type, but don't specify what type they actually are, we guess by file extension and other
// markers. This is not ideal. If you're writing a new builder, endeavor to actually select a product asset type and a subId
// that matches your needs.
static AZ::Data::AssetType InferAssetTypeByProductFileName(const char* productFile);
static AZ::u32 InferSubIDFromProductFileName(const AZ::Data::AssetType& assetType, const char* productFile);
//////////////////////////////////////////////////////////////////////////
static void Reflect(AZ::ReflectContext* context);
};
//! ProcessJobRequest contains input job data that will be send by the AssetProcessor to the builder for processing jobs
struct ProcessJobRequest
{
AZ_CLASS_ALLOCATOR(ProcessJobRequest, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ProcessJobRequest, "{20461454-d2f9-4079-ab95-703905e06002}");
AZStd::string m_sourceFile; ///! relative source file name
AZStd::string m_watchFolder; ///! watch folder for this source file
AZStd::string m_fullPath; ///! full source file name
AZ::Uuid m_builderGuid; ///! builder id
JobDescriptor m_jobDescription; ///! job descriptor for this job. Note that this still contains the job parameters from when you emitted it during CreateJobs
PlatformInfo m_platformInfo; ///! the information about the platform that this job was emitted for.
AZStd::string m_tempDirPath; // temp directory that the builder should use to create job outputs for this job request
AZ::u64 m_jobId; ///! job id for this job, this is also the address for the JobCancelListener
AZ::Uuid m_sourceFileUUID; ///! the UUID of the source file. Will be used as the uuid of the AssetID of the product when combined with the subID.
AZStd::vector<SourceFileDependency> m_sourceFileDependencyList;
static void Reflect(AZ::ReflectContext* context);
};
enum ProcessJobResultCode
{
ProcessJobResult_Success = 0,
ProcessJobResult_Failed = 1,
ProcessJobResult_Crashed = 2,
ProcessJobResult_Cancelled = 3,
ProcessJobResult_NetworkIssue = 4
};
//! ProcessJobResponse contains job data that will be send by the builder to the assetProcessor in response to ProcessJobRequest
struct ProcessJobResponse
{
AZ_CLASS_ALLOCATOR(ProcessJobResponse, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(ProcessJobResponse, "{6b48ada5-0d52-43be-ad57-0bf8aeaef04b}");
ProcessJobResultCode m_resultCode = ProcessJobResult_Failed;
AZStd::vector<JobProduct> m_outputProducts;
bool m_requiresSubIdGeneration = true; //!< Used to determine if legacy RC products need sub ids generated for them.
//! Populate m_sourcesToReprocess with sources by absolute path which you want to trigger a rebuild for
//! To reprocess these sources, make sure to update fingerprints in CreateJobs of those builders which process them, like changing source dependencies.
AZStd::vector<AZStd::string> m_sourcesToReprocess;
bool Succeeded() const;
static void Reflect(AZ::ReflectContext* context);
};
//! BuilderHelloRequest is sent by an AssetBuilder that is attempting to connect to the AssetProcessor to register itself as a worker
class BuilderHelloRequest : public AzFramework::AssetSystem::BaseAssetProcessorMessage
{
public:
AZ_CLASS_ALLOCATOR(BuilderHelloRequest, AZ::OSAllocator, 0);
AZ_RTTI(BuilderHelloRequest, "{5fab5962-a1d8-42a5-bf7a-fb1a8c5a9588}", BaseAssetProcessorMessage);
static void Reflect(AZ::ReflectContext* context);
static unsigned int MessageType();
unsigned int GetMessageType() const override;
//! Unique ID assigned to this builder to identify it
AZ::Uuid m_uuid = AZ::Uuid::CreateNull();
};
//! BuilderHelloResponse contains the AssetProcessor's response to a builder connection attempt, indicating if it is accepted and the ID that it was assigned
class BuilderHelloResponse : public AzFramework::AssetSystem::BaseAssetProcessorMessage
{
public:
AZ_CLASS_ALLOCATOR(BuilderHelloResponse, AZ::OSAllocator, 0);
AZ_RTTI(BuilderHelloResponse, "{5f3d7c11-6639-4c6f-980a-32be546903c2}", BaseAssetProcessorMessage);
static void Reflect(AZ::ReflectContext* context);
unsigned int GetMessageType() const override;
//! Indicates if the builder was accepted by the AP
bool m_accepted = false;
//! Unique ID assigned to the builder. If the builder isn't a local process, this is the ID assigned by the AP
AZ::Uuid m_uuid = AZ::Uuid::CreateNull();
};
class CreateJobsNetRequest : public AzFramework::AssetSystem::BaseAssetProcessorMessage
{
public:
AZ_CLASS_ALLOCATOR(CreateJobsNetRequest, AZ::OSAllocator, 0);
AZ_RTTI(CreateJobsNetRequest, "{97fa717d-3a09-4d21-95c6-b2eafd773f1c}", BaseAssetProcessorMessage);
static void Reflect(AZ::ReflectContext* context);
static unsigned int MessageType();
unsigned int GetMessageType() const override;
CreateJobsRequest m_request;
};
class CreateJobsNetResponse : public AzFramework::AssetSystem::BaseAssetProcessorMessage
{
public:
AZ_CLASS_ALLOCATOR(CreateJobsNetResponse, AZ::OSAllocator, 0);
AZ_RTTI(CreateJobsNetResponse, "{b2c7c2d3-b60e-4b27-b699-43e0ba991c33}", BaseAssetProcessorMessage);
static void Reflect(AZ::ReflectContext* context);
unsigned int GetMessageType() const override;
CreateJobsResponse m_response;
};
class ProcessJobNetRequest : public AzFramework::AssetSystem::BaseAssetProcessorMessage
{
public:
AZ_CLASS_ALLOCATOR(ProcessJobNetRequest, AZ::OSAllocator, 0);
AZ_RTTI(ProcessJobNetRequest, "{05288de1-020b-48db-b9de-715f17284efa}", BaseAssetProcessorMessage);
static void Reflect(AZ::ReflectContext* context);
static unsigned int MessageType();
unsigned int GetMessageType() const override;
ProcessJobRequest m_request;
};
class ProcessJobNetResponse : public AzFramework::AssetSystem::BaseAssetProcessorMessage
{
public:
AZ_CLASS_ALLOCATOR(ProcessJobNetResponse, AZ::OSAllocator, 0);
AZ_RTTI(ProcessJobNetResponse, "{26ddf882-246c-4cfb-912f-9b8e389df4f6}", BaseAssetProcessorMessage);
static void Reflect(AZ::ReflectContext* context);
unsigned int GetMessageType() const override;
ProcessJobResponse m_response;
};
//! JobCancelListener can be used by builders in their processJob method to listen for job cancellation request.
//! The address of this listener is the jobid which can be found in the process job request.
class JobCancelListener : public JobCommandBus::Handler
{
public:
explicit JobCancelListener(AZ::u64 jobId);
~JobCancelListener() override;
JobCancelListener(const JobCancelListener&) = delete;
//////////////////////////////////////////////////////////////////////////
//!JobCommandBus::Handler overrides
//!Note: This will be called on a thread other than your processing job thread.
//!You can derive from JobCancelListener and reimplement Cancel if you need to do something special in order to cancel your job.
void Cancel() override;
///////////////////////////////////////////////////////////////////////
bool IsCancelled() const;
private:
AZStd::atomic_bool m_cancelled;
};
// the Assert Absorber here is used to absorb asserts during regex creation.
// it only absorbs asserts spawned by this thread;
class AssertAbsorber
: public AZ::Debug::TraceMessageBus::Handler
{
public:
AssertAbsorber();
~AssertAbsorber();
bool OnAssert(const char* message) override;
AZStd::string m_assertMessage;
// only absorb messages for your thread!
static AZ_THREAD_LOCAL bool s_onAbsorbThread;
};
//! Trace hook for asserts/errors.
//! This allows us to detect any errors that occur during a job so we can fail it.
class AssertAndErrorAbsorber
: public AZ::Debug::TraceMessageBus::Handler
{
public:
explicit AssertAndErrorAbsorber(bool errorsWillFailJob);
~AssertAndErrorAbsorber() override;
bool OnAssert(const char* message) override;
bool OnError(const char* window, const char* message) override;
size_t GetErrorCount() const;
private:
bool m_errorsWillFailJob;
size_t m_errorsOccurred = 0;
//! The id of the thread that created this object.
//! There can be multiple builders running at once, so we need to filter out ones coming from other builders
AZStd::thread_id m_jobThreadId;
};
} // namespace AssetBuilderSDK
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(AssetBuilderSDK::AssetBuilderPattern::PatternType, "{8519E97D-1159-4CA4-A6DD-16043349B15A}");
AZ_TYPE_INFO_SPECIALIZE(AssetBuilderSDK::CreateJobsResultCode, "{D3F90549-CE6C-4155-BE19-33E4C05373DB}");
AZ_TYPE_INFO_SPECIALIZE(AssetBuilderSDK::JobDependencyType, "{854ADE4E-0C2F-43BC-B5F6-8D99C26A17DF}");
AZ_TYPE_INFO_SPECIALIZE(AssetBuilderSDK::ProcessJobResultCode, "{15797D63-4980-436A-9DE1-E0CCA9B5DB19}");
AZ_TYPE_INFO_SPECIALIZE(AssetBuilderSDK::ProductPathDependencyType, "{EF77742B-9627-4072-B431-396AA7183C80}");
AZ_TYPE_INFO_SPECIALIZE(AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType, "{BE9C8805-DB17-4500-944A-EB33FD0BE347}");
}
//! This macro should be used by every AssetBuilder to register itself,
//! AssetProcessor uses these exported function to identify whether a dll is an Asset Builder or not
//! If you want something highly custom you can do these entry points yourself instead of using the macro.
#define REGISTER_ASSETBUILDER \
extern void BuilderOnInit(); \
extern void BuilderDestroy(); \
extern void BuilderRegisterDescriptors(); \
extern void BuilderAddComponents(AZ::Entity * entity); \
extern "C" \
{ \
AZ_DLL_EXPORT int IsAssetBuilder() \
{ \
return 0; \
} \
\
AZ_DLL_EXPORT void InitializeModule(AZ::EnvironmentInstance sharedEnvironment) \
{ \
AZ::Environment::Attach(sharedEnvironment); \
BuilderOnInit(); \
} \
\
AZ_DLL_EXPORT void UninitializeModule() \
{ \
BuilderDestroy(); \
AZ::Environment::Detach(); \
} \
\
AZ_DLL_EXPORT void ModuleRegisterDescriptors() \
{ \
BuilderRegisterDescriptors(); \
} \
\
AZ_DLL_EXPORT void ModuleAddComponents(AZ::Entity * entity) \
{ \
BuilderAddComponents(entity); \
} \
}
// confusion-reducing note: above end-brace is part of the macro, not a namespace
@@ -0,0 +1,204 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AssetBuilderSDK/SerializationDependencies.h>
namespace AssetBuilderSDK
{
bool UpdateDependenciesFromClassData(
const AZ::SerializeContext& serializeContext,
void* instancePointer,
const AZ::SerializeContext::ClassData* classData,
const AZ::SerializeContext::ClassElement* classElement,
UniqueDependencyList& productDependencySet,
ProductPathDependencySet& productPathDependencySet,
bool enumerateChildren)
{
if(classData == nullptr)
{
return false;
}
if (classData->m_typeId == AZ::GetAssetClassId())
{
auto* asset = reinterpret_cast<AZ::Data::Asset<AZ::Data::AssetData>*>(instancePointer);
if (asset->GetId().IsValid())
{
productDependencySet[asset->GetId()] = AZ::Data::ProductDependencyInfo::CreateFlags(asset->GetAutoLoadBehavior());
}
}
else if (classData->m_typeId == azrtti_typeid<AZ::Data::AssetId>())
{
auto* assetId = reinterpret_cast<AZ::Data::AssetId*>(instancePointer);
if (assetId->IsValid())
{
// For asset ID dependencies, set the behavior to "NoLoad" so that loading the parent asset doesn't trigger a load
// of the dependent asset.
productDependencySet[*assetId] = AZ::Data::ProductDependencyInfo::CreateFlags(AZ::Data::AssetLoadBehavior::NoLoad);
}
}
else if (classData->m_azRtti && classData->m_azRtti->IsTypeOf(azrtti_typeid<AzFramework::SimpleAssetReferenceBase>()))
{
auto* asset = reinterpret_cast<AzFramework::SimpleAssetReferenceBase*>(instancePointer);
if (!asset->GetAssetPath().empty())
{
AZStd::string filePath = asset->GetAssetPath();
AZStd::string fileExtension;
if (!AzFramework::StringFunc::Path::GetExtension(filePath.c_str(), fileExtension))
{
// GetFileFilter can return either
// 1) one file extension like "*.fileExtension"
// 2) one file extension like "fileExtension"
// 3) a semi colon separated list of file extensions like "*.fileExtension1; *.fileExtension2"
// Please note that if file extension is missing from the path and we get a list of semicolon separated file extensions
// we will extract the first file extension and use that.
fileExtension = asset->GetFileFilter();
AZStd::regex fileExtensionRegex("^(?:\\*\\.)?(\\w+);?");
AZStd::smatch match;
if (AZStd::regex_search(fileExtension, match, fileExtensionRegex))
{
fileExtension = match[1];
AzFramework::StringFunc::Path::ReplaceExtension(filePath, fileExtension.c_str());
}
}
productPathDependencySet.emplace(filePath, ProductPathDependencyType::ProductFile);
}
}
else if(enumerateChildren)
{
auto beginCallback = [&serializeContext, &productDependencySet, &productPathDependencySet](void* instancePointer, const AZ::SerializeContext::ClassData* classData, const AZ::SerializeContext::ClassElement* classElement)
{
// EnumerateInstance calls are already recursive, so no need to keep going, set enumerateChildren to false.
return UpdateDependenciesFromClassData(serializeContext, instancePointer, classData, classElement, productDependencySet, productPathDependencySet, false);
};
AZ::SerializeContext::EnumerateInstanceCallContext callContext(
beginCallback,
{},
&serializeContext,
AZ::SerializeContext::ENUM_ACCESS_FOR_READ,
nullptr
);
return serializeContext.EnumerateInstance(&callContext, instancePointer, classData->m_typeId, classData, classElement);
}
return true;
}
void FillDependencyVectorFromSet(
AZStd::vector<ProductDependency>& productDependencies,
UniqueDependencyList& productDependencySet)
{
productDependencies.reserve(productDependencySet.size());
for (const auto& thisEntry : productDependencySet)
{
constexpr int flags = 0;
productDependencies.emplace_back(thisEntry.first, thisEntry.second);
}
}
bool GatherProductDependenciesForFile(
AZ::SerializeContext& serializeContext,
const AZStd::string& filePath,
AZStd::vector<ProductDependency>& productDependencies,
ProductPathDependencySet& productPathDependencySet)
{
AZ::IO::FileIOStream fileStream;
if (!fileStream.Open(filePath.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary))
{
return false;
}
UniqueDependencyList productDependencySet;
// UpdateDependenciesFromClassData is also looking for assets. In some cases, the assets may not be ready to use
// in UpdateDependenciesFromClassData, and have an invalid asset ID. This asset filter will be called with valid, ready to use assets,
// but it's only called on assets and not other supported types, and it's only available when loading the file, and not on an in-memory stream.
AZ::ObjectStream::FilterDescriptor assetReadyFilterDescriptor([&productDependencySet](const AZ::Data::AssetFilterInfo& filterInfo)
{
if (filterInfo.m_assetId.IsValid())
{
productDependencySet[filterInfo.m_assetId] = AZ::Data::ProductDependencyInfo::CreateFlags(filterInfo.m_loadBehavior);
}
return false;
});
if (!AZ::ObjectStream::LoadBlocking(&fileStream, serializeContext, [&productDependencySet, &productPathDependencySet](void* instancePointer, const AZ::Uuid& classId, const AZ::SerializeContext* callbackSerializeContext)
{
auto classData = callbackSerializeContext->FindClassData(classId);
// LoadBlocking only enumerates the topmost level objects, so call UpdateDependenciesFromClassData with enumerateChildren set.
UpdateDependenciesFromClassData(*callbackSerializeContext, instancePointer, classData, nullptr, productDependencySet, productPathDependencySet, true);
return true;
}, assetReadyFilterDescriptor))
{
return false;
}
FillDependencyVectorFromSet(productDependencies, productDependencySet);
return true;
}
bool GatherProductDependencies(
AZ::SerializeContext& serializeContext,
void* obj,
AZ::TypeId typeId,
AZStd::vector<ProductDependency>& productDependencies,
ProductPathDependencySet& productPathDependencySet,
const DependencyHandler& handler)
{
if (obj == nullptr)
{
AZ_Error("AssetBuilderSDK", false, "Cannot gather product dependencies for null data.");
return false;
}
// start with a set to make it easy to avoid duplicate entries.
UniqueDependencyList productDependencySet;
auto beginCallback = [&serializeContext, &productDependencySet, &productPathDependencySet, handler](void* instancePointer, const AZ::SerializeContext::ClassData* classData, const AZ::SerializeContext::ClassElement* classElement)
{
// EnumerateObject already visits every element, so no need to enumerate farther, set enumerateChildren to false.
return handler(serializeContext, instancePointer, classData, classElement, productDependencySet, productPathDependencySet, false);
};
bool enumerateResult = serializeContext.EnumerateInstanceConst(obj, typeId, beginCallback, {}, AZ::SerializeContext::ENUM_ACCESS_FOR_READ, nullptr, nullptr);
FillDependencyVectorFromSet(productDependencies, productDependencySet);
return enumerateResult;
}
bool OutputObject(void* obj, AZ::TypeId typeId, AZStd::string_view outputPath, AZ::Data::AssetType assetType, AZ::u32 subId, JobProduct& jobProduct, AZ::SerializeContext* serializeContext, const DependencyHandler& handler)
{
if (!serializeContext)
{
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
}
if(!serializeContext)
{
AZ_Error("AssetBuilderSDK", false, "Failed to retrieve serialization context.");
return false;
}
jobProduct = JobProduct(outputPath, assetType, subId);
if (GatherProductDependencies(*serializeContext, obj, typeId, jobProduct.m_dependencies, jobProduct.m_pathDependencies, handler))
{
jobProduct.m_dependenciesHandled = true;
return true;
}
jobProduct = {};
return false;
}
}
@@ -0,0 +1,107 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzFramework/Asset/SimpleAsset.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzCore/std/string/regex.h>
#include <AzCore/Component/ComponentApplicationBus.h>
namespace AZ
{
class SerializeContext;
}
namespace AssetBuilderSDK
{
using UniqueDependencyList = AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::ProductDependencyInfo::ProductDependencyFlags>;
bool UpdateDependenciesFromClassData(
const AZ::SerializeContext& serializeContext,
void* instancePointer,
const AZ::SerializeContext::ClassData* classData,
const AZ::SerializeContext::ClassElement* classElement,
UniqueDependencyList& productDependencySet,
ProductPathDependencySet& productPathDependencySet,
bool enumerateChildren);
void FillDependencyVectorFromSet(AZStd::vector<AssetBuilderSDK::ProductDependency>& productDependencies, UniqueDependencyList& productDependencySet);
bool GatherProductDependenciesForFile(
AZ::SerializeContext& serializeContext,
const AZStd::string& filePath,
AZStd::vector<AssetBuilderSDK::ProductDependency>& productDependencies,
ProductPathDependencySet& productPathDependencySet);
using DependencyHandler = AZStd::function<bool(
const AZ::SerializeContext& /*serializeContext*/,
void* /*instancePointer*/,
const AZ::SerializeContext::ClassData* /*classData*/,
const AZ::SerializeContext::ClassElement* /*classElement*/,
UniqueDependencyList& /*productDependencySet*/,
ProductPathDependencySet& /*productPathDependencySet*/,
bool enumerateChildren)>;
bool GatherProductDependencies(
AZ::SerializeContext& serializeContext,
void* obj,
AZ::TypeId typeId,
AZStd::vector<ProductDependency>& productDependencies,
ProductPathDependencySet& productPathDependencySet,
const DependencyHandler& handler = &UpdateDependenciesFromClassData);
template<class T>
bool GatherProductDependencies(
AZ::SerializeContext& serializeContext,
AZ::Data::Asset<T>* obj,
AZ::TypeId typeId,
AZStd::vector<ProductDependency>& productDependencies,
ProductPathDependencySet& productPathDependencySet,
const DependencyHandler& handler = &UpdateDependenciesFromClassData)
{
AZ_Error("AssetBuilderSDK", false, "Can't output dependencies for AZ::Data::Asset<T>* - Use T* or another underlying type");
return false;
}
template<class T>
bool GatherProductDependencies(
AZ::SerializeContext& serializeContext,
T* obj,
AZStd::vector<ProductDependency>& productDependencies,
ProductPathDependencySet& productPathDependencySet,
const DependencyHandler& handler = &UpdateDependenciesFromClassData)
{
return GatherProductDependencies(serializeContext, obj, azrtti_typeid<T>(), productDependencies, productPathDependencySet, handler);
}
bool OutputObject(void* obj, AZ::TypeId typeId, AZStd::string_view outputPath, AZ::Data::AssetType assetType, AZ::u32 subId, JobProduct& jobProduct, AZ::SerializeContext* serializeContext = nullptr,
const DependencyHandler& handler = &UpdateDependenciesFromClassData);
template<class T>
bool OutputObject(T* obj, AZStd::string_view outputPath, AZ::Data::AssetType assetType, AZ::u32 subId, JobProduct& jobProduct, AZ::SerializeContext* serializeContext = nullptr,
const DependencyHandler& handler = &UpdateDependenciesFromClassData)
{
return OutputObject(obj, azrtti_typeid<T>(), outputPath, assetType, subId, jobProduct, serializeContext, handler);
}
template<class T>
bool OutputObject(AZ::Data::Asset<T>* obj, AZStd::string_view outputPath, AZ::Data::AssetType assetType, AZ::u32 subId, JobProduct& jobProduct, AZ::SerializeContext* serializeContext = nullptr,
const DependencyHandler& handler = &UpdateDependenciesFromClassData)
{
AZ_Error("AssetBuilderSDK", false, "Can't output dependencies for AZ::Data::Asset<T>* - Use T* or another underlying type");
return false;
}
}
@@ -0,0 +1,43 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_get_pal_tool_dirs(pal_tool_dirs ${CMAKE_CURRENT_LIST_DIR}/AssetBuilderSDK/Platform)
set(pal_files "")
foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED})
string(TOLOWER ${enabled_platform} enabled_platform_lowercase)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/AssetBuilderSDK/Platform/${enabled_platform})
list(APPEND pal_files ${pal_dir}/assetbuildersdk_${enabled_platform_lowercase}_files.cmake)
endforeach()
ly_add_target(
NAME AssetBuilderSDK STATIC
NAMESPACE AZ
FILES_CMAKE
assetbuilder_files.cmake
${pal_files}
INCLUDE_DIRECTORIES
PUBLIC
.
PRIVATE
${pal_tool_dirs}
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
PUBLIC
AZ::AzFramework
AZ::AzToolsFramework
)
ly_add_source_properties(
SOURCES AssetBuilderSDK/AssetBuilderSDK.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES ${LY_PAL_TOOLS_DEFINES}
)
@@ -0,0 +1,18 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
AssetBuilderSDK/AssetBuilderSDK.h
AssetBuilderSDK/AssetBuilderSDK.cpp
AssetBuilderSDK/AssetBuilderBusses.h
AssetBuilderSDK/SerializationDependencies.h
AssetBuilderSDK/SerializationDependencies.cpp
)
+205
View File
@@ -0,0 +1,205 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
# Builders need to be defined first because we collect the builders and pass them
# to AssetBuilder and AssetProcessor so it loads them.
add_subdirectory(AssetBuilderSDK)
add_subdirectory(AssetBuilder)
include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
ly_add_target(
NAME AssetProcessor.Static STATIC
NAMESPACE AZ
AUTOMOC
AUTORCC
FILES_CMAKE
assetprocessor_static_files.cmake
Platform/${PAL_PLATFORM_NAME}/assetprocessor_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
Platform/${PAL_PLATFORM_NAME}
PRIVATE
native
BUILD_DEPENDENCIES
PUBLIC
3rdParty::Qt::Core
3rdParty::Qt::Gui
3rdParty::Qt::Network
3rdParty::RapidJSON
3rdParty::SQLite
3rdParty::XXHash
AZ::AzCore
AZ::AzFramework
AZ::AzQtComponents
AZ::AzToolsFramework
AZ::AssetBuilderSDK
${additional_dependencies}
RUNTIME_DEPENDENCIES
AZ::AssetBuilder
Legacy::RC
)
# Aggregates all combined AssetBuilders into a single LY_ASSET_BUILDERS #define
get_property(asset_builders GLOBAL PROPERTY LY_ASSET_BUILDERS)
string (REPLACE ";" "," asset_builders "${asset_builders}")
ly_add_source_properties(
SOURCES native/utilities/ApplicationManager.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES LY_ASSET_BUILDERS="${asset_builders}"
)
ly_add_target(
NAME AssetProcessor ${PAL_TRAIT_BUILD_ASSETPROCESSOR_APPLICATION_TYPE}
NAMESPACE AZ
AUTOMOC
AUTOUIC
AUTORCC
FILES_CMAKE
assetprocessor_gui_files.cmake
Platform/${PAL_PLATFORM_NAME}/assetprocessor_gui_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
Platform/${PAL_PLATFORM_NAME}/assetprocessor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
PRIVATE
native
BUILD_DEPENDENCIES
PRIVATE
AZ::AssetProcessor.Static
)
ly_add_source_properties(
SOURCES native/utilities/BatchApplicationManager.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES LY_METRICS_BUILD_TIME=${LY_METRICS_BUILD_TIME}
)
# Adds the AssetProcessor target as a C preprocessor define so that it can be used as a Settings Registry
# specialization in order to look up the generated .setreg which contains the dependencies
# specified for the target.
if(TARGET AssetProcessor)
set_source_files_properties(
native/AssetProcessorBuildTarget.cpp
PROPERTIES
COMPILE_DEFINITIONS
LY_CMAKE_TARGET="AssetProcessor"
)
else()
message(FATAL_ERROR "Cannot set LY_CMAKE_TARGET define to AssetProcessor as the target doesn't exist anymore."
" Perhaps it has been renamed")
endif()
ly_add_target(
NAME AssetProcessorBatch.Static STATIC
NAMESPACE AZ
AUTOMOC
FILES_CMAKE
assetprocessor_static_batch_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
PRIVATE
native
BUILD_DEPENDENCIES
PUBLIC
AZ::AssetProcessor.Static
)
ly_add_target(
NAME AssetProcessorBatch EXECUTABLE
NAMESPACE AZ
AUTOMOC
FILES_CMAKE
assetprocessor_batch_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
native
BUILD_DEPENDENCIES
PRIVATE
AZ::AssetProcessorBatch.Static
)
# Adds the AssetProcessorBatch target as a C preprocessor define so that it can be used as a Settings Registry
# specialization in order to look up the generated .setreg which contains the dependencies
# specified for the target.
if(TARGET AssetProcessorBatch)
set_source_files_properties(
native/AssetProcessorBatchBuildTarget.cpp
PROPERTIES
COMPILE_DEFINITIONS
LY_CMAKE_TARGET="AssetProcessorBatch"
)
else()
message(FATAL_ERROR "Cannot set LY_CMAKE_TARGET define to AssetProcessorBatch as the target doesn't exist anymore."
" Perhaps it has been renamed")
endif()
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AssetProcessor.Tests EXECUTABLE
NAMESPACE AZ
AUTOMOC
AUTORCC
FILES_CMAKE
assetprocessor_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
native
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
AZ::AssetProcessorBatch.Static
AZ::AzToolsFrameworkTestCommon
)
ly_add_source_properties(
SOURCES native/tests/assetBuilderSDK/assetBuilderSDKTest.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES ${LY_PAL_TOOLS_DEFINES}
)
ly_add_source_properties(
SOURCES native/unittests/AssetProcessorManagerUnitTests.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES LY_CMAKE_BINARY_DIR="${CMAKE_BINARY_DIR}"
)
# Have the AssetProcessorTest use the LY_CMAKE_TARGET define of AssetProcessorBatch for the purpose
# of looking up the generated cmake build dependencies settings registry .setreg file
# It is tied to the UnitTestRunner.cpp file
if(TARGET AssetProcessorBatch)
set_source_files_properties(
native/unittests/UnitTestRunner.cpp
PROPERTIES
COMPILE_DEFINITIONS
LY_CMAKE_TARGET="AssetProcessorBatch"
)
else()
message(FATAL_ERROR "Cannot set LY_CMAKE_TARGET define to AssetProcessorBatch as the target doesn't exist anymore."
" Perhaps it has been renamed")
endif()
ly_add_googletest(
NAME AZ::AssetProcessor.Tests
TEST_COMMAND $<TARGET_FILE:AZ::AssetProcessor.Tests> --unittest
)
endif()
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#define ASSETPROCESSOR_TRAIT_LEGACY_RC_RELATIVE_PATH "/rc"
#define ASSETPROCESSOR_TRAIT_CASE_SENSITIVE_FILESYSTEM true
@@ -0,0 +1,14 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AssetProcessor_Traits_Linux.h>
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set (PAL_TRAIT_BUILD_ASSETPROCESSOR_APPLICATION_TYPE APPLICATION)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
)

Some files were not shown because too many files have changed in this diff Show More