// Copyright Epic Games, Inc. All Rights Reserved. #include "ComponentAssetBroker.h" #include "GameFramework/Actor.h" #include "Engine/Blueprint.h" #include "Components/StaticMeshComponent.h" #include "Engine/SkeletalMesh.h" #include "Components/SkeletalMeshComponent.h" #include "Particles/ParticleSystem.h" #include "Components/AudioComponent.h" #include "Particles/ParticleSystemComponent.h" #include "Engine/StaticMesh.h" #include "Sound/SoundBase.h" #include "Components/ChildActorComponent.h" ////////////////////////////////////////////////////////////////////////// // FStaticMeshComponentBroker class FStaticMeshComponentBroker : public IComponentAssetBroker { public: UClass* GetSupportedAssetClass() override { return UStaticMesh::StaticClass(); } virtual bool AssignAssetToComponent(UActorComponent* InComponent, UObject* InAsset) override { if (UStaticMeshComponent* StaticMeshComp = Cast(InComponent)) { UStaticMesh* StaticMesh = Cast(InAsset); if ((StaticMesh != NULL) || (InAsset == NULL)) { StaticMeshComp->SetStaticMesh(StaticMesh); return true; } } return false; } virtual UObject* GetAssetFromComponent(UActorComponent* InComponent) override { if (UStaticMeshComponent* StaticMeshComp = Cast(InComponent)) { return StaticMeshComp->GetStaticMesh(); } return NULL; } }; ////////////////////////////////////////////////////////////////////////// // FSkeletalMeshComponentBroker class FSkeletalMeshComponentBroker : public IComponentAssetBroker { public: UClass* GetSupportedAssetClass() override { return USkeletalMesh::StaticClass(); } virtual bool AssignAssetToComponent(UActorComponent* InComponent, UObject* InAsset) override { if (USkeletalMeshComponent* SkeletalComp = Cast(InComponent)) { USkeletalMesh* SkeletalMesh = Cast(InAsset); if ((SkeletalMesh != NULL) || (InAsset == NULL)) { SkeletalComp->SetSkeletalMesh(SkeletalMesh); return true; } } return false; } virtual UObject* GetAssetFromComponent(UActorComponent* InComponent) override { if (USkeletalMeshComponent* SkelMeshComp = Cast(InComponent)) { return SkelMeshComp->GetSkeletalMeshAsset(); } return NULL; } }; ////////////////////////////////////////////////////////////////////////// // FParticleSystemComponentBroker class FParticleSystemComponentBroker : public IComponentAssetBroker { public: UClass* GetSupportedAssetClass() override { return UParticleSystem::StaticClass(); } virtual bool AssignAssetToComponent(UActorComponent* InComponent, UObject* InAsset) override { if (UParticleSystemComponent* ParticleComp = Cast(InComponent)) { UParticleSystem* ParticleSystem = Cast(InAsset); if ((ParticleSystem != NULL) || (InAsset == NULL)) { ParticleComp->SetTemplate(ParticleSystem); return true; } } return false; } virtual UObject* GetAssetFromComponent(UActorComponent* InComponent) override { if (UParticleSystemComponent* ParticleComp = Cast(InComponent)) { return ParticleComp->Template; } return NULL; } }; ////////////////////////////////////////////////////////////////////////// // FChildActorComponentBroker class FChildActorComponentBroker : public IComponentAssetBroker { public: UClass* GetSupportedAssetClass() override { return UBlueprint::StaticClass(); } virtual bool AssignAssetToComponent(UActorComponent* InComponent, UObject* InAsset) override { if (UChildActorComponent* ChildActorComp = Cast(InComponent)) { UClass* Class = Cast(InAsset); if (Class == nullptr) { if (UBlueprint* BP = Cast(InAsset)) { Class = *(BP->GeneratedClass); } } if (Class && Class->IsChildOf()) { ChildActorComp->SetChildActorClass(Class); return true; } } return false; } virtual UObject* GetAssetFromComponent(UActorComponent* InComponent) override { if (UChildActorComponent* ChildActorComp = Cast(InComponent)) { return UBlueprint::GetBlueprintFromClass(*(ChildActorComp->GetChildActorClass())); } return NULL; } }; ////////////////////////////////////////////////////////////////////////// // FComponentAssetBrokerageage statics TMap FComponentAssetBrokerage::AssetToComponentClassMap; TMap< TSubclassOf, TSharedPtr > FComponentAssetBrokerage::ComponentToBrokerMap; TMap< UClass*, TArray< TSharedPtr > > FComponentAssetBrokerage::AssetToBrokerMap; bool FComponentAssetBrokerage::bInitializedBuiltinMap = false; bool FComponentAssetBrokerage::bShutSystemDown = false; ////////////////////////////////////////////////////////////////////////// // FComponentAssetBrokerageage /** Find set of components that support this asset */ FComponentClassList FComponentAssetBrokerage::GetComponentsForAsset(const UObject* InAsset) { InitializeMap(); FComponentClassList OutClasses; if (InAsset != NULL) { for (UClass* Class = InAsset->GetClass(); Class != UObject::StaticClass(); Class = Class->GetSuperClass()) { if (FComponentClassList* pTypesForClass = AssetToComponentClassMap.Find(Class)) { OutClasses.Append(*pTypesForClass); } } } return OutClasses; } TSubclassOf FComponentAssetBrokerage::GetPrimaryComponentForAsset(UClass* InAssetClass) { InitializeMap(); if (InAssetClass != NULL) { for (UClass* Class = InAssetClass; Class != UObject::StaticClass(); Class = Class->GetSuperClass()) { if (FComponentClassList* pTypesForClass = AssetToComponentClassMap.Find(Class)) { if (pTypesForClass->Num() > 0) { return (*pTypesForClass)[0]; } } } } return NULL; } /** Assign the assigned asset to the supplied component */ bool FComponentAssetBrokerage::AssignAssetToComponent(UActorComponent* InComponent, UObject* InAsset) { InitializeMap(); if (InComponent != NULL) { TSharedPtr Broker = FindBrokerByComponentType(InComponent->GetClass()); if (Broker.IsValid()) { return Broker->AssignAssetToComponent(InComponent, InAsset); } } return false; } UObject* FComponentAssetBrokerage::GetAssetFromComponent(UActorComponent* InComponent) { InitializeMap(); if (InComponent != NULL) { TSharedPtr Broker = FindBrokerByComponentType(InComponent->GetClass()); if (Broker.IsValid()) { return Broker->GetAssetFromComponent(InComponent); } } return NULL; } /** See if this component supports assets of any type */ bool FComponentAssetBrokerage::SupportsAssets(UActorComponent* InComponent) { InitializeMap(); if (InComponent == NULL) { return false; } else { TSharedPtr Broker = FindBrokerByComponentType(InComponent->GetClass()); return Broker.IsValid(); } } void FComponentAssetBrokerage::PRIVATE_ShutdownBrokerage() { check(!bShutSystemDown); bShutSystemDown = true; AssetToComponentClassMap.Empty(); AssetToBrokerMap.Empty(); ComponentToBrokerMap.Empty(); } void FComponentAssetBrokerage::InitializeMap() { check(!bShutSystemDown); if (!bInitializedBuiltinMap) { bInitializedBuiltinMap = true; RegisterBroker(MakeShareable(new FStaticMeshComponentBroker), UStaticMeshComponent::StaticClass(), true, true); RegisterBroker(MakeShareable(new FSkeletalMeshComponentBroker), USkeletalMeshComponent::StaticClass(), true, true); RegisterBroker(MakeShareable(new FParticleSystemComponentBroker), UParticleSystemComponent::StaticClass(), true, true); RegisterBroker(MakeShareable(new FChildActorComponentBroker), UChildActorComponent::StaticClass(), true, false); } } void FComponentAssetBrokerage::RegisterBroker(TSharedPtr Broker, TSubclassOf InComponentClass, bool bSetAsPrimary, bool bMapComponentForAssets) { InitializeMap(); check(Broker.IsValid()); UClass* AssetClass = Broker->GetSupportedAssetClass(); check((AssetClass != NULL) && (AssetClass != UObject::StaticClass())); checkf(!ComponentToBrokerMap.Contains(InComponentClass), TEXT("Component class already has a registered broker; you have to chain them yourself.")); ComponentToBrokerMap.Add(InComponentClass, Broker); if (bSetAsPrimary) { AssetToBrokerMap.FindOrAdd(AssetClass).Insert(Broker, 0); } else { AssetToBrokerMap.FindOrAdd(AssetClass).Add(Broker); } if (bMapComponentForAssets) { FComponentClassList& ValidComponentTypes = AssetToComponentClassMap.FindOrAdd(AssetClass); if (bSetAsPrimary) { ValidComponentTypes.Insert(InComponentClass, 0); } else { ValidComponentTypes.Add(InComponentClass); } } } void FComponentAssetBrokerage::UnregisterBroker(TSharedPtr Broker) { UClass* AssetClass = Broker->GetSupportedAssetClass(); if (TArray< TSharedPtr >* pBrokerList = AssetToBrokerMap.Find(AssetClass)) { pBrokerList->Remove(Broker); } if (FComponentClassList* pTypesForClass = AssetToComponentClassMap.Find(AssetClass)) { for (auto ComponentTypeIt = ComponentToBrokerMap.CreateIterator(); ComponentTypeIt; ++ComponentTypeIt) { TSubclassOf ComponentClass = ComponentTypeIt.Key(); if (ComponentTypeIt.Value() == Broker) { ComponentTypeIt.RemoveCurrent(); pTypesForClass->Remove(ComponentClass); } } if (pTypesForClass->Num() == 0) { AssetToComponentClassMap.Remove(AssetClass); } } } TSharedPtr FComponentAssetBrokerage::FindBrokerByComponentType(TSubclassOf InComponentClass) { InitializeMap(); return ComponentToBrokerMap.FindRef(InComponentClass); } TSharedPtr FComponentAssetBrokerage::FindBrokerByAssetType(UClass* InAssetClass) { InitializeMap(); TArray< TSharedPtr >* pBrokerList = AssetToBrokerMap.Find(InAssetClass); return ((pBrokerList != NULL) && (pBrokerList->Num() > 0)) ? (*pBrokerList)[0] : NULL; } TArray FComponentAssetBrokerage::GetSupportedAssets(UClass* InFilterComponentClass) { InitializeMap(); TArray< UClass* > SupportedAssets; for (auto ComponentTypeIt = ComponentToBrokerMap.CreateIterator(); ComponentTypeIt; ++ComponentTypeIt) { TSubclassOf Component = ComponentTypeIt.Key(); if(InFilterComponentClass == NULL || Component->IsChildOf(InFilterComponentClass)) { SupportedAssets.Add(ComponentTypeIt.Value()->GetSupportedAssetClass()); } } return SupportedAssets; }