Add asset picker support to spawn SC node and thread safety measures
This commit is contained in:
@@ -123,6 +123,7 @@ namespace AZ
|
||||
|
||||
const static AZ::Crc32 NameLabelOverride = AZ_CRC("NameLabelOverride", 0x9ff79cab);
|
||||
const static AZ::Crc32 AssetPickerTitle = AZ_CRC_CE("AssetPickerTitle");
|
||||
const static AZ::Crc32 HideProductFilesInAssetPicker = AZ_CRC_CE("HideProductFilesInAssetPicker");
|
||||
const static AZ::Crc32 ChildNameLabelOverride = AZ_CRC("ChildNameLabelOverride", 0x73dd2909);
|
||||
//! Container attribute that is used to override labels for its elements given the index of the element
|
||||
const static AZ::Crc32 IndexedChildNameLabelOverride = AZ_CRC("IndexedChildNameLabelOverride", 0x5f313ac2);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
@@ -88,4 +89,10 @@ namespace AzFramework
|
||||
{
|
||||
extensions.push_back(Spawnable::FileExtension);
|
||||
}
|
||||
|
||||
uint32_t SpawnableAssetHandler::BuildSubId(AZStd::string_view id)
|
||||
{
|
||||
AZ::Uuid subIdHash = AZ::Uuid::CreateData(id.data(), id.size());
|
||||
return azlossy_caster(subIdHash.GetHash());
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace AzFramework
|
||||
const char* GetGroup() const override;
|
||||
const char* GetBrowserIcon() const override;
|
||||
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
|
||||
static uint32_t BuildSubId(AZStd::string_view id);
|
||||
|
||||
protected:
|
||||
LoadResult LoadAssetData(
|
||||
|
||||
+2
-3
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
@@ -73,8 +73,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
|
||||
uint32_t ProcessedObjectStore::BuildSubId(AZStd::string_view id)
|
||||
{
|
||||
AZ::Uuid subIdHash = AZ::Uuid::CreateData(id.data(), id.size());
|
||||
return azlossy_caster(subIdHash.GetHash());
|
||||
return AzFramework::SpawnableAssetHandler::BuildSubId(id);
|
||||
}
|
||||
|
||||
const AZStd::string& ProcessedObjectStore::GetId() const
|
||||
|
||||
+45
-1
@@ -777,6 +777,23 @@ namespace AzToolsFramework
|
||||
selection.SetDefaultDirectory(defaultDirectory);
|
||||
}
|
||||
|
||||
if (m_hideProductFilesInAssetPicker)
|
||||
{
|
||||
FilterConstType displayFilter = selection.GetDisplayFilter();
|
||||
|
||||
EntryTypeFilter* productsFilter = new EntryTypeFilter();
|
||||
productsFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Product);
|
||||
|
||||
InverseFilter* noProductsFilter = new InverseFilter();
|
||||
noProductsFilter->SetFilter(FilterConstType(productsFilter));
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(FilterConstType(displayFilter));
|
||||
compFilter->AddFilter(FilterConstType(noProductsFilter));
|
||||
|
||||
selection.SetDisplayFilter(FilterConstType(compFilter));
|
||||
}
|
||||
|
||||
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget());
|
||||
if (selection.IsValid())
|
||||
{
|
||||
@@ -785,7 +802,16 @@ namespace AzToolsFramework
|
||||
AZ_Assert(product || folder, "Incorrect entry type selected. Expected product or folder.");
|
||||
if (product)
|
||||
{
|
||||
SetSelectedAssetID(product->GetAssetId());
|
||||
AZ::Data::AssetId selectedAssetId = product->GetAssetId();
|
||||
|
||||
// If we hid the product files a source asset was picked
|
||||
// Clear the sub id as a source could have N products with different sub ids
|
||||
if (m_hideProductFilesInAssetPicker)
|
||||
{
|
||||
selectedAssetId.m_subId = 0;
|
||||
}
|
||||
|
||||
SetSelectedAssetID(selectedAssetId);
|
||||
}
|
||||
else if (folder)
|
||||
{
|
||||
@@ -1172,6 +1198,16 @@ namespace AzToolsFramework
|
||||
return m_showProductAssetName;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetHideProductFilesInAssetPicker(bool hide)
|
||||
{
|
||||
m_hideProductFilesInAssetPicker = hide;
|
||||
}
|
||||
|
||||
bool PropertyAssetCtrl::GetHideProductFilesInAssetPicker() const
|
||||
{
|
||||
return m_hideProductFilesInAssetPicker;
|
||||
}
|
||||
|
||||
void PropertyAssetCtrl::SetShowThumbnail(bool enable)
|
||||
{
|
||||
m_showThumbnail = enable;
|
||||
@@ -1297,6 +1333,14 @@ namespace AzToolsFramework
|
||||
GUI->SetShowProductAssetName(showProductAssetName);
|
||||
}
|
||||
}
|
||||
else if(attrib == AZ::Edit::Attributes::HideProductFilesInAssetPicker)
|
||||
{
|
||||
bool hideProductFilesInAssetPicker = false;
|
||||
if (attrValue->Read<bool>(hideProductFilesInAssetPicker))
|
||||
{
|
||||
GUI->SetHideProductFilesInAssetPicker(hideProductFilesInAssetPicker);
|
||||
}
|
||||
}
|
||||
else if (attrib == AZ::Edit::Attributes::ClearNotify)
|
||||
{
|
||||
PropertyAssetCtrl::ClearCallbackType* func = azdynamic_cast<PropertyAssetCtrl::ClearCallbackType*>(attrValue->GetAttribute());
|
||||
|
||||
+7
@@ -158,6 +158,10 @@ namespace AzToolsFramework
|
||||
//! Assets can be either source or product assets generated from source assets. By default, source assets are shown in the property asset. You can override that with this flag.
|
||||
bool m_showProductAssetName = true;
|
||||
|
||||
//! Assets can be either source or product assets generated from source assets.
|
||||
//! By default the asset picker shows both on an AZ::Asset<> property. You can hide product assets with this flag.
|
||||
bool m_hideProductFilesInAssetPicker = false;
|
||||
|
||||
bool m_showThumbnail = false;
|
||||
bool m_showThumbnailDropDownButton = false;
|
||||
EditCallbackType* m_thumbnailCallback = nullptr;
|
||||
@@ -211,6 +215,9 @@ namespace AzToolsFramework
|
||||
void SetShowProductAssetName(bool enable);
|
||||
bool GetShowProductAssetName() const;
|
||||
|
||||
void SetHideProductFilesInAssetPicker(bool hide);
|
||||
bool GetHideProductFilesInAssetPicker() const;
|
||||
|
||||
void SetShowThumbnail(bool enable);
|
||||
bool GetShowThumbnail() const;
|
||||
void SetShowThumbnailDropDownButton(bool enable);
|
||||
|
||||
+13
@@ -7,6 +7,7 @@
|
||||
Base="ScriptCanvas::Nodeable"
|
||||
Icon="Icons/ScriptCanvas/Placeholder.png"
|
||||
Category="Spawning"
|
||||
Version="0"
|
||||
GeneratePropertyFriend="True"
|
||||
Namespace="ScriptCanvas"
|
||||
Description="Spawn">
|
||||
@@ -21,5 +22,17 @@
|
||||
<Parameter Name="SpawnedEntitiesList" Type="AZStd::vector<Data::EntityIDType>" Description="List of spawned entities sorted by hiearchy with the root being first"/>
|
||||
</Output>/>
|
||||
|
||||
<Property Name ="m_spawnableAsset" Type="AZ::Data::Asset<AzFramework::Spawnable>" Serialize="true">
|
||||
<PropertyData Name="Prefab Asset"
|
||||
Description="Prefab source asset to spawn."
|
||||
Serialize="true"
|
||||
UIHandler="AZ::Edit::UIHandlers::Default">
|
||||
<EditAttribute Key="AZ::Edit::Attributes::ShowProductAssetFileName" Value="false"/>
|
||||
<EditAttribute Key="AZ::Edit::Attributes::HideProductFilesInAssetPicker" Value="true"/>
|
||||
<EditAttribute Key="AZ::Edit::Attributes::AssetPickerTitle" Value=""a Prefab""/>
|
||||
<EditAttribute Key="AZ::Edit::Attributes::ChangeNotify" Value="&SpawnNodeable::OnSpawnAssetChanged"/>
|
||||
</PropertyData>
|
||||
</Property>
|
||||
|
||||
</Class>
|
||||
</ScriptCanvas>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <ScriptCanvas/Libraries/Spawning/SpawnNodeable.h>
|
||||
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
|
||||
|
||||
namespace ScriptCanvas
|
||||
{
|
||||
@@ -23,9 +24,6 @@ namespace ScriptCanvas
|
||||
{
|
||||
SpawnNodeable::SpawnNodeable()
|
||||
{
|
||||
AZ::Data::AssetId cubeAssetId("{90552CB9-2F29-5A2E-976C-61BF7ADACB81}", 272062881);
|
||||
m_spawnableAsset = AZ::Data::AssetManager::Instance().GetAsset<AzFramework::Spawnable>(cubeAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
AZ::Data::AssetManager::Instance().BlockUntilLoadComplete(m_spawnableAsset);
|
||||
}
|
||||
|
||||
SpawnNodeable::SpawnNodeable(const SpawnNodeable& rhs)
|
||||
@@ -35,35 +33,85 @@ namespace ScriptCanvas
|
||||
|
||||
void SpawnNodeable::OnInitializeExecutionState()
|
||||
{
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
m_spawnTicket.IsValid();
|
||||
m_spawnTicket = AzFramework::EntitySpawnTicket(m_spawnableAsset);
|
||||
}
|
||||
|
||||
void SpawnNodeable::OnDeactivate()
|
||||
{
|
||||
if (AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
m_spawnTicket = AzFramework::EntitySpawnTicket();
|
||||
}
|
||||
|
||||
//void SpawnNodeable::Translation(Data::Vector3Type translation)
|
||||
//{
|
||||
// m_translation = translation;
|
||||
//}
|
||||
void SpawnNodeable::OnTick([[maybe_unused]] float delta, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
|
||||
{
|
||||
AZStd::vector<Data::EntityIDType> swappedSpawnedEntityList;
|
||||
AZStd::vector<size_t> swappedSpawnBatchSizes;
|
||||
{
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_recursiveMutex);
|
||||
|
||||
//void SpawnNodeable::Rotation(Data::Vector3Type rotation)
|
||||
//{
|
||||
// m_rotation = rotation;
|
||||
//}
|
||||
swappedSpawnedEntityList.swap(m_spawnedEntityList);
|
||||
swappedSpawnBatchSizes.swap(m_spawnBatchSizes);
|
||||
}
|
||||
|
||||
//void SpawnNodeable::Scale(Data::Vector3Type scale)
|
||||
//{
|
||||
// m_scale = scale;
|
||||
//}
|
||||
AZ::EntityId* batchBegin = swappedSpawnedEntityList.data();
|
||||
for (size_t batchSize : swappedSpawnBatchSizes)
|
||||
{
|
||||
if (batchSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::EntityId> spawnedEntitiesBatch(
|
||||
batchBegin, batchBegin + batchSize);
|
||||
|
||||
CallOnSpawn(AZStd::move(spawnedEntitiesBatch));
|
||||
|
||||
batchBegin += batchSize;
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnNodeable::OnSpawnAssetChanged()
|
||||
{
|
||||
if (m_spawnableAsset.GetId().IsValid())
|
||||
{
|
||||
AZStd::string rootSpawnableFile;
|
||||
AzFramework::StringFunc::Path::GetFileName(m_spawnableAsset.GetHint().c_str(), rootSpawnableFile);
|
||||
|
||||
rootSpawnableFile += AzFramework::Spawnable::DotFileExtension;
|
||||
|
||||
AZ::u32 rootSubId = AzFramework::SpawnableAssetHandler::BuildSubId(AZStd::move(rootSpawnableFile));
|
||||
|
||||
if (m_spawnableAsset.GetId().m_subId != rootSubId)
|
||||
{
|
||||
AZ::Data::AssetId rootAssetId = m_spawnableAsset.GetId();
|
||||
rootAssetId.m_subId = rootSubId;
|
||||
|
||||
m_spawnableAsset = AZ::Data::AssetManager::Instance().
|
||||
FindOrCreateAsset<AzFramework::Spawnable>(rootAssetId, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnNodeable::RequestSpawn(Data::Vector3Type translation, Data::Vector3Type rotation, Data::NumberType scale)
|
||||
{
|
||||
if (!m_spawnableAsset.IsReady())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto preSpawnCB = [this, translation, rotation, scale]([[maybe_unused]] AzFramework::EntitySpawnTicket& ticket,
|
||||
AzFramework::SpawnableEntityContainerView view)
|
||||
{
|
||||
|
||||
AZ::Entity* rootEntity = *view.begin();
|
||||
|
||||
AzFramework::TransformComponent* entityTransform =
|
||||
@@ -81,15 +129,13 @@ namespace ScriptCanvas
|
||||
auto spawnCompleteCB = [this]([[maybe_unused]] AzFramework::EntitySpawnTicket& ticket,
|
||||
AzFramework::SpawnableConstEntityContainerView view)
|
||||
{
|
||||
AZStd::vector<Data::EntityIDType> spawnedEntities;
|
||||
spawnedEntities.resize(view.size());
|
||||
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_recursiveMutex);
|
||||
m_spawnedEntityList.reserve(m_spawnedEntityList.size() + view.size());
|
||||
for (const AZ::Entity* entity : view)
|
||||
{
|
||||
spawnedEntities.emplace_back(entity->GetId());
|
||||
m_spawnedEntityList.emplace_back(entity->GetId());
|
||||
}
|
||||
|
||||
CallOnSpawn(spawnedEntities);
|
||||
m_spawnBatchSizes.push_back(view.size());
|
||||
};
|
||||
|
||||
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_spawnTicket, preSpawnCB, spawnCompleteCB);
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
#include <Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.generated.h>
|
||||
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
|
||||
|
||||
#include <ScriptCanvas/CodeGen/NodeableCodegen.h>
|
||||
#include <ScriptCanvas/Core/Node.h>
|
||||
#include <ScriptCanvas/Core/Nodeable.h>
|
||||
@@ -26,21 +29,28 @@ namespace ScriptCanvas
|
||||
namespace Spawning
|
||||
{
|
||||
class SpawnNodeable
|
||||
: public ScriptCanvas::Nodeable
|
||||
: public ScriptCanvas::Nodeable,
|
||||
public AZ::TickBus::Handler
|
||||
{
|
||||
SCRIPTCANVAS_NODE(SpawnNodeable);
|
||||
public:
|
||||
SpawnNodeable();
|
||||
|
||||
SpawnNodeable(const SpawnNodeable& rhs);
|
||||
|
||||
void OnInitializeExecutionState() override;
|
||||
|
||||
void OnDeactivate() override;
|
||||
|
||||
//TickBus
|
||||
void OnTick(float delta, AZ::ScriptTimePoint timePoint) override;
|
||||
|
||||
void OnSpawnAssetChanged();
|
||||
|
||||
private:
|
||||
AZ::Data::Asset<AzFramework::Spawnable> m_spawnableAsset;
|
||||
AzFramework::EntitySpawnTicket m_spawnTicket;
|
||||
|
||||
AZStd::vector<Data::EntityIDType> m_spawnedEntityList;
|
||||
AZStd::vector<size_t> m_spawnBatchSizes;
|
||||
AZStd::recursive_mutex m_recursiveMutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user