You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.h

167 lines
7.0 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#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_projectPath;
AZStd::string m_gameCache;
};