{LYN-4514} Re-factored Blast gem's python asset builder (#2143)
* {LYN-4514} Re-factored Blast gem's python asset builder
* Re-factored Blast gem's python asset builder so that the .blast file creates an asset info scene manifest
* Added a python script to act as a SceneAPI script + Python Asset Builder (blast_asset_builder.py)
* renaming types from "Slice" to "Chunk"
Tests: Re-enabled Gems/Blast/Code/Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* renaming from Slice to Chunks
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* updated the Copyright
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* Removing StdAfx.h includes
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* null check added m_blastChunksAsset.Get()
removing 'slice' like EditorBlastSliceAssetHandlerTestFixture
delete old asset builder blast file
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* adding source deps for FBX -> BLAST file
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* removing slice name
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
* Adding error message and updates from PR
Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
void BlastChunksAsset::SetModelAssetIds(const AZStd::vector<AZ::Data::AssetId>& modelAssetIds)
|
||||
{
|
||||
m_modelAssetIds = modelAssetIds;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::AssetId>& BlastChunksAsset::GetModelAssetIds() const
|
||||
{
|
||||
return m_modelAssetIds;
|
||||
}
|
||||
|
||||
void BlastChunksAsset::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<BlastChunksAsset, AZ::Data::AssetData>()
|
||||
->Version(1)
|
||||
->Field("modelAssetIds", &BlastChunksAsset::m_modelAssetIds);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//! The product asset file from a .blast_chunks file product asset file
|
||||
class BlastChunksAsset final
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BlastChunksAsset, "{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}", AZ::Data::AssetData);
|
||||
AZ_CLASS_ALLOCATOR(BlastChunksAsset, AZ::SystemAllocator, 0);
|
||||
|
||||
BlastChunksAsset() = default;
|
||||
~BlastChunksAsset() override = default;
|
||||
|
||||
void SetModelAssetIds(const AZStd::vector<AZ::Data::AssetId>& modelAssetIds);
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetModelAssetIds() const;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
AZStd::vector<AZ::Data::AssetId> m_modelAssetIds;
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
void BlastSliceAsset::SetMeshIdList(const AZStd::vector<AZ::Data::AssetId>& meshAssetIdList)
|
||||
{
|
||||
m_meshAssetIdList = meshAssetIdList;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::AssetId>& BlastSliceAsset::GetMeshIdList() const
|
||||
{
|
||||
return m_meshAssetIdList;
|
||||
}
|
||||
|
||||
void BlastSliceAsset::SetMaterialId(const AZ::Data::AssetId& materialAssetId)
|
||||
{
|
||||
m_materialAssetId = materialAssetId;
|
||||
}
|
||||
|
||||
const AZ::Data::AssetId& BlastSliceAsset::GetMaterialId() const
|
||||
{
|
||||
return m_materialAssetId;
|
||||
}
|
||||
|
||||
void BlastSliceAsset::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<BlastSliceAsset, AZ::Data::AssetData>()
|
||||
->Version(1)
|
||||
->Field("meshAssetIdList", &BlastSliceAsset::m_meshAssetIdList)
|
||||
->Field("materialAssetId", &BlastSliceAsset::m_materialAssetId);
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behavior = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behavior->Class<BlastSliceAsset>("BlastSliceAsset")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "blast")
|
||||
->Method("SetMeshIdList", &BlastSliceAsset::SetMeshIdList)
|
||||
->Method("GetMeshIdList", &BlastSliceAsset::GetMeshIdList)
|
||||
->Method("SetMaterialId", &BlastSliceAsset::SetMaterialId)
|
||||
->Method("GetMaterialId", &BlastSliceAsset::GetMaterialId)
|
||||
->Method(
|
||||
"GetAssetTypeId",
|
||||
[](BlastSliceAsset*)
|
||||
{
|
||||
return azrtti_typeid<BlastSliceAsset>();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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 <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//! The product asset file from a .blast_slice file product asset file
|
||||
class BlastSliceAsset final : public AZ::Data::AssetData
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BlastSliceAsset, "{D04AAF07-EB12-4E50-8964-114A9B9C1FD1}", AZ::Data::AssetData);
|
||||
AZ_CLASS_ALLOCATOR(BlastSliceAsset, AZ::SystemAllocator, 0);
|
||||
|
||||
BlastSliceAsset() = default;
|
||||
~BlastSliceAsset() override = default;
|
||||
|
||||
void SetMeshIdList(const AZStd::vector<AZ::Data::AssetId>& meshAssetIdList);
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetMeshIdList() const;
|
||||
|
||||
void SetMaterialId(const AZ::Data::AssetId& materialAssetId);
|
||||
const AZ::Data::AssetId& GetMaterialId() const;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
AZStd::vector<AZ::Data::AssetId> m_meshAssetIdList;
|
||||
AZ::Data::AssetId m_materialAssetId;
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -16,7 +16,6 @@
|
||||
#ifdef BLAST_EDITOR
|
||||
#include <Editor/EditorBlastFamilyComponent.h>
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
#include <Editor/EditorSystemComponent.h>
|
||||
#endif
|
||||
|
||||
@@ -40,8 +39,7 @@ namespace Blast
|
||||
#ifdef BLAST_EDITOR
|
||||
EditorSystemComponent::CreateDescriptor(),
|
||||
EditorBlastFamilyComponent::CreateDescriptor(),
|
||||
EditorBlastMeshDataComponent::CreateDescriptor(),
|
||||
BlastSliceAssetStorageComponent::CreateDescriptor(),
|
||||
EditorBlastMeshDataComponent::CreateDescriptor()
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Editor/EditorBlastChunksAssetHandler.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//
|
||||
// EditorBlastChunksAssetHandler
|
||||
//
|
||||
|
||||
EditorBlastChunksAssetHandler::~EditorBlastChunksAssetHandler()
|
||||
{
|
||||
Unregister();
|
||||
}
|
||||
|
||||
AZ::Data::AssetPtr EditorBlastChunksAssetHandler::CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
|
||||
{
|
||||
if (type != GetAssetType())
|
||||
{
|
||||
AZ_Error("Blast", type == GetAssetType(), "Invalid asset type! We only handle 'BlastChunksAsset'");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!CanHandleAsset(id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aznew BlastChunksAsset;
|
||||
}
|
||||
|
||||
AZ::Data::AssetHandler::LoadResult EditorBlastChunksAssetHandler::LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB)
|
||||
{
|
||||
BlastChunksAsset* blastChunksAsset = asset.GetAs<BlastChunksAsset>();
|
||||
AZ_Error("blast", blastChunksAsset,
|
||||
"This should be a BlastChunksAsset type, as this is the only type we process!");
|
||||
if (!blastChunksAsset)
|
||||
{
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
// get all products from the source scene asset
|
||||
bool found = false;
|
||||
AZStd::vector<AZ::Data::AssetInfo> productsAssetInfo;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
found,
|
||||
&AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID,
|
||||
asset.Get()->GetId().m_guid,
|
||||
productsAssetInfo);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
AZ_Error("blast",
|
||||
found,
|
||||
"Could not find asset models produced by source asset ID %s, verify the output product model assets.",
|
||||
asset.Get()->GetId().m_guid.ToString<AZStd::string>().c_str());
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
// find all model assets
|
||||
AZStd::vector<AZ::Data::AssetId> modelAssetIdList;
|
||||
for (const AZ::Data::AssetInfo& assetInfo : productsAssetInfo)
|
||||
{
|
||||
if (azrtti_typeid<AZ::RPI::ModelAsset>() == assetInfo.m_assetType)
|
||||
{
|
||||
modelAssetIdList.push_back(assetInfo.m_assetId);
|
||||
}
|
||||
}
|
||||
blastChunksAsset->SetModelAssetIds(modelAssetIdList);
|
||||
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
|
||||
{
|
||||
assetTypes.push_back(azrtti_typeid<BlastChunksAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::Register()
|
||||
{
|
||||
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid<BlastChunksAsset>());
|
||||
AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid<BlastChunksAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::Unregister()
|
||||
{
|
||||
AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid<BlastChunksAsset>());
|
||||
if (AZ::Data::AssetManager::IsReady())
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Data::AssetType EditorBlastChunksAssetHandler::GetAssetType() const
|
||||
{
|
||||
return azrtti_typeid<BlastChunksAsset>();
|
||||
}
|
||||
|
||||
const char* EditorBlastChunksAssetHandler::GetAssetTypeDisplayName() const
|
||||
{
|
||||
return "Blast Chunks Asset";
|
||||
}
|
||||
|
||||
const char* EditorBlastChunksAssetHandler::GetGroup() const
|
||||
{
|
||||
return "Blast";
|
||||
}
|
||||
|
||||
const char* EditorBlastChunksAssetHandler::GetBrowserIcon() const
|
||||
{
|
||||
return "Icons/Components/Box.png";
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
|
||||
{
|
||||
extensions.push_back("blast_chunks");
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 <Asset/BlastChunksAsset.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Asset/AssetTypeInfoBus.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
class EditorBlastChunksAssetHandler final
|
||||
: public AZ::Data::AssetHandler
|
||||
, public AZ::AssetTypeInfoBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EditorBlastChunksAssetHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
~EditorBlastChunksAssetHandler() override;
|
||||
|
||||
// AZ::Data::AssetHandler
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
|
||||
LoadResult LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
|
||||
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
|
||||
|
||||
// AZ::AssetTypeInfoBus::Handler
|
||||
AZ::Data::AssetType GetAssetType() const override;
|
||||
const char* GetAssetTypeDisplayName() const override;
|
||||
const char* GetGroup() const override;
|
||||
const char* GetBrowserIcon() const override;
|
||||
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
|
||||
|
||||
void Register();
|
||||
void Unregister();
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -45,10 +45,10 @@ namespace Blast
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<EditorBlastMeshDataComponent, AzToolsFramework::Components::EditorComponentBase>()
|
||||
->Version(4)
|
||||
->Version(5)
|
||||
->Field("Show Mesh Assets", &EditorBlastMeshDataComponent::m_showMeshAssets)
|
||||
->Field("Mesh Assets", &EditorBlastMeshDataComponent::m_meshAssets)
|
||||
->Field("Blast Slice", &EditorBlastMeshDataComponent::m_blastSliceAsset);
|
||||
->Field("Blast Chunks", &EditorBlastMeshDataComponent::m_blastChunksAsset);
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
@@ -77,9 +77,9 @@ namespace Blast
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnMeshAssetsChanged)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &EditorBlastMeshDataComponent::m_blastSliceAsset, "Blast Slice",
|
||||
"Slice override to fill out meshes and material")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnSliceAssetChanged);
|
||||
AZ::Edit::UIHandlers::Default, &EditorBlastMeshDataComponent::m_blastChunksAsset, "Blast Chunks",
|
||||
"Manifest override to fill out meshes and material")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnBlastChunksAssetChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,23 +107,27 @@ namespace Blast
|
||||
UnregisterModel();
|
||||
}
|
||||
|
||||
void EditorBlastMeshDataComponent::OnSliceAssetChanged()
|
||||
void EditorBlastMeshDataComponent::OnBlastChunksAssetChanged()
|
||||
{
|
||||
if (!m_blastSliceAsset.GetId().IsValid())
|
||||
if (!m_blastChunksAsset.GetId().IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace AZ::Data;
|
||||
const AssetId blastAssetId = m_blastChunksAsset.GetId();
|
||||
m_blastChunksAsset = AssetManager::Instance().GetAsset<BlastChunksAsset>(blastAssetId, AssetLoadBehavior::QueueLoad);
|
||||
m_blastChunksAsset.BlockUntilLoadComplete();
|
||||
|
||||
const AssetId blastAssetId = m_blastSliceAsset.GetId();
|
||||
m_blastSliceAsset =
|
||||
AssetManager::Instance().GetAsset<BlastSliceAsset>(blastAssetId, AssetLoadBehavior::QueueLoad);
|
||||
m_blastSliceAsset.BlockUntilLoadComplete();
|
||||
if (!m_blastChunksAsset.Get() || m_blastChunksAsset.Get()->GetModelAssetIds().empty())
|
||||
{
|
||||
AZ_Warning("blast", false, "Blast Chunk Asset does not contain any models.")
|
||||
return;
|
||||
}
|
||||
|
||||
// load up the new mesh list
|
||||
m_meshAssets.clear();
|
||||
for (const auto& meshId : m_blastSliceAsset.Get()->GetMeshIdList())
|
||||
for (const auto& meshId : m_blastChunksAsset.Get()->GetModelAssetIds())
|
||||
{
|
||||
auto meshAsset = AssetManager::Instance().GetAsset<AZ::RPI::ModelAsset>(meshId, AssetLoadBehavior::QueueLoad);
|
||||
if (meshAsset)
|
||||
@@ -135,8 +139,8 @@ namespace Blast
|
||||
UnregisterModel();
|
||||
RegisterModel();
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree);
|
||||
using namespace AzToolsFramework;
|
||||
ToolsApplicationEvents::Bus::Broadcast(&ToolsApplicationEvents::InvalidatePropertyDisplay, Refresh_EntireTree);
|
||||
}
|
||||
|
||||
void EditorBlastMeshDataComponent::OnMeshAssetsChanged()
|
||||
@@ -205,9 +209,9 @@ namespace Blast
|
||||
gameEntity->CreateComponent<BlastMeshDataComponent>(m_meshAssets);
|
||||
}
|
||||
|
||||
const AZ::Data::Asset<BlastSliceAsset>& EditorBlastMeshDataComponent::GetBlastSliceAsset() const
|
||||
const AZ::Data::Asset<BlastChunksAsset>& EditorBlastMeshDataComponent::GetBlastChunksAsset() const
|
||||
{
|
||||
return m_blastSliceAsset;
|
||||
return m_blastChunksAsset;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::RPI::ModelAsset>>& EditorBlastMeshDataComponent::GetMeshAssets() const
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
#include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/Model/Model.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
@@ -43,14 +43,14 @@ namespace Blast
|
||||
// EditorComponentBase
|
||||
void BuildGameEntity(AZ::Entity* gameEntity) override;
|
||||
|
||||
const AZ::Data::Asset<BlastSliceAsset>& GetBlastSliceAsset() const;
|
||||
const AZ::Data::Asset<BlastChunksAsset>& GetBlastChunksAsset() const;
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::RPI::ModelAsset>>& GetMeshAssets() const;
|
||||
|
||||
void OnMaterialsUpdated(const AZ::Render::MaterialAssignmentMap& materials) override;
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
|
||||
private:
|
||||
void OnSliceAssetChanged();
|
||||
void OnBlastChunksAssetChanged();
|
||||
void OnMeshAssetsChanged();
|
||||
AZ::Crc32 GetMeshAssetsVisibility() const;
|
||||
void OnMeshAssetsVisibilityChanged();
|
||||
@@ -62,7 +62,7 @@ namespace Blast
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Reflected data
|
||||
bool m_showMeshAssets = false;
|
||||
AZ::Data::Asset<BlastSliceAsset> m_blastSliceAsset;
|
||||
AZ::Data::Asset<BlastChunksAsset> m_blastChunksAsset;
|
||||
AZStd::vector<AZ::Data::Asset<AZ::RPI::ModelAsset>> m_meshAssets;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/Slice/SliceComponent.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <SceneAPI/SceneCore/Containers/RuleContainer.h>
|
||||
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
|
||||
#include <SceneAPI/SceneData/Groups/MeshGroup.h>
|
||||
#include <SceneAPI/SceneData/ManifestBase/SceneNodeSelectionList.h>
|
||||
#include <SceneAPI/SceneData/Rules/MaterialRule.h>
|
||||
|
||||
#include <GFxFramework/MaterialIO/Material.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
// BlastSliceAssetStorageComponent
|
||||
|
||||
void BlastSliceAssetStorageComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
using namespace AZ::Edit;
|
||||
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<BlastSliceAssetStorageComponent, AzToolsFramework::Components::EditorComponentBase>()
|
||||
->Version(2)
|
||||
->Field("Mesh Data", &BlastSliceAssetStorageComponent::m_meshAssetIdList)
|
||||
->Field("Mesh Path List", &BlastSliceAssetStorageComponent::m_meshAssetPathList);
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
ec->Class<BlastSliceAssetStorageComponent>(
|
||||
"Blast Slice Storage Component", "Used process blast slice data")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Physics")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Box.png")
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Box.png")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::AddableByUser, false)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &BlastSliceAssetStorageComponent::m_meshAssetIdList, "Mesh Data",
|
||||
"Slice data to fill out the mesh list")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &BlastSliceAssetStorageComponent::m_meshAssetPathList,
|
||||
"Mesh Paths", "The mesh path list");
|
||||
}
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behavior = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behavior->Class<BlastSliceAssetStorageComponent>("BlastSliceAssetStorageComponent")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "blast")
|
||||
->Method("GenerateAssetInfo", &BlastSliceAssetStorageComponent::GenerateAssetInfo)
|
||||
->Method("WriteMaterialFile", &BlastSliceAssetStorageComponent::WriteMaterialFile);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlastSliceAssetStorageComponent::GenerateAssetInfo(
|
||||
const AZStd::vector<AZStd::string>& chunkNames, AZStd::string_view blastFilename,
|
||||
AZStd::string_view assetinfoFilename)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (serializeContext == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
using namespace AZ::SceneAPI::Containers;
|
||||
using namespace AZ::SceneAPI::SceneData;
|
||||
|
||||
AZStd::string filename;
|
||||
AZ::StringFunc::Path::Split(blastFilename.data(), nullptr, nullptr, &filename, nullptr);
|
||||
|
||||
AZStd::any sceneManifestPointer(serializeContext->CreateAny(azrtti_typeid<SceneManifest>()));
|
||||
SceneManifest* sceneManifest = AZStd::any_cast<SceneManifest>(&sceneManifestPointer);
|
||||
|
||||
AZStd::vector<AZStd::any> meshGroupData;
|
||||
meshGroupData.reserve(chunkNames.size());
|
||||
|
||||
AZStd::vector<AZStd::any> materialRuleData;
|
||||
materialRuleData.reserve(chunkNames.size());
|
||||
|
||||
for (const AZStd::string& chunkName : chunkNames)
|
||||
{
|
||||
meshGroupData.emplace_back(serializeContext->CreateAny(azrtti_typeid<MeshGroup>()));
|
||||
AZStd::any& meshGroupPointer = meshGroupData.back();
|
||||
MeshGroup* meshGroup = AZStd::any_cast<MeshGroup>(&meshGroupPointer);
|
||||
|
||||
// make selection list
|
||||
meshGroup->GetSceneNodeSelectionList().RemoveSelectedNode("RootNode");
|
||||
for (const AZStd::string& node : chunkNames)
|
||||
{
|
||||
meshGroup->GetSceneNodeSelectionList().RemoveSelectedNode(
|
||||
AZStd::string::format("RootNode.%s", node.c_str()));
|
||||
}
|
||||
meshGroup->GetSceneNodeSelectionList().AddSelectedNode(
|
||||
AZStd::string::format("RootNode.%s", chunkName.c_str()));
|
||||
|
||||
// create a default material for the mesh group
|
||||
materialRuleData.emplace_back(serializeContext->CreateAny(azrtti_typeid<MaterialRule>()));
|
||||
AZStd::any& materialRulePointer = materialRuleData.back();
|
||||
MaterialRule* materialRule = AZStd::any_cast<MaterialRule>(&materialRulePointer);
|
||||
|
||||
// override the deleter since the AZStd::any will clean up later on
|
||||
AZStd::shared_ptr<MaterialRule> materialRuleEntry = AZStd::shared_ptr<MaterialRule>(
|
||||
materialRule,
|
||||
[](auto)
|
||||
{
|
||||
});
|
||||
meshGroup->GetRuleContainer().AddRule(materialRuleEntry);
|
||||
|
||||
// construct the asset name for the chunk's mesh group
|
||||
AZStd::string meshGroupName(filename);
|
||||
meshGroupName.append("-");
|
||||
meshGroupName.append(chunkName);
|
||||
// TODO: Uncomment lines below as part of SPEC-3542
|
||||
// meshGroup->OverrideId(AZ::Uuid::CreateName(meshGroupName.c_str()));
|
||||
// meshGroup->SetName(AZStd::move(meshGroupName));
|
||||
|
||||
// override the deleter since the AZStd::any will clean up later on
|
||||
AZStd::shared_ptr<MeshGroup> meshGroupEntry = AZStd::shared_ptr<MeshGroup>(
|
||||
meshGroup,
|
||||
[](auto)
|
||||
{
|
||||
});
|
||||
sceneManifest->AddEntry(AZStd::move(meshGroupEntry));
|
||||
}
|
||||
|
||||
return sceneManifest->SaveToFile(assetinfoFilename.data());
|
||||
}
|
||||
|
||||
bool BlastSliceAssetStorageComponent::WriteMaterialFile(
|
||||
AZStd::string_view materialGroupName, const AZStd::vector<AZStd::string>& materialNames,
|
||||
AZStd::string_view materialFilename)
|
||||
{
|
||||
AZ::GFxFramework::MaterialGroup group;
|
||||
for (const auto& texture : materialNames)
|
||||
{
|
||||
auto mat = AZStd::make_shared<AZ::GFxFramework::Material>();
|
||||
mat->SetName(texture);
|
||||
mat->SetTexture(AZ::GFxFramework::TextureMapType::Diffuse, "EngineAssets/Textures/white.dds");
|
||||
group.AddMaterial(mat);
|
||||
}
|
||||
group.SetMtlName(materialGroupName);
|
||||
return group.WriteMtlFile(materialFilename.data());
|
||||
}
|
||||
|
||||
//
|
||||
// EditorBlastSliceAssetHandler
|
||||
//
|
||||
|
||||
EditorBlastSliceAssetHandler::~EditorBlastSliceAssetHandler()
|
||||
{
|
||||
Unregister();
|
||||
}
|
||||
|
||||
AZ::Data::AssetPtr EditorBlastSliceAssetHandler::CreateAsset(
|
||||
const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
|
||||
{
|
||||
if (type != GetAssetType())
|
||||
{
|
||||
AZ_Error("Blast", type == GetAssetType(), "Invalid asset type! We only handle 'BlastAsset'");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!CanHandleAsset(id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aznew BlastSliceAsset;
|
||||
}
|
||||
|
||||
AZ::Data::AssetHandler::LoadResult EditorBlastSliceAssetHandler::LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilterCB)
|
||||
{
|
||||
BlastSliceAsset* blastSliceAssetData = asset.GetAs<BlastSliceAsset>();
|
||||
AZ_Error(
|
||||
"blast", blastSliceAssetData,
|
||||
"This should be a BlastSliceAsset type, as this is the only type we process!");
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (blastSliceAssetData && serializeContext)
|
||||
{
|
||||
AZ::ObjectStream::FilterDescriptor filter(assetLoadFilterCB);
|
||||
AZStd::unique_ptr<AZ::Entity> baseEntity(
|
||||
AZ::Utils::LoadObjectFromStream<AZ::Entity>(*stream, serializeContext, filter));
|
||||
AZ_Error("Blast", baseEntity, "Could not load slice root entity {asset id}");
|
||||
if (!baseEntity)
|
||||
{
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
auto&& sliceComponent = baseEntity->FindComponent<AZ::SliceComponent>();
|
||||
AZ_Error("Blast", sliceComponent, "blast_slice entity missing SliceComponent!");
|
||||
if (sliceComponent == nullptr)
|
||||
{
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Entity*> enityList;
|
||||
sliceComponent->GetEntities(enityList);
|
||||
for (auto&& entity : enityList)
|
||||
{
|
||||
// the base element type to store Blast mesh data is the BlastSliceAssetStorageComponent
|
||||
auto&& blastSliceAssetStorage = entity->FindComponent<BlastSliceAssetStorageComponent>();
|
||||
if (blastSliceAssetStorage)
|
||||
{
|
||||
if (blastSliceAssetStorage->GetMeshData().empty() == false)
|
||||
{
|
||||
blastSliceAssetData->SetMeshIdList(blastSliceAssetStorage->GetMeshData());
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
else if (blastSliceAssetStorage->GetMeshPathList().empty() == false)
|
||||
{
|
||||
AZStd::vector<AZ::Data::AssetId> meshAssetIdList;
|
||||
meshAssetIdList.reserve(blastSliceAssetStorage->GetMeshPathList().size());
|
||||
|
||||
for (auto&& assetPath : blastSliceAssetStorage->GetMeshPathList())
|
||||
{
|
||||
AZ::Data::AssetId meshAssetId;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
meshAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
assetPath.c_str(), AZ::Data::s_invalidAssetType, false);
|
||||
|
||||
if (meshAssetId.IsValid())
|
||||
{
|
||||
meshAssetIdList.emplace_back(meshAssetId);
|
||||
}
|
||||
}
|
||||
blastSliceAssetData->SetMeshIdList(meshAssetIdList);
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
}
|
||||
|
||||
// back up logic to load blast data for the EditorBlastMeshDataComponent
|
||||
auto&& meshDataComponent = entity->FindComponent<EditorBlastMeshDataComponent>();
|
||||
if (meshDataComponent)
|
||||
{
|
||||
auto&& innerBlastSliceAsset = meshDataComponent->GetBlastSliceAsset();
|
||||
if (innerBlastSliceAsset.IsReady())
|
||||
{
|
||||
blastSliceAssetData->SetMeshIdList(innerBlastSliceAsset.Get()->GetMeshIdList());
|
||||
blastSliceAssetData->SetMaterialId(innerBlastSliceAsset.Get()->GetMaterialId());
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto&& meshDataList = meshDataComponent->GetMeshAssets();
|
||||
AZStd::vector<AZ::Data::AssetId> meshAssetIdList;
|
||||
meshAssetIdList.reserve(meshDataList.size());
|
||||
for (auto&& meshData : meshDataList)
|
||||
{
|
||||
AZ::RPI::ModelAsset* meshAsset = meshData.Get();
|
||||
if (meshAsset)
|
||||
{
|
||||
meshAssetIdList.push_back(meshAsset->GetId());
|
||||
}
|
||||
}
|
||||
blastSliceAssetData->SetMeshIdList(meshAssetIdList);
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
}
|
||||
}
|
||||
AZ_Error(
|
||||
"Blast", false, "blast_slice assetId:%s missing EditorBlastMeshDataComponent!",
|
||||
asset->GetId().ToString<AZStd::string>().c_str());
|
||||
}
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
|
||||
{
|
||||
assetTypes.push_back(azrtti_typeid<BlastSliceAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::Register()
|
||||
{
|
||||
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid<BlastSliceAsset>());
|
||||
AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid<BlastSliceAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::Unregister()
|
||||
{
|
||||
AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid<BlastSliceAsset>());
|
||||
if (AZ::Data::AssetManager::IsReady())
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Data::AssetType EditorBlastSliceAssetHandler::GetAssetType() const
|
||||
{
|
||||
return azrtti_typeid<BlastSliceAsset>();
|
||||
}
|
||||
|
||||
const char* EditorBlastSliceAssetHandler::GetAssetTypeDisplayName() const
|
||||
{
|
||||
return "Blast Slice Asset";
|
||||
}
|
||||
|
||||
const char* EditorBlastSliceAssetHandler::GetGroup() const
|
||||
{
|
||||
return "Blast";
|
||||
}
|
||||
|
||||
const char* EditorBlastSliceAssetHandler::GetBrowserIcon() const
|
||||
{
|
||||
return "Icons/Components/Box.png";
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
|
||||
{
|
||||
extensions.push_back("blast_slice");
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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 <Asset/BlastSliceAsset.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Asset/AssetTypeInfoBus.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//! Used to create store asset references (i.e. ids) to fill out the EditorBlastMeshDataComponent
|
||||
class BlastSliceAssetStorageComponent final : public AzToolsFramework::Components::EditorComponentBase
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(
|
||||
BlastSliceAssetStorageComponent, "{696C7E62-1EA4-41E2-B4F6-7BD0D30888DC}",
|
||||
AzToolsFramework::Components::EditorComponentBase);
|
||||
|
||||
~BlastSliceAssetStorageComponent() override = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetMeshData() const
|
||||
{
|
||||
return m_meshAssetIdList;
|
||||
}
|
||||
|
||||
void SetMeshData(const AZStd::vector<AZ::Data::AssetId>& meshAssetIdList)
|
||||
{
|
||||
m_meshAssetIdList = meshAssetIdList;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::string>& GetMeshPathList() const
|
||||
{
|
||||
return m_meshAssetPathList;
|
||||
}
|
||||
|
||||
void SetMeshPathList(const AZStd::vector<AZStd::string>& meshAssetPathList)
|
||||
{
|
||||
m_meshAssetPathList = meshAssetPathList;
|
||||
}
|
||||
|
||||
private:
|
||||
// AZ::Component interface implementation
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
// EditorComponentBase
|
||||
void BuildGameEntity([[maybe_unused]] AZ::Entity* gameEntity) override {}
|
||||
|
||||
// Script API
|
||||
bool GenerateAssetInfo(
|
||||
const AZStd::vector<AZStd::string>& chunkNames,
|
||||
AZStd::string_view blastFilename,
|
||||
AZStd::string_view assetinfoFilename);
|
||||
|
||||
bool WriteMaterialFile(
|
||||
AZStd::string_view materialGroupName,
|
||||
const AZStd::vector<AZStd::string>& materialNames,
|
||||
AZStd::string_view materialFilename);
|
||||
|
||||
AZStd::vector<AZ::Data::AssetId> m_meshAssetIdList;
|
||||
AZStd::vector<AZStd::string> m_meshAssetPathList;
|
||||
};
|
||||
|
||||
class EditorBlastSliceAssetHandler final
|
||||
: public AZ::Data::AssetHandler
|
||||
, public AZ::AssetTypeInfoBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EditorBlastSliceAssetHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
~EditorBlastSliceAssetHandler() override;
|
||||
|
||||
// AZ::Data::AssetHandler
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
|
||||
LoadResult LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
|
||||
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
|
||||
|
||||
// AZ::AssetTypeInfoBus::Handler
|
||||
AZ::Data::AssetType GetAssetType() const override;
|
||||
const char* GetAssetTypeDisplayName() const override;
|
||||
const char* GetGroup() const override;
|
||||
const char* GetBrowserIcon() const override;
|
||||
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
|
||||
|
||||
void Register();
|
||||
void Unregister();
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <Editor/EditorSystemComponent.h>
|
||||
#include <Editor/EditorWindow.h>
|
||||
@@ -16,7 +16,7 @@ namespace Blast
|
||||
{
|
||||
void EditorSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
BlastSliceAsset::Reflect(context);
|
||||
BlastChunksAsset::Reflect(context);
|
||||
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
@@ -26,14 +26,14 @@ namespace Blast
|
||||
|
||||
void EditorSystemComponent::Activate()
|
||||
{
|
||||
m_editorBlastSliceAssetHandler = AZStd::make_unique<EditorBlastSliceAssetHandler>();
|
||||
m_editorBlastSliceAssetHandler->Register();
|
||||
m_editorBlastChunksAssetHandler = AZStd::make_unique<EditorBlastChunksAssetHandler>();
|
||||
m_editorBlastChunksAssetHandler->Register();
|
||||
|
||||
auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler();
|
||||
if (assetCatalog)
|
||||
{
|
||||
assetCatalog->EnableCatalogForAsset(azrtti_typeid<BlastSliceAsset>());
|
||||
assetCatalog->AddExtension("blast_slice");
|
||||
assetCatalog->EnableCatalogForAsset(azrtti_typeid<BlastChunksAsset>());
|
||||
assetCatalog->AddExtension("blast_chunks");
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
||||
@@ -46,7 +46,7 @@ namespace Blast
|
||||
void EditorSystemComponent::Deactivate()
|
||||
{
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
||||
m_editorBlastSliceAssetHandler.reset();
|
||||
m_editorBlastChunksAssetHandler.reset();
|
||||
}
|
||||
|
||||
// This will be called when the IEditor instance is ready
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
#include <Editor/EditorBlastChunksAssetHandler.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace Blast
|
||||
required.push_back(AZ_CRC("BlastService", 0x75beae2d));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<EditorBlastSliceAssetHandler> m_editorBlastSliceAssetHandler;
|
||||
AZStd::unique_ptr<EditorBlastChunksAssetHandler> m_editorBlastChunksAssetHandler;
|
||||
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <Editor/EditorBlastChunksAssetHandler.h>
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <AzCore/UnitTest/MockComponentApplication.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
MockComponentApplication::MockComponentApplication()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusConnect();
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
|
||||
}
|
||||
|
||||
MockComponentApplication::~MockComponentApplication()
|
||||
{
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
|
||||
AZ::ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
class MockAssetCatalogRequestBusHandler final
|
||||
: public AZ::Data::AssetCatalogRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD3(GetAssetIdByPath, AZ::Data::AssetId(const char*, const AZ::Data::AssetType&, bool));
|
||||
MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(AddAssetType, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD1(AddDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(AddExtension, void(const char*));
|
||||
MOCK_METHOD0(ClearCatalog, void());
|
||||
MOCK_METHOD5(CreateBundleManifest, bool(const AZStd::string&, const AZStd::vector<AZStd::string>&, const AZStd::string&, int, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD2(CreateDeltaCatalog, bool(const AZStd::vector<AZStd::string>&, const AZStd::string&));
|
||||
MOCK_METHOD0(DisableCatalog, void());
|
||||
MOCK_METHOD1(EnableCatalogForAsset, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD3(EnumerateAssets, void(BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB));
|
||||
MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId(const char*));
|
||||
MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&, const AZStd::unordered_set<AZ::Data::AssetId>&, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD1(GetAssetPathById, AZStd::string(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetHandledAssetTypes, void(AZStd::vector<AZ::Data::AssetType>&));
|
||||
MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector<AZStd::string>());
|
||||
MOCK_METHOD2(InsertDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, size_t));
|
||||
MOCK_METHOD2(InsertDeltaCatalogBefore, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(LoadCatalog, bool(const char*));
|
||||
MOCK_METHOD2(RegisterAsset, void(const AZ::Data::AssetId&, AZ::Data::AssetInfo&));
|
||||
MOCK_METHOD1(RemoveDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(SaveCatalog, bool(const char*));
|
||||
MOCK_METHOD0(StartMonitoringAssets, void());
|
||||
MOCK_METHOD0(StopMonitoringAssets, void());
|
||||
MOCK_METHOD1(UnregisterAsset, void(const AZ::Data::AssetId&));
|
||||
};
|
||||
|
||||
class MockAssetManager
|
||||
: public AZ::Data::AssetManager
|
||||
{
|
||||
public:
|
||||
MockAssetManager(const AZ::Data::AssetManager::Descriptor& desc) :
|
||||
AssetManager(desc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EditorBlastChunkAssetHandlerTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
AZStd::unique_ptr<UnitTest::MockComponentApplication> m_mockComponentApplicationBusHandler;
|
||||
AZStd::unique_ptr<MockAssetCatalogRequestBusHandler> m_mockAssetCatalogRequestBusHandler;
|
||||
AZStd::unique_ptr<MockAssetManager> m_mockAssetManager;
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
|
||||
void SetUpChunkComponents()
|
||||
{
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
|
||||
AZ::Entity::Reflect(m_serializeContext.get());
|
||||
AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
|
||||
}
|
||||
|
||||
void TearDownChunkComponents()
|
||||
{
|
||||
m_serializeContext.reset();
|
||||
}
|
||||
|
||||
void SetUp() override final
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
|
||||
m_mockComponentApplicationBusHandler = AZStd::make_unique<UnitTest::MockComponentApplication>();
|
||||
m_mockAssetCatalogRequestBusHandler = AZStd::make_unique<MockAssetCatalogRequestBusHandler>();
|
||||
m_mockAssetManager = AZStd::make_unique<MockAssetManager>(AZ::Data::AssetManager::Descriptor{});
|
||||
|
||||
AZ::Data::AssetManager::SetInstance(m_mockAssetManager.get());
|
||||
}
|
||||
|
||||
void TearDown() override final
|
||||
{
|
||||
m_mockAssetManager.release();
|
||||
AZ::Data::AssetManager::Destroy();
|
||||
|
||||
m_mockAssetCatalogRequestBusHandler.reset();
|
||||
m_mockComponentApplicationBusHandler.reset();
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
void SaveChunkAssetToStream(AZ::Entity* chunkAssetEntity, AZStd::vector<char>& buffer)
|
||||
{
|
||||
buffer.clear();
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
|
||||
AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext.get(), AZ::ObjectStream::ST_XML);
|
||||
objStream->WriteClass(chunkAssetEntity);
|
||||
EXPECT_TRUE(objStream->Finalize());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetManager_Registered)
|
||||
{
|
||||
Blast::EditorBlastChunksAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_NE(nullptr, AZ::Data::AssetManager::Instance().GetHandler(azrtti_typeid<Blast::BlastChunksAsset>()));
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetTypeInfoBus_Responds)
|
||||
{
|
||||
auto assetId = azrtti_typeid<Blast::BlastChunksAsset>();
|
||||
|
||||
Blast::EditorBlastChunksAssetHandler handler;
|
||||
handler.Register();
|
||||
|
||||
AZ::Data::AssetType assetType = AZ::Uuid::CreateNull();
|
||||
AZ::AssetTypeInfoBus::EventResult(assetType, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetType);
|
||||
EXPECT_NE(AZ::Uuid::CreateNull(), assetType);
|
||||
|
||||
const char* displayName = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(displayName, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeDisplayName);
|
||||
EXPECT_STREQ("Blast Chunks Asset", displayName);
|
||||
|
||||
const char* group = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(group, assetId, &AZ::AssetTypeInfoBus::Events::GetGroup);
|
||||
EXPECT_STREQ("Blast", group);
|
||||
|
||||
const char* icon = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(icon, assetId, &AZ::AssetTypeInfoBus::Events::GetBrowserIcon);
|
||||
EXPECT_STREQ("Icons/Components/Box.png", icon);
|
||||
|
||||
AZStd::vector<AZStd::string> extensions;
|
||||
AZ::AssetTypeInfoBus::Event(assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeExtensions, extensions);
|
||||
ASSERT_EQ(1, extensions.size());
|
||||
ASSERT_EQ("blast_chunks", extensions[0]);
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetHandler_Ready)
|
||||
{
|
||||
auto assetType = azrtti_typeid<Blast::BlastChunksAsset>();
|
||||
auto&& assetManager = AZ::Data::AssetManager::Instance();
|
||||
|
||||
Blast::EditorBlastChunksAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_EQ(&handler, assetManager.GetHandler(assetType));
|
||||
|
||||
// create and release an instance of the BlastChunkAsset asset type
|
||||
{
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetInfo{}));
|
||||
|
||||
auto assetPtr = assetManager.CreateAsset<Blast::BlastChunksAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0));
|
||||
EXPECT_NE(nullptr, assetPtr.Get());
|
||||
EXPECT_EQ(azrtti_typeid<Blast::BlastChunksAsset>(), assetPtr.GetType());
|
||||
}
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
|
||||
#include <AzCore/UnitTest/MockComponentApplication.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class MockComponentApplicationBusHandler final
|
||||
//: public MockComponentApplication
|
||||
: public AZ::ComponentApplicationBus::Handler
|
||||
{
|
||||
public:
|
||||
MockComponentApplicationBusHandler()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockComponentApplicationBusHandler()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD0(Destroy, void());
|
||||
MOCK_METHOD1(RegisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*));
|
||||
MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&));
|
||||
MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&));
|
||||
MOCK_METHOD1(AddEntity, bool(AZ::Entity*));
|
||||
MOCK_METHOD1(FindEntity, AZ::Entity*(const AZ::EntityId&));
|
||||
MOCK_METHOD1(EnumerateEntities, void(const ComponentApplicationRequests::EntityCallback&));
|
||||
MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
|
||||
MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
|
||||
MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
|
||||
MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
|
||||
MOCK_METHOD0(GetAppRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_METHOD0(GetTickDeltaTime, float());
|
||||
MOCK_METHOD1(Tick, void(float));
|
||||
MOCK_METHOD0(TickSystem, void());
|
||||
MOCK_CONST_METHOD0(GetRequiredSystemComponents, AZ::ComponentTypeList());
|
||||
MOCK_METHOD1(ResolveModulePath, void(AZ::OSString&));
|
||||
MOCK_METHOD0(CreateSerializeContext, void());
|
||||
MOCK_METHOD0(DestroySerializeContext, void());
|
||||
MOCK_METHOD0(CreateBehaviorContext, void());
|
||||
MOCK_METHOD0(DestroyBehaviorContext, void());
|
||||
MOCK_METHOD0(RegisterCoreComponents, void());
|
||||
MOCK_METHOD1(AddSystemComponents, void(AZ::Entity*));
|
||||
MOCK_METHOD0(ReflectSerialize, void());
|
||||
MOCK_METHOD1(Reflect, void(AZ::ReflectContext*));
|
||||
MOCK_CONST_METHOD0(GetBinFolder, const char* ());
|
||||
};
|
||||
|
||||
class MockAssetCatalogRequestBusHandler final
|
||||
: public AZ::Data::AssetCatalogRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD3(GetAssetIdByPath, AZ::Data::AssetId(const char*, const AZ::Data::AssetType&, bool));
|
||||
MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(AddAssetType, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD1(AddDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(AddExtension, void(const char*));
|
||||
MOCK_METHOD0(ClearCatalog, void());
|
||||
MOCK_METHOD5(CreateBundleManifest, bool(const AZStd::string&, const AZStd::vector<AZStd::string>&, const AZStd::string&, int, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD2(CreateDeltaCatalog, bool(const AZStd::vector<AZStd::string>&, const AZStd::string&));
|
||||
MOCK_METHOD0(DisableCatalog, void());
|
||||
MOCK_METHOD1(EnableCatalogForAsset, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD3(EnumerateAssets, void(BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB));
|
||||
MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId(const char*));
|
||||
MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&, const AZStd::unordered_set<AZ::Data::AssetId>&, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD1(GetAssetPathById, AZStd::string(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetHandledAssetTypes, void(AZStd::vector<AZ::Data::AssetType>&));
|
||||
MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector<AZStd::string>());
|
||||
MOCK_METHOD2(InsertDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, size_t));
|
||||
MOCK_METHOD2(InsertDeltaCatalogBefore, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(LoadCatalog, bool(const char*));
|
||||
MOCK_METHOD2(RegisterAsset, void(const AZ::Data::AssetId&, AZ::Data::AssetInfo&));
|
||||
MOCK_METHOD1(RemoveDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(SaveCatalog, bool(const char*));
|
||||
MOCK_METHOD0(StartMonitoringAssets, void());
|
||||
MOCK_METHOD0(StopMonitoringAssets, void());
|
||||
MOCK_METHOD1(UnregisterAsset, void(const AZ::Data::AssetId&));
|
||||
};
|
||||
|
||||
class MockAssetManager
|
||||
: public AZ::Data::AssetManager
|
||||
{
|
||||
public:
|
||||
MockAssetManager(const AZ::Data::AssetManager::Descriptor& desc) :
|
||||
AssetManager(desc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EditorBlastSliceAssetHandlerTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
AZStd::unique_ptr<MockComponentApplicationBusHandler> m_mockComponentApplicationBusHandler;
|
||||
//AZStd::unique_ptr<UnitTest::MockComponentApplication> m_mockComponentApplicationBusHandler;
|
||||
AZStd::unique_ptr<MockAssetCatalogRequestBusHandler> m_mockAssetCatalogRequestBusHandler;
|
||||
AZStd::unique_ptr<MockAssetManager> m_mockAssetManager;
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
const AZ::ComponentDescriptor* m_sliceComponentDescriptor = nullptr;
|
||||
|
||||
void SetUpSliceComponents()
|
||||
{
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
|
||||
AZ::Entity::Reflect(m_serializeContext.get());
|
||||
Blast::BlastSliceAssetStorageComponent::Reflect(m_serializeContext.get());
|
||||
AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
|
||||
|
||||
m_sliceComponentDescriptor = AZ::SliceComponent::CreateDescriptor();
|
||||
m_sliceComponentDescriptor->Reflect(m_serializeContext.get());
|
||||
}
|
||||
|
||||
void TearDownSliceComponents()
|
||||
{
|
||||
delete m_sliceComponentDescriptor;
|
||||
m_serializeContext.reset();
|
||||
}
|
||||
|
||||
void SetUp() override final
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
|
||||
m_mockComponentApplicationBusHandler = AZStd::make_unique<MockComponentApplicationBusHandler>();
|
||||
m_mockAssetCatalogRequestBusHandler = AZStd::make_unique<MockAssetCatalogRequestBusHandler>();
|
||||
m_mockAssetManager = AZStd::make_unique<MockAssetManager>(AZ::Data::AssetManager::Descriptor{});
|
||||
|
||||
AZ::Data::AssetManager::SetInstance(m_mockAssetManager.get());
|
||||
}
|
||||
|
||||
void TearDown() override final
|
||||
{
|
||||
AZ::Data::AssetManager::SetInstance(nullptr);
|
||||
|
||||
m_mockAssetManager.reset();
|
||||
m_mockAssetCatalogRequestBusHandler.reset();
|
||||
m_mockComponentApplicationBusHandler.reset();
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
void SaveSliceAssetToStream(AZ::Entity* sliceAssetEntity, AZStd::vector<char>& buffer)
|
||||
{
|
||||
buffer.clear();
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
|
||||
AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext.get(), AZ::ObjectStream::ST_XML);
|
||||
objStream->WriteClass(sliceAssetEntity);
|
||||
EXPECT_TRUE(objStream->Finalize());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetManager_Registered)
|
||||
{
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_NE(nullptr, AZ::Data::AssetManager::Instance().GetHandler(azrtti_typeid<Blast::BlastSliceAsset>()));
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, BlastSliceAssetStorageComponent_Behavior_Registered)
|
||||
{
|
||||
AZ::BehaviorContext behaviorContext;
|
||||
Blast::BlastSliceAssetStorageComponent::Reflect(&behaviorContext);
|
||||
|
||||
auto classEntry = behaviorContext.m_classes.find("BlastSliceAssetStorageComponent");
|
||||
EXPECT_NE(behaviorContext.m_classes.end(), classEntry);
|
||||
AZ::BehaviorClass* behaviorClass = classEntry->second;
|
||||
auto methodEntry = behaviorClass->m_methods.find("GenerateAssetInfo");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), methodEntry);
|
||||
AZ::BehaviorMethod* behaviorMethod = methodEntry->second;
|
||||
EXPECT_EQ(4, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAssetStorageComponent>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid<AZStd::vector<AZStd::string>>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(2)->m_typeId, azrtti_typeid<AZStd::string_view>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(3)->m_typeId, azrtti_typeid<AZStd::string_view>());
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, BlastSliceAsset_Behavior_Registered)
|
||||
{
|
||||
AZ::BehaviorContext behaviorContext;
|
||||
Blast::BlastSliceAsset::Reflect(&behaviorContext);
|
||||
|
||||
auto classEntry = behaviorContext.m_classes.find("BlastSliceAsset");
|
||||
EXPECT_NE(behaviorContext.m_classes.end(), classEntry);
|
||||
AZ::BehaviorClass* behaviorClass = classEntry->second;
|
||||
|
||||
auto setMeshIdListEntry = behaviorClass->m_methods.find("SetMeshIdList");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), setMeshIdListEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = setMeshIdListEntry->second;
|
||||
EXPECT_EQ(2, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid<AZStd::vector<AZ::Data::AssetId>>());
|
||||
}
|
||||
|
||||
auto getMeshIdListEntry = behaviorClass->m_methods.find("GetMeshIdList");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), getMeshIdListEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = getMeshIdListEntry->second;
|
||||
EXPECT_EQ(1, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid<AZStd::vector<AZ::Data::AssetId>>());
|
||||
}
|
||||
|
||||
auto setMaterialIdEntry = behaviorClass->m_methods.find("SetMaterialId");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), setMaterialIdEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = setMaterialIdEntry->second;
|
||||
EXPECT_EQ(2, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid<AZ::Data::AssetId>());
|
||||
}
|
||||
|
||||
auto getMaterialIdEntry = behaviorClass->m_methods.find("GetMaterialId");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), getMaterialIdEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = getMaterialIdEntry->second;
|
||||
EXPECT_EQ(1, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid<AZ::Data::AssetId>());
|
||||
}
|
||||
|
||||
auto getAssetTypeIdEntry = behaviorClass->m_methods.find("GetAssetTypeId");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), getAssetTypeIdEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = getAssetTypeIdEntry->second;
|
||||
EXPECT_EQ(1, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid<AZ::TypeId>());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetTypeInfoBus_Responds)
|
||||
{
|
||||
auto assetId = azrtti_typeid<Blast::BlastSliceAsset>();
|
||||
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
|
||||
AZ::Data::AssetType assetType = AZ::Uuid::CreateNull();
|
||||
AZ::AssetTypeInfoBus::EventResult(assetType, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetType);
|
||||
EXPECT_NE(AZ::Uuid::CreateNull(), assetType);
|
||||
|
||||
const char* displayName = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(displayName, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeDisplayName);
|
||||
EXPECT_STREQ("Blast Slice Asset", displayName);
|
||||
|
||||
const char* group = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(group, assetId, &AZ::AssetTypeInfoBus::Events::GetGroup);
|
||||
EXPECT_STREQ("Blast", group);
|
||||
|
||||
const char* icon = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(icon, assetId, &AZ::AssetTypeInfoBus::Events::GetBrowserIcon);
|
||||
EXPECT_STREQ("Editor/Icons/Components/Box.png", icon);
|
||||
|
||||
AZStd::vector<AZStd::string> extensions;
|
||||
AZ::AssetTypeInfoBus::Event(assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeExtensions, extensions);
|
||||
ASSERT_EQ(1, extensions.size());
|
||||
ASSERT_EQ("blast_slice", extensions[0]);
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetHandler_Ready)
|
||||
{
|
||||
auto assetType = azrtti_typeid<Blast::BlastSliceAsset>();
|
||||
auto&& assetManager = AZ::Data::AssetManager::Instance();
|
||||
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_EQ(&handler, assetManager.GetHandler(assetType));
|
||||
|
||||
// create and release an instance of the BlastSliceAsset asset type
|
||||
{
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetInfo{}));
|
||||
|
||||
auto assetPtr = assetManager.CreateAsset<Blast::BlastSliceAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0));
|
||||
EXPECT_NE(nullptr, assetPtr.Get());
|
||||
EXPECT_EQ(azrtti_typeid<Blast::BlastSliceAsset>(), assetPtr.GetType());
|
||||
}
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetHandler_LoadsAssetData)
|
||||
{
|
||||
SetUpSliceComponents();
|
||||
|
||||
AZStd::vector<AZStd::string> meshAssetPathList = { "/foo/path/thing.cgf", "/foo/path/that.cgf" };
|
||||
AZ::Entity* storageEntity = aznew AZ::Entity();
|
||||
auto* blastStorage = storageEntity->CreateComponent<Blast::BlastSliceAssetStorageComponent>();
|
||||
blastStorage->SetMeshPathList(meshAssetPathList);
|
||||
|
||||
AZ::Entity sliceEntity;
|
||||
AZ::SliceComponent* slice = sliceEntity.CreateComponent<AZ::SliceComponent>();
|
||||
slice->AddEntity(storageEntity);
|
||||
|
||||
AZStd::vector<char> buffer;
|
||||
SaveSliceAssetToStream(&sliceEntity, buffer);
|
||||
|
||||
// Load a slice with the BlastSliceAssetStorageComponent
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
{
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
EXPECT_CALL(*m_mockComponentApplicationBusHandler, GetSerializeContext)
|
||||
.Times(1)
|
||||
.WillOnce(Return(m_serializeContext.get()));
|
||||
|
||||
EXPECT_CALL(*m_mockComponentApplicationBusHandler, FindEntity(_))
|
||||
.Times(1)
|
||||
.WillOnce(Return(&sliceEntity));
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetIdByPath(_,_,_))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0)));
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetInfo{}));
|
||||
|
||||
auto&& assetManager = AZ::Data::AssetManager::Instance();
|
||||
auto assetPtr = assetManager.CreateAsset<Blast::BlastSliceAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0));
|
||||
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
|
||||
stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
|
||||
|
||||
const AZ::Data::AssetFilterCB assetLoadFilterCB{};
|
||||
bool loaded = handler.LoadAssetData(assetPtr, &stream, assetLoadFilterCB);
|
||||
EXPECT_TRUE(loaded);
|
||||
}
|
||||
handler.Unregister();
|
||||
|
||||
TearDownSliceComponents();
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ set(FILES
|
||||
Source/Editor/EditorBlastFamilyComponent.cpp
|
||||
Source/Editor/EditorBlastMeshDataComponent.cpp
|
||||
Source/Editor/EditorBlastMeshDataComponent.h
|
||||
Source/Editor/EditorBlastSliceAssetHandler.h
|
||||
Source/Editor/EditorBlastSliceAssetHandler.cpp
|
||||
Source/Editor/EditorBlastChunksAssetHandler.h
|
||||
Source/Editor/EditorBlastChunksAssetHandler.cpp
|
||||
Source/Editor/EditorSystemComponent.h
|
||||
Source/Editor/EditorSystemComponent.cpp
|
||||
Editor/ConfigurationWidget.h
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
# Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp
|
||||
Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp
|
||||
Tests/Editor/EditorTestMain.cpp
|
||||
)
|
||||
|
||||
@@ -26,8 +26,8 @@ set(FILES
|
||||
Source/Asset/BlastAsset.cpp
|
||||
Source/Asset/BlastAssetHandler.h
|
||||
Source/Asset/BlastAssetHandler.cpp
|
||||
Source/Asset/BlastSliceAsset.h
|
||||
Source/Asset/BlastSliceAsset.cpp
|
||||
Source/Asset/BlastChunksAsset.h
|
||||
Source/Asset/BlastChunksAsset.cpp
|
||||
Source/Components/BlastFamilyComponent.h
|
||||
Source/Components/BlastFamilyComponent.cpp
|
||||
Source/Components/BlastFamilyComponentNotificationBusHandler.h
|
||||
|
||||
@@ -1,323 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
def install_user_site():
|
||||
import os
|
||||
import sys
|
||||
import azlmbr.paths
|
||||
executableBinFolder = azlmbr.paths.executableFolder
|
||||
|
||||
# the PyAssImp module checks the Windows PATH for the assimp DLL file
|
||||
if os.name == "nt":
|
||||
os.environ['PATH'] = os.environ['PATH'] + os.pathsep + executableBinFolder
|
||||
|
||||
# PyAssImp module needs to find the shared library for assimp to load; "posix" handles Mac and Linux
|
||||
if os.name == "posix":
|
||||
if 'LD_LIBRARY_PATH' in os.environ:
|
||||
os.environ['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] + os.pathsep + executableBinFolder
|
||||
else:
|
||||
os.environ['LD_LIBRARY_PATH'] = executableBinFolder
|
||||
|
||||
# add the user site packages folder to find the pyassimp egg link
|
||||
import site
|
||||
for item in sys.path:
|
||||
if (item.find('site-packages') != -1):
|
||||
site.addsitedir(item)
|
||||
|
||||
install_user_site()
|
||||
import pyassimp
|
||||
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.builder
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.blast
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity
|
||||
import azlmbr.math
|
||||
import os
|
||||
import traceback
|
||||
import binascii
|
||||
import sys
|
||||
|
||||
# the UUID must be unique amongst all the asset builders in Python or otherwise
|
||||
# a collision of builders will happen preventing one from running
|
||||
busIdString = '{CF5C74D1-9ED4-4851-85B1-9B15090DBEC7}'
|
||||
busId = azlmbr.math.Uuid_CreateString(busIdString, 0)
|
||||
handler = None
|
||||
jobKeyName = 'Blast Chunk Assets'
|
||||
sceneManifestType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0)
|
||||
dccMaterialType = azlmbr.math.Uuid_CreateString('{C88469CF-21E7-41EB-96FD-BF14FBB05EDC}', 0)
|
||||
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
|
||||
def get_source_fbx_filename(request):
|
||||
fullPath = os.path.join(request.watchFolder, request.sourceFile)
|
||||
basePath, filePart = os.path.split(fullPath)
|
||||
filename = os.path.splitext(filePart)[0] + '.fbx'
|
||||
filename = os.path.join(basePath, filename)
|
||||
return filename
|
||||
|
||||
|
||||
def raise_error(message):
|
||||
raise RuntimeError(f'[ERROR]: {message}')
|
||||
|
||||
|
||||
def generate_asset_info(chunkNames, request):
|
||||
import azlmbr.blast
|
||||
|
||||
# write out an object stream with the extension of .fbx.assetinfo.generated
|
||||
basePath, sceneFile = os.path.split(request.sourceFile)
|
||||
assetinfoFilename = os.path.splitext(sceneFile)[0] + '.fbx.assetinfo.generated'
|
||||
assetinfoFilename = os.path.join(basePath, assetinfoFilename)
|
||||
assetinfoFilename = assetinfoFilename.replace('\\', '/').lower()
|
||||
outputFilename = os.path.join(request.tempDirPath, assetinfoFilename)
|
||||
|
||||
storage = azlmbr.blast.BlastSliceAssetStorageComponent()
|
||||
if (storage.GenerateAssetInfo(chunkNames, request.sourceFile, outputFilename)):
|
||||
product = azlmbr.asset.builder.JobProduct(assetinfoFilename, sceneManifestType, 1)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
raise_error('Failed to generate assetinfo.generated')
|
||||
|
||||
|
||||
def export_fbx_manifest(request):
|
||||
output = []
|
||||
fbxFilename = get_source_fbx_filename(request)
|
||||
sceneAsset = pyassimp.load(fbxFilename)
|
||||
with sceneAsset as scene:
|
||||
rootNode = scene.mRootNode.contents
|
||||
for index in range(0, rootNode.mNumChildren):
|
||||
child = rootNode.mChildren[index]
|
||||
childNode = child.contents
|
||||
childNodeName = bytes.decode(childNode.mName.data)
|
||||
output.append(str(childNodeName))
|
||||
return output
|
||||
|
||||
|
||||
def convert_to_asset_paths(fbxFilename, gameRoot, chunkNameList):
|
||||
realtivePath = fbxFilename[len(gameRoot) + 1:]
|
||||
realtivePath = os.path.splitext(realtivePath)[0]
|
||||
output = []
|
||||
for chunk in chunkNameList:
|
||||
assetPath = realtivePath + '-' + chunk + '.cgf'
|
||||
assetPath = assetPath.replace('\\', '/')
|
||||
assetPath = assetPath.lower()
|
||||
output.append(assetPath)
|
||||
return output
|
||||
|
||||
|
||||
# creates a single job to compile for each platform
|
||||
def create_jobs(request):
|
||||
fbxSidecarFilename = get_source_fbx_filename(request)
|
||||
if (os.path.exists(fbxSidecarFilename) is False):
|
||||
print('[WARN] Sidecar FBX file {} is missing for blast file {}'.format(fbxSidecarFilename, request.sourceFile))
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
# see if the FBX file already has a .assetinfo source asset, if so then do not create a job
|
||||
if (os.path.exists(f'{fbxSidecarFilename}.assetinfo')):
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
return response
|
||||
|
||||
# create job descriptor for each platform
|
||||
jobDescriptorList = []
|
||||
for platformInfo in request.enabledPlatforms:
|
||||
jobDesc = azlmbr.asset.builder.JobDescriptor()
|
||||
jobDesc.jobKey = jobKeyName
|
||||
jobDesc.priority = 12 # higher than the 'Scene compilation' or 'fbx'
|
||||
jobDesc.set_platform_identifier(platformInfo.identifier)
|
||||
jobDescriptorList.append(jobDesc)
|
||||
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
response.createJobOutputs = jobDescriptorList
|
||||
return response
|
||||
|
||||
# handler to create jobs for a source asset
|
||||
|
||||
|
||||
def on_create_jobs(args):
|
||||
try:
|
||||
request = args[0]
|
||||
return create_jobs(request)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
|
||||
def generate_blast_slice_asset(chunkNameList, request):
|
||||
# get list of relative chunk paths
|
||||
fbxFilename = get_source_fbx_filename(request)
|
||||
assetPaths = convert_to_asset_paths(fbxFilename, request.watchFolder, chunkNameList)
|
||||
|
||||
outcome = azlmbr.asset.entity.PythonBuilderRequestBus(bus.Broadcast, 'CreateEditorEntity', 'BlastData')
|
||||
if (outcome.IsSuccess() is False):
|
||||
raise_error('could not create an editor entity')
|
||||
blastDataEntityId = outcome.GetValue()
|
||||
|
||||
# create a component for the editor entity
|
||||
gameType = azlmbr.entity.EntityType().Game
|
||||
blastMeshDataTypeIdList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Blast Slice Storage Component"], gameType)
|
||||
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', blastDataEntityId, blastMeshDataTypeIdList[0])
|
||||
if (componentOutcome.IsSuccess() is False):
|
||||
raise_error('failed to add component (Blast Slice Storage Component) to the blast_slice')
|
||||
|
||||
# build the blast slice using the chunk asset paths
|
||||
blastMeshComponentId = componentOutcome.GetValue()[0]
|
||||
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', blastMeshComponentId)
|
||||
if(outcome.IsSuccess() is False):
|
||||
raise_error(f'failed to create Property Tree Editor for component ({blastMeshComponentId})')
|
||||
pte = outcome.GetValue()
|
||||
pte.set_visible_enforcement(True)
|
||||
pte.set_value('Mesh Paths', assetPaths)
|
||||
|
||||
# write out an object stream with the extension of .blast_slice
|
||||
basePath, sceneFile = os.path.split(request.sourceFile)
|
||||
blastFilename = os.path.splitext(sceneFile)[0] + '.blast_slice'
|
||||
blastFilename = os.path.join(basePath, blastFilename)
|
||||
blastFilename = blastFilename.replace('\\', '/').lower()
|
||||
tempFilename = os.path.join(request.tempDirPath, blastFilename)
|
||||
entityList = [blastDataEntityId]
|
||||
makeDynamic = False
|
||||
outcome = azlmbr.asset.entity.PythonBuilderRequestBus(bus.Broadcast, 'WriteSliceFile', tempFilename, entityList, makeDynamic)
|
||||
if (outcome.IsSuccess() is False):
|
||||
raise_error(f'WriteSliceFile failed for blast_slice file ({blastFilename})')
|
||||
|
||||
# return a job product
|
||||
blastSliceAsset = azlmbr.blast.BlastSliceAsset()
|
||||
subId = binascii.crc32(blastFilename.encode('utf8'))
|
||||
product = azlmbr.asset.builder.JobProduct(blastFilename, blastSliceAsset.GetAssetTypeId(), subId)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
|
||||
|
||||
def read_in_string(data, dataLength):
|
||||
stringData = ''
|
||||
for idx in range(4, dataLength - 1):
|
||||
char = bytes.decode(data[idx])
|
||||
if (str.isascii(char)):
|
||||
stringData += char
|
||||
return stringData
|
||||
|
||||
|
||||
def import_material_info(fbxFilename):
|
||||
_, group_name = os.path.split(fbxFilename)
|
||||
group_name = os.path.splitext(group_name)[0]
|
||||
output = {}
|
||||
output['group_name'] = group_name
|
||||
output['material_name_list'] = []
|
||||
sceneAsset = pyassimp.load(fbxFilename)
|
||||
with sceneAsset as scene:
|
||||
for materialIndex in range(0, scene.mNumMaterials):
|
||||
material = scene.mMaterials[materialIndex].contents
|
||||
for materialPropertyIdx in range(0, material.mNumProperties):
|
||||
materialProperty = material.mProperties[materialPropertyIdx].contents
|
||||
materialPropertyName = bytes.decode(materialProperty.mKey.data)
|
||||
if (materialPropertyName.endswith('mat.name') and materialProperty.mType is 3):
|
||||
stringData = read_in_string(materialProperty.mData, materialProperty.mDataLength)
|
||||
output['material_name_list'].append(stringData)
|
||||
return output
|
||||
|
||||
|
||||
def write_material_file(sourceFile, destFolder):
|
||||
# preserve source MTL files
|
||||
rootPath, materialSourceFile = os.path.split(sourceFile)
|
||||
materialSourceFile = os.path.splitext(materialSourceFile)[0] + '.mtl'
|
||||
materialSourceFile = os.path.join(rootPath, materialSourceFile)
|
||||
if (os.path.exists(materialSourceFile)):
|
||||
print(f'{materialSourceFile} source already exists')
|
||||
return None
|
||||
|
||||
# auto-generate a DCC material file
|
||||
info = import_material_info(sourceFile)
|
||||
materialGroupName = info['group_name']
|
||||
materialNames = info['material_name_list']
|
||||
materialFilename = materialGroupName + '.dccmtl.generated'
|
||||
subId = binascii.crc32(materialFilename.encode('utf8'))
|
||||
materialFilename = os.path.join(destFolder, materialFilename)
|
||||
storage = azlmbr.blast.BlastSliceAssetStorageComponent()
|
||||
storage.WriteMaterialFile(materialGroupName, materialNames, materialFilename)
|
||||
product = azlmbr.asset.builder.JobProduct(materialFilename, dccMaterialType, subId)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
|
||||
|
||||
def process_fbx_file(request):
|
||||
# fill out response object
|
||||
response = azlmbr.asset.builder.ProcessJobResponse()
|
||||
productOutputs = []
|
||||
|
||||
# write out DCCMTL file as a product (if needed)
|
||||
materialProduct = write_material_file(get_source_fbx_filename(request), request.tempDirPath)
|
||||
if (materialProduct is not None):
|
||||
productOutputs.append(materialProduct)
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(request.sourceFile)
|
||||
outputPath = os.path.join(request.tempDirPath, basePath)
|
||||
os.makedirs(outputPath)
|
||||
|
||||
# parse FBX for chunk names
|
||||
chunkNameList = export_fbx_manifest(request)
|
||||
|
||||
# create assetinfo generated (is product)
|
||||
productOutputs.append(generate_asset_info(chunkNameList, request))
|
||||
|
||||
# write out the blast_slice object stream
|
||||
productOutputs.append(generate_blast_slice_asset(chunkNameList, request))
|
||||
|
||||
response.outputProducts = productOutputs
|
||||
response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success
|
||||
response.dependenciesHandled = True
|
||||
return response
|
||||
|
||||
|
||||
# using the incoming 'request' find the type of job via 'jobKey' to determine what to do
|
||||
def on_process_job(args):
|
||||
try:
|
||||
request = args[0]
|
||||
if (request.jobDescription.jobKey.startswith(jobKeyName)):
|
||||
return process_fbx_file(request)
|
||||
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
|
||||
# register asset builder
|
||||
def register_asset_builder():
|
||||
assetPattern = azlmbr.asset.builder.AssetBuilderPattern()
|
||||
assetPattern.pattern = '*.blast'
|
||||
assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard
|
||||
|
||||
builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc()
|
||||
builderDescriptor.name = "Blast Gem"
|
||||
builderDescriptor.patterns = [assetPattern]
|
||||
builderDescriptor.busId = busId
|
||||
builderDescriptor.version = 5
|
||||
|
||||
outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor)
|
||||
if outcome.IsSuccess():
|
||||
# created the asset builder to hook into the notification bus
|
||||
handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler()
|
||||
handler.connect(busId)
|
||||
handler.add_callback('OnCreateJobsRequest', on_create_jobs)
|
||||
handler.add_callback('OnProcessJobRequest', on_process_job)
|
||||
return handler
|
||||
|
||||
|
||||
# create the asset builder handler
|
||||
try:
|
||||
handler = register_asset_builder()
|
||||
except:
|
||||
handler = None
|
||||
log_exception_traceback()
|
||||
@@ -0,0 +1,290 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
"""
|
||||
This a Python Asset Builder script examines each .blast file to see if an
|
||||
associated .fbx file needs to be processed by exporting all of its chunks
|
||||
into a scene manifest
|
||||
|
||||
This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene
|
||||
manifest that writes out asset chunk data for .blast files
|
||||
"""
|
||||
import os, traceback, binascii, sys, json, pathlib
|
||||
import azlmbr.math
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.asset.builder
|
||||
import azlmbr.bus
|
||||
|
||||
#
|
||||
# Python Asset Builder
|
||||
#
|
||||
busId = azlmbr.math.Uuid_CreateString('{D4FA20E3-8EF4-44A3-A045-AAE6C1CCAAAB}', 0)
|
||||
jobKeyName = 'Blast Chunk Assets'
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def raise_error(message):
|
||||
print (f'ERROR - {message}');
|
||||
raise RuntimeError(f'[ERROR]: {message}');
|
||||
|
||||
# creates a single job to compile for each platform
|
||||
def get_source_fbx_filename(request):
|
||||
fullPath = os.path.join(request.watchFolder, request.sourceFile)
|
||||
basePath, filePart = os.path.split(fullPath)
|
||||
filename = os.path.splitext(filePart)[0] + '.fbx'
|
||||
filename = os.path.join(basePath, filename)
|
||||
return filename
|
||||
|
||||
def create_jobs(request):
|
||||
fbxSidecarFilename = get_source_fbx_filename(request)
|
||||
if (os.path.exists(fbxSidecarFilename) is False):
|
||||
print('[WARN] Sidecar FBX file {} is missing for blast file {}'.format(fbxSidecarFilename, request.sourceFile))
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
# see if the FBX file already has a .assetinfo source asset, if so then do not create a job
|
||||
establishedAssetInfo = f'{fbxSidecarFilename}.assetinfo';
|
||||
if (os.path.exists(establishedAssetInfo)):
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
return response
|
||||
|
||||
# create job descriptor for each platform
|
||||
jobDescriptorList = []
|
||||
for platformInfo in request.enabledPlatforms:
|
||||
sourceFileDependency = azlmbr.asset.builder.SourceFileDependency()
|
||||
sourceFileDependency.sourceFileDependencyPath = fbxSidecarFilename
|
||||
|
||||
jobDependency = azlmbr.asset.builder.JobDependency()
|
||||
jobDependency.sourceFile = sourceFileDependency
|
||||
jobDependency.jobKey = jobKeyName
|
||||
jobDependency.platformIdentifier = platformInfo.identifier
|
||||
|
||||
jobDesc = azlmbr.asset.builder.JobDescriptor()
|
||||
jobDesc.jobKey = jobKeyName
|
||||
jobDesc.set_platform_identifier(platformInfo.identifier)
|
||||
jobDesc.jobDependencyList = [jobDependency]
|
||||
jobDescriptorList.append(jobDesc)
|
||||
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
response.createJobOutputs = jobDescriptorList
|
||||
return response
|
||||
|
||||
# to create jobs for a source asset
|
||||
def on_create_jobs(args):
|
||||
try:
|
||||
request = args[0]
|
||||
return create_jobs(request)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
def generate_assetinfo_product(request):
|
||||
# write out a product asset file with the extension of .fbx.assetinfo.generated
|
||||
basePath, sceneFile = os.path.split(request.sourceFile)
|
||||
assetinfoFilename = os.path.splitext(sceneFile)[0] + '.fbx.assetinfo.generated'
|
||||
assetinfoFilename = os.path.join(basePath, assetinfoFilename)
|
||||
assetinfoFilename = assetinfoFilename.replace('\\', '/').lower()
|
||||
outputFilename = os.path.join(request.tempDirPath, assetinfoFilename)
|
||||
|
||||
# the only rule in it is to run this file again as a scene processor
|
||||
currentScript = pathlib.Path(__file__).resolve()
|
||||
aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]}
|
||||
jsonString = json.dumps(aDict)
|
||||
jsonFile = open(outputFilename, "w")
|
||||
jsonFile.write(jsonString)
|
||||
jsonFile.close()
|
||||
|
||||
# return a job product for the generated assetinfo file
|
||||
sceneManifestType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0)
|
||||
subId = 1
|
||||
product = azlmbr.asset.builder.JobProduct(outputFilename, sceneManifestType, subId)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
|
||||
def process_fbx_file(request):
|
||||
# fill out response object
|
||||
response = azlmbr.asset.builder.ProcessJobResponse()
|
||||
productOutputs = []
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(request.sourceFile)
|
||||
outputPath = os.path.join(request.tempDirPath, basePath)
|
||||
os.makedirs(outputPath)
|
||||
|
||||
# create assetinfo generated file
|
||||
productOutputs.append(generate_assetinfo_product(request))
|
||||
|
||||
response.outputProducts = productOutputs
|
||||
response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success
|
||||
response.dependenciesHandled = True
|
||||
return response
|
||||
|
||||
# using the incoming 'request' find the type of job via 'jobKey' to determine what to do
|
||||
def on_process_job(args):
|
||||
try:
|
||||
request = args[0]
|
||||
if (request.jobDescription.jobKey.startswith(jobKeyName)):
|
||||
return process_fbx_file(request)
|
||||
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
|
||||
# register asset builder
|
||||
def register_asset_builder():
|
||||
assetPattern = azlmbr.asset.builder.AssetBuilderPattern()
|
||||
assetPattern.pattern = '*.blast'
|
||||
assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard
|
||||
|
||||
builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc()
|
||||
builderDescriptor.name = "Blast Scene Builder"
|
||||
builderDescriptor.patterns = [assetPattern]
|
||||
builderDescriptor.busId = busId
|
||||
builderDescriptor.version = 1
|
||||
|
||||
outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor)
|
||||
if outcome.IsSuccess():
|
||||
# created the asset builder to hook into the notification bus
|
||||
handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler()
|
||||
handler.connect(busId)
|
||||
handler.add_callback('OnCreateJobsRequest', on_create_jobs)
|
||||
handler.add_callback('OnProcessJobRequest', on_process_job)
|
||||
return handler
|
||||
|
||||
# create the asset builder handler
|
||||
pythonAssetBuilderHandler = None
|
||||
try:
|
||||
if (pythonAssetBuilderHandler == None):
|
||||
pythonAssetBuilderHandler = register_asset_builder()
|
||||
except:
|
||||
pythonAssetBuilderHandler = None
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0)
|
||||
|
||||
def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList):
|
||||
import azlmbr.scene
|
||||
import azlmbr.object
|
||||
import azlmbr.paths
|
||||
import json, os
|
||||
|
||||
jsonFilename = os.path.basename(scene.sourceFilename)
|
||||
jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks')
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(jsonFilename)
|
||||
outputPath = os.path.join(outputDirectory, basePath)
|
||||
if not os.path.exists(outputPath):
|
||||
os.makedirs(outputPath, False)
|
||||
|
||||
# write out a JSON file with the chunk file info
|
||||
with open(jsonFilename, "w") as jsonFile:
|
||||
jsonFile.write(scene.manifest.ExportToJson())
|
||||
|
||||
exportProduct = azlmbr.scene.ExportProduct()
|
||||
exportProduct.filename = jsonFilename
|
||||
exportProduct.sourceId = scene.sourceGuid
|
||||
exportProduct.assetType = blastChunksAssetType
|
||||
exportProduct.subId = 101
|
||||
|
||||
exportProductList = azlmbr.scene.ExportProductList()
|
||||
exportProductList.AddProduct(exportProduct)
|
||||
return exportProductList
|
||||
|
||||
def on_prepare_for_export(args):
|
||||
try:
|
||||
scene = args[0] # azlmbr.scene.Scene
|
||||
outputDirectory = args[1] # string
|
||||
platformIdentifier = args[2] # string
|
||||
productList = args[3] # azlmbr.scene.ExportProductList
|
||||
return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
|
||||
def get_mesh_node_names(sceneGraph):
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
meshDataList = []
|
||||
node = sceneGraph.get_root()
|
||||
children = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
# store any node that has mesh data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'):
|
||||
if sceneGraph.is_node_end_point(node) is False:
|
||||
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
nodePath = nodeName.get_path()
|
||||
if (len(nodeName.get_path())):
|
||||
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return meshDataList
|
||||
|
||||
def update_manifest(scene):
|
||||
import uuid, os
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
graph = sceneData.SceneGraph(scene.graph)
|
||||
meshNameList = get_mesh_node_names(graph)
|
||||
sceneManifest = sceneData.SceneManifest()
|
||||
sourceFilenameOnly = os.path.basename(scene.sourceFilename)
|
||||
sourceFilenameOnly = sourceFilenameOnly.replace('.','_')
|
||||
|
||||
for activeMeshIndex in range(len(meshNameList)):
|
||||
chunkName = meshNameList[activeMeshIndex]
|
||||
chunkPath = chunkName.get_path()
|
||||
meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name())
|
||||
meshGroup = sceneManifest.add_mesh_group(meshGroupName)
|
||||
meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}'
|
||||
sceneManifest.mesh_group_select_node(meshGroup, chunkPath)
|
||||
|
||||
return sceneManifest.export()
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except:
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
log_exception_traceback()
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -4,6 +4,13 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# LYN-652 to re-enable once the Blast gem tests are stable
|
||||
# import asset_builder_blast
|
||||
try:
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.asset.builder
|
||||
import blast_asset_builder
|
||||
except:
|
||||
# this script only runs in an asset processing environment
|
||||
# like the AssetProcessor or an AssetBuilder
|
||||
# plus the Blast gem needs to be enabled for the project
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user