void UChildActorComponent::DestroyChildActor() { // If we own an Actor, kill it now unless we don't have authority on it, for that we rely on the server // If the level that the child actor is being removed then don't destory the child actor so re-adding it doesn't // need to create a new actor if (ChildActor && ChildActor->HasAuthority() && !GetOwner()->GetLevel()->bIsBeingRemoved) { if (!GExitPurge) { // if still alive, destroy, otherwise just clear the pointer if (!ChildActor->IsPendingKillOrUnreachable()) { #if WITH_EDITOR if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } #else check(!CachedInstanceData); #endif // If we're already tearing down we won't be needing this if (!HasAnyFlags(RF_BeginDestroyed) && !IsUnreachable()) { CachedInstanceData = new FChildActorComponentInstanceData(this); } UWorld* World = ChildActor->GetWorld(); // World may be nullptr during shutdown if (World != nullptr) { UClass* ChildClass = ChildActor->GetClass(); // We would like to make certain that our name is not going to accidentally get taken from us while we're destroyed // so we increment ClassUnique beyond our index to be certain of it. This is ... a bit hacky. int32& ClassUnique = ChildActor->GetOutermost()->ClassUniqueNameIndexMap.FindOrAdd(ChildClass->GetFName()); ClassUnique = FMath::Max(ClassUnique, ChildActor->GetFName().GetNumber()); // If we are getting here due to garbage collection we can't rename, so we'll have to abandon this child actor name and pick up a new one if (!IsGarbageCollecting()) { const FString ObjectBaseName = FString::Printf(TEXT("DESTROYED_%s_CHILDACTOR"), *ChildClass->GetName()); const ERenameFlags RenameFlags = ((GetWorld()->IsGameWorld() || IsLoading()) ? REN_DoNotDirty | REN_ForceNoResetLoaders : REN_DoNotDirty); ChildActor->Rename(*MakeUniqueObjectName(ChildActor->GetOuter(), ChildClass, *ObjectBaseName).ToString(), nullptr, RenameFlags); } else { ChildActorName = NAME_None; if (CachedInstanceData) { CachedInstanceData->ChildActorName = NAME_None; } } World->DestroyActor(ChildActor); } } } ChildActor = nullptr; } }
FPropertyAccess::Result SPropertyEditorAsset::GetValue( FObjectOrAssetData& OutValue ) const { // Potentially accessing the value while garbage collecting or saving the package could trigger a crash. // so we fail to get the value when that is occuring. if ( GIsSavingPackage || IsGarbageCollecting() ) { return FPropertyAccess::Fail; } FPropertyAccess::Result Result = FPropertyAccess::Fail; if( PropertyEditor.IsValid() && PropertyEditor->GetPropertyHandle()->IsValidHandle() ) { UObject* Object = NULL; Result = PropertyEditor->GetPropertyHandle()->GetValue(Object); if (Object == NULL) { // Check to see if it's pointing to an unloaded object FString CurrentObjectPath; PropertyEditor->GetPropertyHandle()->GetValueAsFormattedString( CurrentObjectPath ); if (CurrentObjectPath.Len() > 0 && CurrentObjectPath != TEXT("None")) { if( !CachedAssetData.IsValid() || CachedAssetData.ObjectPath.ToString() != CurrentObjectPath ) { static FName AssetRegistryName("AssetRegistry"); FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>(AssetRegistryName); CachedAssetData = AssetRegistryModule.Get().GetAssetByObjectPath( *CurrentObjectPath ); } Result = FPropertyAccess::Success; OutValue = FObjectOrAssetData( CachedAssetData ); return Result; } } OutValue = FObjectOrAssetData( Object ); } else { UObject* Object = NULL; if (PropertyHandle.IsValid()) { Result = PropertyHandle->GetValue(Object); } if (Object != NULL) { OutValue = FObjectOrAssetData(Object); } else { const FString CurrentObjectPath = ObjectPath.Get(); Result = FPropertyAccess::Success; if (CurrentObjectPath != TEXT("None") && (!CachedAssetData.IsValid() || CachedAssetData.ObjectPath.ToString() != CurrentObjectPath)) { static FName AssetRegistryName("AssetRegistry"); FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>(AssetRegistryName); CachedAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*CurrentObjectPath); if (PropertyHandle.IsValid()) { // No property editor was specified so check if multiple property values are associated with the property handle TArray<FString> ObjectValues; PropertyHandle->GetPerObjectValues(ObjectValues); if (ObjectValues.Num() > 1) { for (int32 ObjectIndex = 1; ObjectIndex < ObjectValues.Num() && Result == FPropertyAccess::Success; ++ObjectIndex) { if (ObjectValues[ObjectIndex] != ObjectValues[0]) { Result = FPropertyAccess::MultipleValues; } } } } } else if (CurrentObjectPath == TEXT("None")) { CachedAssetData = FAssetData(); } OutValue = FObjectOrAssetData(CachedAssetData); } } return Result; }