void UActorRecording::StartRecordingNewComponents(ULevelSequence* CurrentSequence, float CurrentSequenceTime) { if (GetActorToRecord() != nullptr) { // find the new component(s) TInlineComponentArray<USceneComponent*> NewComponents; TArray<USceneComponent*> SceneComponents; GetSceneComponents(SceneComponents); for(USceneComponent* SceneComponent : SceneComponents) { if(ValidComponent(SceneComponent)) { TWeakObjectPtr<USceneComponent> WeakSceneComponent(SceneComponent); int32 FoundIndex = TrackedComponents.Find(WeakSceneComponent); if(FoundIndex == INDEX_NONE) { // new component! NewComponents.Add(SceneComponent); } } } ProcessNewComponentArray(NewComponents); UMovieScene* MovieScene = CurrentSequence->GetMovieScene(); check(MovieScene); FAnimationRecordingSettings ComponentAnimationSettings = AnimationSettings; ComponentAnimationSettings.bRemoveRootAnimation = false; ComponentAnimationSettings.bRecordInWorldSpace = false; const USequenceRecorderSettings* Settings = GetDefault<USequenceRecorderSettings>(); if (!bRecordToPossessable) { FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(Guid); check(Spawnable); AActor* ObjectTemplate = CastChecked<AActor>(Spawnable->GetObjectTemplate()); for (USceneComponent* SceneComponent : NewComponents) { // new component, so we need to add this to our BP if it didn't come from SCS FName NewName; if (SceneComponent->CreationMethod != EComponentCreationMethod::SimpleConstructionScript) { // Give this component a unique name within its parent NewName = *FString::Printf(TEXT("Dynamic%s"), *SceneComponent->GetFName().GetPlainNameString()); NewName.SetNumber(1); while (FindObjectFast<UObject>(ObjectTemplate, NewName)) { NewName.SetNumber(NewName.GetNumber() + 1); } USceneComponent* TemplateRoot = ObjectTemplate->GetRootComponent(); USceneComponent* AttachToComponent = nullptr; // look for a similar attach parent in the current structure USceneComponent* AttachParent = SceneComponent->GetAttachParent(); if(AttachParent != nullptr) { // First off, check if we're attached to a component that has already been duplicated into this object // If so, the name lookup will fail, so we use a direct reference if (TWeakObjectPtr<USceneComponent>* DuplicatedComponent = DuplicatedDynamicComponents.Find(AttachParent)) { AttachToComponent = DuplicatedComponent->Get(); } // If we don't have an attachment parent duplicated already, perform a name lookup if (!AttachToComponent) { FName AttachName = SceneComponent->GetAttachParent()->GetFName(); TInlineComponentArray<USceneComponent*> AllChildren; ObjectTemplate->GetComponents(AllChildren); for (USceneComponent* Child : AllChildren) { CA_SUPPRESS(28182); // Dereferencing NULL pointer. 'Child' contains the same NULL value as 'AttachToComponent' did. if (Child->GetFName() == AttachName) { AttachToComponent = Child; break; } } } } if (!AttachToComponent) { AttachToComponent = ObjectTemplate->GetRootComponent(); } USceneComponent* NewTemplateComponent = Cast<USceneComponent>(StaticDuplicateObject(SceneComponent, ObjectTemplate, NewName, RF_AllFlags & ~RF_Transient)); NewTemplateComponent->AttachToComponent(AttachToComponent, FAttachmentTransformRules::KeepRelativeTransform, SceneComponent->GetAttachSocketName()); ObjectTemplate->AddInstanceComponent(NewTemplateComponent); DuplicatedDynamicComponents.Add(SceneComponent, NewTemplateComponent); } else { NewName = SceneComponent->GetFName(); } StartRecordingComponentProperties(NewName, SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings); bNewComponentAddedWhileRecording = true; } SyncTrackedComponents(); } else { for (USceneComponent* SceneComponent : NewComponents) { // new component, start recording StartRecordingComponentProperties(SceneComponent->GetFName(), SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings); } SyncTrackedComponents(); } } }
bool UPawnAction_Repeat::PushSubAction() { if (ActionToRepeat == NULL) { Finish(EPawnActionResult::Failed); return false; } else if (RepeatsLeft == 0) { Finish(EPawnActionResult::Success); return true; } if (RepeatsLeft > 0) { --RepeatsLeft; } UPawnAction* ActionCopy = SubActionTriggeringPolicy == EPawnSubActionTriggeringPolicy::CopyBeforeTriggering ? Cast<UPawnAction>(StaticDuplicateObject(ActionToRepeat, this, NULL)) : ActionToRepeat; UE_VLOG(GetPawn(), LogPawnAction, Log, TEXT("%s> pushing repeted action %s %s, repeats left: %d") , *GetName(), SubActionTriggeringPolicy == EPawnSubActionTriggeringPolicy::CopyBeforeTriggering ? TEXT("copy") : TEXT("instance") , *GetNameSafe(ActionCopy), RepeatsLeft); check(ActionCopy); RecentActionCopy = ActionCopy; return PushChildAction(*ActionCopy); }
/** * Duplicates the asset */ void DuplicateAsset() { if (AssetPackage && CreatedAsset) { const FString NewObjectName = FString::Printf(TEXT("%s_Copy"), *AssetName); const FString NewPackageName = FString::Printf(TEXT("%s/%s"), *GetGamePath(), *NewObjectName); // Make sure the referenced object is deselected before duplicating it. GEditor->GetSelectedObjects()->Deselect(CreatedAsset); // Duplicate the asset DuplicatedPackage = CreatePackage(NULL, *NewPackageName); DuplicatedAsset = StaticDuplicateObject(CreatedAsset, DuplicatedPackage, *NewObjectName); if (DuplicatedAsset) { DuplicatedAsset->MarkPackageDirty(); // Notify the asset registry FAssetRegistryModule::AssetCreated(DuplicatedAsset); TestStats->NumDuplicated++; UE_LOG(LogEditorAssetAutomationTests, Display, TEXT("Duplicated asset %s to %s (%s)"), *AssetName, *NewObjectName, *Class->GetName()); } else { UE_LOG(LogEditorAssetAutomationTests, Error, TEXT("Failed to duplicate asset %s (%s)"), *AssetName, *Class->GetName()); } } }
/** * A helper that will take a blueprint and copy it into a new, temporary * package (intended for throwaway purposes). * * @param BlueprintToClone The blueprint you wish to duplicate. * @return A new temporary blueprint copy of what was passed in. */ static UBlueprint* DuplicateBlueprint(UBlueprint const* const BlueprintToClone) { UPackage* TempPackage = CreateTempPackage(BlueprintToClone->GetName()); FString TempBlueprintName = MakeUniqueObjectName(TempPackage, UBlueprint::StaticClass(), BlueprintToClone->GetFName()).ToString(); return Cast<UBlueprint>(StaticDuplicateObject(BlueprintToClone, TempPackage, *TempBlueprintName)); }
static void ReplaceStructWithTempDuplicate( UUserDefinedStruct* StructureToReinstance, TSet<UBlueprint*>& BlueprintsToRecompile, TArray<UUserDefinedStruct*>& ChangedStructs) { if (StructureToReinstance) { UUserDefinedStruct* DuplicatedStruct = NULL; { const FString ReinstancedName = FString::Printf(TEXT("STRUCT_REINST_%s"), *StructureToReinstance->GetName()); const FName UniqueName = MakeUniqueObjectName(GetTransientPackage(), UUserDefinedStruct::StaticClass(), FName(*ReinstancedName)); TGuardValue<bool> IsDuplicatingClassForReinstancing(GIsDuplicatingClassForReinstancing, true); DuplicatedStruct = (UUserDefinedStruct*)StaticDuplicateObject(StructureToReinstance, GetTransientPackage(), *UniqueName.ToString(), ~RF_Transactional); } DuplicatedStruct->Guid = StructureToReinstance->Guid; DuplicatedStruct->Bind(); DuplicatedStruct->StaticLink(true); DuplicatedStruct->PrimaryStruct = StructureToReinstance; DuplicatedStruct->Status = EUserDefinedStructureStatus::UDSS_Duplicate; DuplicatedStruct->SetFlags(RF_Transient); DuplicatedStruct->AddToRoot(); CastChecked<UUserDefinedStructEditorData>(DuplicatedStruct->EditorData)->RecreateDefaultInstance(); for (auto StructProperty : TObjectRange<UStructProperty>(RF_ClassDefaultObject | RF_PendingKill)) { if (StructProperty && (StructureToReinstance == StructProperty->Struct)) { if (auto OwnerClass = Cast<UBlueprintGeneratedClass>(StructProperty->GetOwnerClass())) { if (UBlueprint* FoundBlueprint = Cast<UBlueprint>(OwnerClass->ClassGeneratedBy)) { BlueprintsToRecompile.Add(FoundBlueprint); StructProperty->Struct = DuplicatedStruct; } } else if (auto OwnerStruct = Cast<UUserDefinedStruct>(StructProperty->GetOwnerStruct())) { check(OwnerStruct != DuplicatedStruct); const bool bValidStruct = (OwnerStruct->GetOutermost() != GetTransientPackage()) && !OwnerStruct->HasAnyFlags(RF_PendingKill) && (EUserDefinedStructureStatus::UDSS_Duplicate != OwnerStruct->Status.GetValue()); if (bValidStruct) { ChangedStructs.AddUnique(OwnerStruct); StructProperty->Struct = DuplicatedStruct; } } else { UE_LOG(LogK2Compiler, Error, TEXT("ReplaceStructWithTempDuplicate unknown owner")); } } } DuplicatedStruct->RemoveFromRoot(); } }
void UAnimCompress_BitwiseCompressOnly::DoReduction(UAnimSequence* AnimSeq, const TArray<FBoneData>& BoneData) { #if WITH_EDITORONLY_DATA // split the raw data into tracks TArray<FTranslationTrack> TranslationData; TArray<FRotationTrack> RotationData; TArray<FScaleTrack> ScaleData; SeparateRawDataIntoTracks( AnimSeq->RawAnimationData, AnimSeq->SequenceLength, TranslationData, RotationData, ScaleData ); // Remove Translation Keys from tracks marked bAnimRotationOnly FilterAnimRotationOnlyKeys(TranslationData, AnimSeq); // remove obviously redundant keys from the source data FilterTrivialKeys(TranslationData, RotationData, ScaleData, TRANSLATION_ZEROING_THRESHOLD, QUATERNION_ZEROING_THRESHOLD, SCALE_ZEROING_THRESHOLD); // bitwise compress the tracks into the anim sequence buffers BitwiseCompressAnimationTracks( AnimSeq, static_cast<AnimationCompressionFormat>(TranslationCompressionFormat), static_cast<AnimationCompressionFormat>(RotationCompressionFormat), static_cast<AnimationCompressionFormat>(ScaleCompressionFormat), TranslationData, RotationData, ScaleData); // record the proper runtime decompressor to use AnimSeq->KeyEncodingFormat = AKF_ConstantKeyLerp; AnimationFormat_SetInterfaceLinks(*AnimSeq); AnimSeq->CompressionScheme = static_cast<UAnimCompress*>( StaticDuplicateObject( this, AnimSeq, TEXT("None")) ); #endif // WITH_EDITORONLY_DATA }
void FAssetTypeActions_CameraAnim::OpenAssetEditor( const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor ) { if(InObjects.Num() > 0) { UCameraAnim* CameraAnim = Cast<UCameraAnim>(InObjects[0]); if (CameraAnim != NULL) { // construct a temporary matinee actor CreateMatineeActorForCameraAnim(CameraAnim); if (GEditor->ShouldOpenMatinee(PreviewMatineeActor.Get())) { // changed the actor type, but don't want to lose any properties from previous // so duplicate from old, but with new class check(CameraAnim->CameraInterpGroup); if (!CameraAnim->CameraInterpGroup->IsA(UInterpGroupCamera::StaticClass())) { CameraAnim->CameraInterpGroup = CastChecked<UInterpGroupCamera>(StaticDuplicateObject(CameraAnim->CameraInterpGroup, CameraAnim, TEXT("CameraAnimation"), RF_NoFlags, UInterpGroupCamera::StaticClass())); } UInterpGroupCamera* NewInterpGroup = CastChecked<UInterpGroupCamera>(CameraAnim->CameraInterpGroup); check(NewInterpGroup); if (PreviewMatineeActor.Get()->MatineeData) { PreviewMatineeActor.Get()->MatineeData->SetFlags(RF_Transient); PreviewMatineeActor.Get()->MatineeData->InterpLength = CameraAnim->AnimLength; if (NewInterpGroup) { PreviewMatineeActor.Get()->MatineeData->InterpGroups.Add(NewInterpGroup); } } // create a CameraActor and connect it to the Interp. will create this at the perspective viewport's location and rotation CreateCameraActorForCameraAnim(CameraAnim); // set up the group actor PreviewMatineeActor.Get()->InitGroupActorForGroup(NewInterpGroup, PreviewCamera.Get()); // Create preview pawn CreatePreviewPawnForCameraAnim(CameraAnim); // this will create the instances for everything PreviewMatineeActor.Get()->InitInterp(); // open matinee for this actor GEditor->OpenMatinee(PreviewMatineeActor.Get()); // install our delegate so we can clean up when finished OnMatineeEditorClosedDelegateHandle = FEditorDelegates::EditorModeExit.AddSP(this, &FAssetTypeActions_CameraAnim::OnMatineeEditorClosed); } else { GEditor->GetEditorWorldContext().World()->DestroyActor(PreviewMatineeActor.Get()); } } } }
/** * Called after duplication & serialization and before PostLoad. Used to make sure UModel's FPolys * get duplicated as well. */ void UModel::PostDuplicate(bool bDuplicateForPIE) { Super::PostDuplicate(bDuplicateForPIE); #if WITH_EDITOR if( Polys ) { Polys = CastChecked<UPolys>(StaticDuplicateObject( Polys, this, NULL )); } #endif // WITH_EDITOR }
bool UBehaviorTreeManager::LoadTree(UBehaviorTree& Asset, UBTCompositeNode*& Root, uint16& InstanceMemorySize) { SCOPE_CYCLE_COUNTER(STAT_AI_BehaviorTree_LoadTime); for (int32 TemplateIndex = 0; TemplateIndex < LoadedTemplates.Num(); TemplateIndex++) { FBehaviorTreeTemplateInfo& TemplateInfo = LoadedTemplates[TemplateIndex]; if (TemplateInfo.Asset == &Asset) { Root = TemplateInfo.Template; InstanceMemorySize = TemplateInfo.InstanceMemorySize; return true; } } if (Asset.RootNode) { FBehaviorTreeTemplateInfo TemplateInfo; TemplateInfo.Asset = &Asset; TemplateInfo.Template = Cast<UBTCompositeNode>(StaticDuplicateObject(Asset.RootNode, this, TEXT("None"))); TArray<FNodeInitializationData> InitList; uint16 ExecutionIndex = 0; InitializeNodeHelper(NULL, TemplateInfo.Template, 0, ExecutionIndex, InitList, Asset, this); #if USE_BEHAVIORTREE_DEBUGGER // fill in information about next nodes in execution index, before sorting memory offsets for (int32 Index = 0; Index < InitList.Num() - 1; Index++) { InitList[Index].Node->InitializeExecutionOrder(InitList[Index + 1].Node); } #endif // sort nodes by memory size, so they can be packed better // it still won't protect against structures, that are internally misaligned (-> uint8, uint32) // but since all Engine level nodes are good... InitList.Sort(FNodeInitializationData::FMemorySort()); uint16 MemoryOffset = 0; for (int32 Index = 0; Index < InitList.Num(); Index++) { InitList[Index].Node->InitializeNode(InitList[Index].ParentNode, InitList[Index].ExecutionIndex, InitList[Index].SpecialDataSize + MemoryOffset, InitList[Index].TreeDepth); MemoryOffset += InitList[Index].DataSize; } TemplateInfo.InstanceMemorySize = MemoryOffset; INC_DWORD_STAT(STAT_AI_BehaviorTree_NumTemplates); LoadedTemplates.Add(TemplateInfo); Root = TemplateInfo.Template; InstanceMemorySize = TemplateInfo.InstanceMemorySize; return true; } return false; }
UEnvQueryContext* UEnvQueryManager::PrepareLocalContext(TSubclassOf<UEnvQueryContext> ContextClass) { UEnvQueryContext* LocalContext = LocalContextMap.FindRef(ContextClass->GetFName()); if (LocalContext == NULL) { LocalContext = (UEnvQueryContext*)StaticDuplicateObject(ContextClass.GetDefaultObject(), this, TEXT("None")); LocalContexts.Add(LocalContext); LocalContextMap.Add(ContextClass->GetFName(), LocalContext); } return LocalContext; }
bool UCameraAnim::CreateFromInterpGroup(class UInterpGroup* SrcGroup, class AMatineeActor* InMatineeActor) { // assert we're controlling a camera actor #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) { UInterpGroupInst* GroupInst = InMatineeActor ? InMatineeActor->FindFirstGroupInst(SrcGroup) : NULL; if (GroupInst) { check( GroupInst->GetGroupActor()->IsA(ACameraActor::StaticClass()) ); } } #endif // copy length information AnimLength = (InMatineeActor && InMatineeActor->MatineeData) ? InMatineeActor->MatineeData->InterpLength : 0.f; UInterpGroup* OldGroup = CameraInterpGroup; if (CameraInterpGroup != SrcGroup) { // copy the source interp group for use in the CameraAnim // @fixme jf: fixed this potentially creating an object of UInterpGroup and raw casting it to InterpGroupCamera. No source data in UE4 to test though. CameraInterpGroup = Cast<UInterpGroupCamera>(StaticDuplicateObject(SrcGroup, this, NAME_None, RF_AllFlags, UInterpGroupCamera::StaticClass())); if (CameraInterpGroup) { // delete the old one, if it exists if (OldGroup) { OldGroup->MarkPendingKill(); } // success! return true; } else { // creation of new one failed somehow, restore the old one CameraInterpGroup = OldGroup; } } else { // no need to perform work above, but still a "success" case return true; } // failed creation return false; }
UActorComponent* AActor::CreateComponentFromTemplate(UActorComponent* Template, const FString & InName) { UActorComponent* NewActorComp = NULL; if(Template != NULL) { // Note we aren't copying the the RF_ArchetypeObject flag. Also note the result is non-transactional by default. NewActorComp = (UActorComponent*)StaticDuplicateObject(Template, this, *InName, RF_AllFlags & ~(RF_ArchetypeObject|RF_Transactional|RF_WasLoaded) ); //NewActorComp = ConstructObject<UActorComponent>(Template->GetClass(), this, *InName, RF_NoFlags, Template); NewActorComp->bCreatedByConstructionScript = true; // Need to do this so component gets saved - Components array is not serialized SerializedComponents.Add(NewActorComp); } return NewActorComp; }
void UAnimCompress_Automatic::DoReduction(UAnimSequence* AnimSeq, const TArray<FBoneData>& BoneData) { #if WITH_EDITORONLY_DATA FAnimationUtils::CompressAnimSequenceExplicit( AnimSeq, MaxEndEffectorError, false, // bOutput bRunCurrentDefaultCompressor, bAutoReplaceIfExistingErrorTooGreat, bRaiseMaxErrorToExisting, bTryFixedBitwiseCompression, bTryPerTrackBitwiseCompression, bTryLinearKeyRemovalCompression, bTryIntervalKeyRemoval); AnimSeq->CompressionScheme = static_cast<UAnimCompress*>( StaticDuplicateObject( AnimSeq->CompressionScheme, AnimSeq, TEXT("None")) ); #endif // WITH_EDITORONLY_DATA }
void UChildActorComponent::Serialize(FArchive& Ar) { Super::Serialize(Ar); if (Ar.HasAllPortFlags(PPF_DuplicateForPIE)) { // PIE duplication should just work normally Ar << ChildActorTemplate; } else if (Ar.HasAllPortFlags(PPF_Duplicate)) { if (GIsEditor && Ar.IsLoading() && !IsTemplate()) { // If we're not a template then we do not want the duplicate so serialize manually and destroy the template that was created for us Ar.Serialize(&ChildActorTemplate, sizeof(UObject*)); if (AActor* UnwantedDuplicate = static_cast<AActor*>(FindObjectWithOuter(this, AActor::StaticClass()))) { UnwantedDuplicate->MarkPendingKill(); } } else if (!GIsEditor && !Ar.IsLoading() && !GIsDuplicatingClassForReinstancing) { // Avoid the archiver in the duplicate writer case because we want to avoid the duplicate being created Ar.Serialize(&ChildActorTemplate, sizeof(UObject*)); } else { // When we're loading outside of the editor we won't have created the duplicate, so its fine to just use the normal path // When we're loading a template then we want the duplicate, so it is fine to use normal archiver // When we're saving in the editor we'll create the duplicate, but on loading decide whether to take it or not Ar << ChildActorTemplate; } } #if WITH_EDITOR // Since we sometimes serialize properties in instead of using duplication if we are a template // and are not pointing at a component we own we'll need to fix that if (ChildActorTemplate && ChildActorTemplate->GetOuter() != this && IsTemplate()) { const FString TemplateName = FString::Printf(TEXT("%s_%s_CAT"), *GetName(), *ChildActorClass->GetName()); ChildActorTemplate = CastChecked<AActor>(StaticDuplicateObject(ChildActorTemplate, this, *TemplateName)); } #endif }
UActorComponent* AActor::CreateComponentFromTemplate(UActorComponent* Template, const FString& InName) { UActorComponent* NewActorComp = NULL; if(Template != NULL) { // If there is a Component with this name already (almost certainly because it is an Instance component), we need to rename it out of the way if (!InName.IsEmpty()) { UObject* ConflictingObject = FindObjectFast<UObject>(this, *InName); if (ConflictingObject && ConflictingObject->IsA<UActorComponent>() && CastChecked<UActorComponent>(ConflictingObject)->CreationMethod == EComponentCreationMethod::Instance) { // Try and pick a good name FString ConflictingObjectName = ConflictingObject->GetName(); int32 CharIndex = ConflictingObjectName.Len()-1; while (FChar::IsDigit(ConflictingObjectName[CharIndex])) { --CharIndex; } int32 Counter = 0; if (CharIndex < ConflictingObjectName.Len()-1) { Counter = FCString::Atoi(*ConflictingObjectName.RightChop(CharIndex+1)); ConflictingObjectName = ConflictingObjectName.Left(CharIndex+1); } FString NewObjectName; do { NewObjectName = ConflictingObjectName + FString::FromInt(++Counter); } while (FindObjectFast<UObject>(this, *NewObjectName) != nullptr); ConflictingObject->Rename(*NewObjectName, this); } } // Note we aren't copying the the RF_ArchetypeObject flag. Also note the result is non-transactional by default. NewActorComp = (UActorComponent*)StaticDuplicateObject(Template, this, *InName, RF_AllFlags & ~(RF_ArchetypeObject|RF_Transactional|RF_WasLoaded|RF_Public|RF_InheritableComponentTemplate) ); NewActorComp->CreationMethod = EComponentCreationMethod::UserConstructionScript; // Need to do this so component gets saved - Components array is not serialized BlueprintCreatedComponents.Add(NewActorComp); } return NewActorComp; }
FReply FNiagaraEffectEditor::OnDuplicateEmitterClicked(TSharedPtr<FNiagaraSimulation> Emitter) { FNiagaraEditorModule& NiagaraEditorModule = FModuleManager::LoadModuleChecked<FNiagaraEditorModule>("NiagaraEditor"); if (UNiagaraEmitterProperties* ToDupe = Emitter->GetProperties().Get()) { UNiagaraEmitterProperties *Props = CastChecked<UNiagaraEmitterProperties>(StaticDuplicateObject(ToDupe,Effect,NULL)); Effect->AddEmitterProperties(Props); TSharedPtr<FNiagaraSimulation> NewEmitter = EffectInstance->AddEmitter(Props); Effect->CreateEffectRendererProps(NewEmitter); Viewport->SetPreviewEffect(EffectInstance); EmitterEditorWidget->UpdateList(); DevEmitterEditorWidget->UpdateList(); Effect->MarkPackageDirty(); } return FReply::Handled(); }
bool UPawnAction_Sequence::PushNextActionCopy() { if (CurrentActionIndex >= uint32(ActionSequence.Num())) { Finish(EPawnActionResult::Success); return true; } UPawnAction* ActionCopy = SubActionTriggeringPolicy == EPawnSubActionTriggeringPolicy::CopyBeforeTriggering ? Cast<UPawnAction>(StaticDuplicateObject(ActionSequence[CurrentActionIndex], this, NULL)) : ActionSequence[CurrentActionIndex]; UE_VLOG(GetPawn(), LogPawnAction, Log, TEXT("%s> pushing action %s") , *GetName(), *GetNameSafe(ActionCopy)); ++CurrentActionIndex; check(ActionCopy); RecentActionCopy = ActionCopy; return PushChildAction(*ActionCopy); }
void UBehaviorTreeGraph::UpdateDeprecatedNodes() { for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UBehaviorTreeGraphNode* Node = Cast<UBehaviorTreeGraphNode>(Nodes[Index]); if (Node) { // UBTTask_RunBehavior is now handled by dedicated graph node if (Node->NodeInstance && Node->NodeInstance->IsA(UBTTask_RunBehavior::StaticClass())) { UBehaviorTreeGraphNode* NewNode = Cast<UBehaviorTreeGraphNode>(StaticDuplicateObject(Node, this, TEXT(""), RF_AllFlags, UBehaviorTreeGraphNode_SubtreeTask::StaticClass())); check(NewNode); ReplaceNodeConnections(Node, NewNode); Nodes[Index] = NewNode; Node = NewNode; } if (Node->NodeInstance) { Node->ErrorMessage = FClassBrowseHelper::GetDeprecationMessage(Node->NodeInstance->GetClass()); } for (int32 i = 0; i < Node->Decorators.Num(); i++) { if (Node->Decorators[i] && Node->Decorators[i]->NodeInstance) { Node->Decorators[i]->ErrorMessage = FClassBrowseHelper::GetDeprecationMessage(Node->Decorators[i]->NodeInstance->GetClass()); } } for (int32 i = 0; i < Node->Services.Num(); i++) { if (Node->Services[i] && Node->Services[i]->NodeInstance) { Node->Services[i]->ErrorMessage = FClassBrowseHelper::GetDeprecationMessage(Node->Services[i]->NodeInstance->GetClass()); } } } } }
void FConfigPropertyHelperDetails::AddEditablePropertyForConfig(IDetailLayoutBuilder& DetailBuilder, const UPropertyConfigFileDisplayRow* ConfigFilePropertyRowObj) { AssociatedConfigFileAndObjectPairings.Add(ConfigFilePropertyRowObj->ConfigFileName, (UObject*)ConfigFilePropertyRowObj); // Add the properties to a property table so we can edit these. IDetailCategoryBuilder& TempCategory = DetailBuilder.EditCategory("TempCategory"); UObject* ConfigEntryObject = StaticDuplicateObject(ConfigEditorPropertyViewCDO, GetTransientPackage(), *(ConfigFilePropertyRowObj->ConfigFileName + TEXT("_cdoDupe"))); ConfigEntryObject->AddToRoot(); FString ExistingConfigEntryValue; static FString SectionName = OriginalProperty->GetOwnerClass()->GetPathName(); static FString PropertyName = ConfigEditorCopyOfEditProperty->GetName(); if (GConfig->GetString(*SectionName, *PropertyName, ExistingConfigEntryValue, ConfigFilePropertyRowObj->ConfigFileName)) { ConfigEditorCopyOfEditProperty->ImportText(*ExistingConfigEntryValue, ConfigEditorCopyOfEditProperty->ContainerPtrToValuePtr<uint8>(ConfigEntryObject), 0, nullptr); } // Cache a reference for future usage. ConfigFileAndPropertySourcePairings.Add(ConfigFilePropertyRowObj->ConfigFileName, (UObject*)ConfigEntryObject); // We need to add a property row for each config file entry. // This allows us to have an editable widget for each config file. TArray<UObject*> ConfigPropertyDisplayObjects; ConfigPropertyDisplayObjects.Add(ConfigEntryObject); if (IDetailPropertyRow* ExternalRow = TempCategory.AddExternalProperty(ConfigPropertyDisplayObjects, ConfigEditorCopyOfEditProperty->GetFName())) { TSharedPtr<SWidget> NameWidget; TSharedPtr<SWidget> ValueWidget; ExternalRow->GetDefaultWidgets(NameWidget, ValueWidget); // Register the Value widget and config file pairing with the config editor. // The config editor needs this to determine what a cell presenter shows. IConfigEditorModule& ConfigEditor = FModuleManager::Get().LoadModuleChecked<IConfigEditorModule>("ConfigEditor"); ConfigEditor.AddExternalPropertyValueWidgetAndConfigPairing(ConfigFilePropertyRowObj->ConfigFileName, ValueWidget); // now hide the property so it is not added to the property display view ExternalRow->Visibility(EVisibility::Hidden); } }
void UBTNode::InitializeInSubtree(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32& NextInstancedIndex, EBTMemoryInit::Type InitType) const { FBTInstancedNodeMemory* SpecialMemory = GetSpecialNodeMemory<FBTInstancedNodeMemory>(NodeMemory); if (SpecialMemory) { SpecialMemory->NodeIdx = INDEX_NONE; } if (bCreateNodeInstance) { // composite nodes can't be instanced! check(IsA(UBTCompositeNode::StaticClass()) == false); UBTNode* NodeInstance = OwnerComp.NodeInstances.IsValidIndex(NextInstancedIndex) ? OwnerComp.NodeInstances[NextInstancedIndex] : NULL; if (NodeInstance == NULL) { NodeInstance = (UBTNode*)StaticDuplicateObject(this, &OwnerComp); NodeInstance->InitializeNode(GetParentNode(), GetExecutionIndex(), GetMemoryOffset(), GetTreeDepth()); NodeInstance->bIsInstanced = true; OwnerComp.NodeInstances.Add(NodeInstance); } check(NodeInstance); check(SpecialMemory); SpecialMemory->NodeIdx = NextInstancedIndex; NodeInstance->SetOwner(OwnerComp.GetOwner()); NodeInstance->InitializeMemory(OwnerComp, NodeMemory, InitType); check(TreeAsset); NodeInstance->InitializeFromAsset(*TreeAsset); NodeInstance->OnInstanceCreated(OwnerComp); NextInstancedIndex++; } else { InitializeMemory(OwnerComp, NodeMemory, InitType); } }
void UAnimCompress_RemoveLinearKeys::DoReduction(UAnimSequence* AnimSeq, const TArray<FBoneData>& BoneData) { #if WITH_EDITORONLY_DATA // Only need to do the heavy lifting if it will have some impact // One of these will always be true for the base class, but derived classes may choose to turn both off (e.g., in PerTrackCompression) const bool bRunningProcessor = bRetarget || bActuallyFilterLinearKeys; if (GIsEditor && bRunningProcessor) { GWarn->BeginSlowTask( NSLOCTEXT("UAnimCompress_RemoveLinearKeys", "BeginReductionTaskMessage", "Compressing animation with a RemoveLinearKeys scheme."), false); } // If the processor is to be run, then additive animations need to be converted from relative to absolute const bool bNeedToConvertBackToAdditive = bRunningProcessor ? ConvertFromRelativeSpace(AnimSeq) : false; // Separate the raw data into tracks and remove trivial tracks (all the same value) TArray<FTranslationTrack> TranslationData; TArray<FRotationTrack> RotationData; TArray<FScaleTrack> ScaleData; SeparateRawDataIntoTracks(AnimSeq->RawAnimationData, AnimSeq->SequenceLength, TranslationData, RotationData, ScaleData); FilterBeforeMainKeyRemoval(AnimSeq, BoneData, TranslationData, RotationData, ScaleData); if (bRunningProcessor) { #if TIME_LINEAR_KEY_REMOVAL double TimeStart = FPlatformTime::Seconds(); #endif // compress this animation without any key-reduction to prime the codec CompressUsingUnderlyingCompressor( AnimSeq, BoneData, TranslationData, RotationData, ScaleData, false); // now remove the keys which can be approximated with linear interpolation ProcessAnimationTracks( AnimSeq, BoneData, TranslationData, RotationData, ScaleData); #if TIME_LINEAR_KEY_REMOVAL double ElapsedTime = FPlatformTime::Seconds() - TimeStart; UE_LOG(LogAnimationCompression, Log, TEXT("ProcessAnimationTracks time is (%f) seconds"),ElapsedTime); #endif // if previously additive, convert back to relative-space if( bNeedToConvertBackToAdditive ) { ConvertToRelativeSpace(AnimSeq, TranslationData, RotationData); } } // Remove Translation Keys from tracks marked bAnimRotationOnly FilterAnimRotationOnlyKeys(TranslationData, AnimSeq); // compress the final (possibly key-reduced) tracks into the anim sequence buffers CompressUsingUnderlyingCompressor( AnimSeq, BoneData, TranslationData, RotationData, ScaleData, true); if (GIsEditor && bRunningProcessor) { GWarn->EndSlowTask(); } AnimSeq->CompressionScheme = static_cast<UAnimCompress*>( StaticDuplicateObject( this, AnimSeq, TEXT("None")) ); #endif // WITH_EDITORONLY_DATA }
TSharedPtr<FEnvQueryInstance> UEnvQueryManager::CreateQueryInstance(const UEnvQuery* Template, EEnvQueryRunMode::Type RunMode) { if (Template == nullptr || Template->Options.Num() == 0) { UE_CLOG(Template != nullptr && Template->Options.Num() == 0, LogEQS, Warning, TEXT("Query [%s] doesn't have any valid options!"), *Template->GetName()); return nullptr; } // try to find entry in cache FEnvQueryInstance* InstanceTemplate = NULL; for (int32 InstanceIndex = 0; InstanceIndex < InstanceCache.Num(); InstanceIndex++) { if (InstanceCache[InstanceIndex].Template->GetFName() == Template->GetFName() && InstanceCache[InstanceIndex].Instance.Mode == RunMode) { InstanceTemplate = &InstanceCache[InstanceIndex].Instance; break; } } // and create one if can't be found if (InstanceTemplate == NULL) { SCOPE_CYCLE_COUNTER(STAT_AI_EQS_LoadTime); // duplicate template in manager's world for BP based nodes UEnvQuery* LocalTemplate = (UEnvQuery*)StaticDuplicateObject(Template, this, *Template->GetName()); { // memory stat tracking: temporary variable will exist only inside this section FEnvQueryInstanceCache NewCacheEntry; NewCacheEntry.Template = LocalTemplate; NewCacheEntry.Instance.QueryName = LocalTemplate->GetName(); NewCacheEntry.Instance.Mode = RunMode; const int32 Idx = InstanceCache.Add(NewCacheEntry); InstanceTemplate = &InstanceCache[Idx].Instance; } // NOTE: We must iterate over this from 0->Num because we are copying the options from the template into the // instance, and order matters! Since we also may need to remove invalid or null options, we must decrement // the iteration pointer when doing so to avoid problems. for (int32 OptionIndex = 0; OptionIndex < LocalTemplate->Options.Num(); ++OptionIndex) { UEnvQueryOption* MyOption = LocalTemplate->Options[OptionIndex]; if (MyOption == nullptr || MyOption->Generator == nullptr || MyOption->Generator->ItemType == nullptr) { UE_LOG(LogEQS, Error, TEXT("Trying to spawn a query with broken Template (generator:%s itemType:%s): %s, option %d"), MyOption ? (MyOption->Generator ? TEXT("ok") : TEXT("MISSING")) : TEXT("N/A"), (MyOption && MyOption->Generator) ? (MyOption->Generator->ItemType ? TEXT("ok") : TEXT("MISSING")) : TEXT("N/A"), *GetNameSafe(LocalTemplate), OptionIndex); LocalTemplate->Options.RemoveAt(OptionIndex, 1, false); --OptionIndex; // See note at top of for loop. We cannot iterate backwards here. continue; } UEnvQueryOption* LocalOption = (UEnvQueryOption*)StaticDuplicateObject(MyOption, this, TEXT("None")); UEnvQueryGenerator* LocalGenerator = (UEnvQueryGenerator*)StaticDuplicateObject(MyOption->Generator, this, TEXT("None")); LocalTemplate->Options[OptionIndex] = LocalOption; LocalOption->Generator = LocalGenerator; EEnvTestCost::Type HighestCost(EEnvTestCost::Low); TArray<UEnvQueryTest*> SortedTests = MyOption->Tests; TSubclassOf<UEnvQueryItemType> GeneratedType = MyOption->Generator->ItemType; for (int32 TestIndex = SortedTests.Num() - 1; TestIndex >= 0; TestIndex--) { UEnvQueryTest* TestOb = SortedTests[TestIndex]; if (TestOb == NULL || !TestOb->IsSupportedItem(GeneratedType)) { UE_LOG(LogEQS, Warning, TEXT("Query [%s] can't use test [%s] in option %d [%s], removing it"), *GetNameSafe(LocalTemplate), *GetNameSafe(TestOb), OptionIndex, *MyOption->Generator->OptionName); SortedTests.RemoveAt(TestIndex, 1, false); } else if (HighestCost < TestOb->Cost) { HighestCost = TestOb->Cost; } } if (SortedTests.Num() == 0) { UE_LOG(LogEQS, Warning, TEXT("Query [%s] doesn't have any tests in option %d [%s]"), *GetNameSafe(LocalTemplate), OptionIndex, *MyOption->Generator->OptionName); LocalTemplate->Options.RemoveAt(OptionIndex, 1, false); --OptionIndex; // See note at top of for loop. We cannot iterate backwards here. continue; } LocalOption->Tests.Reset(SortedTests.Num()); for (int32 TestIdx = 0; TestIdx < SortedTests.Num(); TestIdx++) { UEnvQueryTest* LocalTest = (UEnvQueryTest*)StaticDuplicateObject(SortedTests[TestIdx], this, TEXT("None")); LocalOption->Tests.Add(LocalTest); } // use locally referenced duplicates SortedTests = LocalOption->Tests; if (SortedTests.Num() && LocalGenerator->bAutoSortTests) { switch (RunMode) { case EEnvQueryRunMode::SingleResult: SortedTests.Sort(EnvQueryTestSort::FSingleResult(HighestCost)); break; case EEnvQueryRunMode::RandomBest5Pct: case EEnvQueryRunMode::RandomBest25Pct: case EEnvQueryRunMode::AllMatching: SortedTests.Sort(EnvQueryTestSort::FAllMatching()); break; default: { UEnum* RunModeEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EEnvQueryRunMode")); UE_LOG(LogEQS, Warning, TEXT("Query [%s] can't be sorted for RunMode: %d [%s]"), *GetNameSafe(LocalTemplate), (int32)RunMode, RunModeEnum ? *RunModeEnum->GetEnumName(RunMode) : TEXT("??")); } } } CreateOptionInstance(LocalOption, SortedTests, *InstanceTemplate); } } if (InstanceTemplate->Options.Num() == 0) { return nullptr; } // create new instance TSharedPtr<FEnvQueryInstance> NewInstance(new FEnvQueryInstance(*InstanceTemplate)); return NewInstance; }
FBlueprintCompileReinstancer::FBlueprintCompileReinstancer(UClass* InClassToReinstance, bool bIsBytecodeOnly, bool bSkipGC) : ClassToReinstance(InClassToReinstance) , DuplicatedClass(NULL) , OriginalCDO(NULL) , bHasReinstanced(false) , bSkipGarbageCollection(bSkipGC) , ClassToReinstanceDefaultValuesCRC(0) { if( InClassToReinstance != NULL ) { bIsReinstancingSkeleton = FKismetEditorUtilities::IsClassABlueprintSkeleton(ClassToReinstance); SaveClassFieldMapping(InClassToReinstance); // Remember the initial CDO for the class being resinstanced OriginalCDO = ClassToReinstance->GetDefaultObject(); // Duplicate the class we're reinstancing into the transient package. We'll re-class all objects we find to point to this new class GIsDuplicatingClassForReinstancing = true; ClassToReinstance->ClassFlags |= CLASS_NewerVersionExists; const FName RenistanceName = MakeUniqueObjectName(GetTransientPackage(), ClassToReinstance->GetClass(), *FString::Printf(TEXT("REINST_%s"), *ClassToReinstance->GetName())); DuplicatedClass = (UClass*)StaticDuplicateObject(ClassToReinstance, GetTransientPackage(), *RenistanceName.ToString(), ~RF_Transactional); ClassToReinstance->ClassFlags &= ~CLASS_NewerVersionExists; GIsDuplicatingClassForReinstancing = false; auto BPGDuplicatedClass = Cast<UBlueprintGeneratedClass>(DuplicatedClass); auto DuplicatedClassUberGraphFunction = BPGDuplicatedClass ? BPGDuplicatedClass->UberGraphFunction : nullptr; if (DuplicatedClassUberGraphFunction) { DuplicatedClassUberGraphFunction->Bind(); DuplicatedClassUberGraphFunction->StaticLink(true); } // Bind and link the duplicate class, so that it has the proper duplicate property offsets DuplicatedClass->Bind(); DuplicatedClass->StaticLink(true); // Copy over the ComponentNametoDefaultObjectMap, which tells CopyPropertiesForUnrelatedObjects which components are instanced and which aren't GIsDuplicatingClassForReinstancing = true; UObject* OldCDO = ClassToReinstance->GetDefaultObject(); DuplicatedClass->ClassDefaultObject = (UObject*)StaticDuplicateObject(OldCDO, GetTransientPackage(), *DuplicatedClass->GetDefaultObjectName().ToString()); GIsDuplicatingClassForReinstancing = false; DuplicatedClass->ClassDefaultObject->SetFlags(RF_ClassDefaultObject); DuplicatedClass->ClassDefaultObject->SetClass(DuplicatedClass); OldCDO->SetClass(DuplicatedClass); ObjectsThatShouldUseOldStuff.Add(DuplicatedClass); //CDO of REINST_ class can be used as archetype if( !bIsBytecodeOnly ) { TArray<UObject*> ObjectsToChange; const bool bIncludeDerivedClasses = false; GetObjectsOfClass(ClassToReinstance, ObjectsToChange, bIncludeDerivedClasses); for (auto ObjIt = ObjectsToChange.CreateConstIterator(); ObjIt; ++ObjIt) { (*ObjIt)->SetClass(DuplicatedClass); } TArray<UClass*> ChildrenOfClass; GetDerivedClasses(ClassToReinstance, ChildrenOfClass); for ( auto ClassIt = ChildrenOfClass.CreateConstIterator(); ClassIt; ++ClassIt ) { UClass* ChildClass = *ClassIt; UBlueprint* ChildBP = Cast<UBlueprint>(ChildClass->ClassGeneratedBy); if (ChildBP) { const bool bClassIsDirectlyGeneratedByTheBlueprint = (ChildBP->GeneratedClass == ChildClass) || (ChildBP->SkeletonGeneratedClass == ChildClass); if (ChildBP->HasAnyFlags(RF_BeingRegenerated) || !bClassIsDirectlyGeneratedByTheBlueprint) { if (ChildClass->GetSuperClass() == ClassToReinstance) { ReparentChild(ChildClass); } //TODO: some stronger condition would be nice if (!bClassIsDirectlyGeneratedByTheBlueprint) { ObjectsThatShouldUseOldStuff.Add(ChildClass); } } // If this is a direct child, change the parent and relink so the property chain is valid for reinstancing else if( !ChildBP->HasAnyFlags(RF_NeedLoad) ) { if( ChildClass->GetSuperClass() == ClassToReinstance ) { ReparentChild(ChildBP); } Children.AddUnique(ChildBP); } else { // If this is a child that caused the load of their parent, relink to the REINST class so that we can still serialize in the CDO, but do not add to later processing ReparentChild(ChildClass); } } } } // Pull the blueprint that generated this reinstance target, and gather the blueprints that are dependent on it UBlueprint* GeneratingBP = Cast<UBlueprint>(ClassToReinstance->ClassGeneratedBy); check(GeneratingBP || GIsAutomationTesting); if(GeneratingBP) { ClassToReinstanceDefaultValuesCRC = GeneratingBP->CrcPreviousCompiledCDO; FBlueprintEditorUtils::GetDependentBlueprints(GeneratingBP, Dependencies); } } }
EReimportResult::Type UReimportFbxSceneFactory::ReimportStaticMesh(void* VoidFbxImporter, TSharedPtr<FFbxMeshInfo> MeshInfo) { UnFbx::FFbxImporter* FbxImporter = (UnFbx::FFbxImporter*)VoidFbxImporter; //Find the UObject associate with this MeshInfo UPackage* PkgExist = LoadPackage(nullptr, *(MeshInfo->GetImportPath()), LOAD_Verify | LOAD_NoWarn); if (PkgExist != nullptr) { PkgExist->FullyLoad(); } FString AssetName = MeshInfo->GetFullImportName(); UStaticMesh* Mesh = FindObjectSafe<UStaticMesh>(ANY_PACKAGE, *AssetName); if (Mesh == nullptr) { //We reimport only static mesh here FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(FText::FromString("Reimport Mesh {0} fail, the original staicmesh in the content browser cannot be load."), FText::FromString(MeshInfo->GetImportPath()))), FName(TEXT("Reimport Fbx Scene"))); return EReimportResult::Failed; } //Copy default options to StaticMeshImportData SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh); SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions); UnFbx::FBXImportOptions* OverrideImportSettings = GetOptionsFromName(MeshInfo->OptionName); if (OverrideImportSettings != nullptr) { SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(OverrideImportSettings, GlobalImportSettings); SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(OverrideImportSettings, SceneImportOptionsStaticMesh); } else { SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(GlobalImportSettingsReference, GlobalImportSettings); SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh); } SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions); FbxImporter->ApplyTransformSettingsToFbxNode(FbxImporter->Scene->GetRootNode(), StaticMeshImportData); const TArray<UAssetUserData*>* UserData = Mesh->GetAssetUserDataArray(); TArray<UAssetUserData*> UserDataCopy; if (UserData) { for (int32 Idx = 0; Idx < UserData->Num(); Idx++) { UserDataCopy.Add((UAssetUserData*)StaticDuplicateObject((*UserData)[Idx], GetTransientPackage())); } } // preserve settings in navcollision subobject UNavCollision* NavCollision = Mesh->NavCollision ? (UNavCollision*)StaticDuplicateObject(Mesh->NavCollision, GetTransientPackage()) : nullptr; // preserve extended bound settings const FVector PositiveBoundsExtension = Mesh->PositiveBoundsExtension; const FVector NegativeBoundsExtension = Mesh->NegativeBoundsExtension; Mesh = FbxImporter->ReimportSceneStaticMesh(MeshInfo->UniqueId, Mesh, StaticMeshImportData); if (Mesh != nullptr) { //Put back the new mesh data since the reimport is putting back the original import data SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions); Mesh->AssetImportData = StaticMeshImportData; // Copy user data to newly created mesh for (int32 Idx = 0; Idx < UserDataCopy.Num(); Idx++) { UserDataCopy[Idx]->Rename(nullptr, Mesh, REN_DontCreateRedirectors | REN_DoNotDirty); Mesh->AddAssetUserData(UserDataCopy[Idx]); } if (NavCollision) { Mesh->NavCollision = NavCollision; NavCollision->Rename(nullptr, Mesh, REN_DontCreateRedirectors | REN_DoNotDirty); } // Restore bounds extension settings Mesh->PositiveBoundsExtension = PositiveBoundsExtension; Mesh->NegativeBoundsExtension = NegativeBoundsExtension; Mesh->AssetImportData->Update(FbxImportFileName); // Try to find the outer package so we can dirty it up if (Mesh->GetOutermost()) { Mesh->GetOutermost()->MarkPackageDirty(); } else { Mesh->MarkPackageDirty(); } AllNewAssets.Add(MeshInfo, Mesh); AssetToSyncContentBrowser.Add(Mesh); } else { return EReimportResult::Failed; } return EReimportResult::Succeeded; }
UPaperTileMap* UPaperTileMap::CloneTileMap(UObject* OuterForClone) { return CastChecked<UPaperTileMap>(StaticDuplicateObject(this, OuterForClone, nullptr)); }
static void InitializeNodeHelper(UBTCompositeNode* ParentNode, UBTNode* NodeOb, uint8 TreeDepth, uint16& ExecutionIndex, TArray<FNodeInitializationData>& InitList, UBehaviorTree& TreeAsset, UObject* NodeOuter) { // special case: subtrees UBTTask_RunBehavior* SubtreeTask = Cast<UBTTask_RunBehavior>(NodeOb); if (SubtreeTask) { ExecutionIndex += SubtreeTask->GetInjectedNodesCount(); } InitList.Add(FNodeInitializationData(NodeOb, ParentNode, ExecutionIndex, TreeDepth, NodeOb->GetInstanceMemorySize(), NodeOb->GetSpecialMemorySize())); NodeOb->InitializeFromAsset(TreeAsset); ExecutionIndex++; UBTCompositeNode* CompositeOb = Cast<UBTCompositeNode>(NodeOb); if (CompositeOb) { for (int32 ServiceIndex = 0; ServiceIndex < CompositeOb->Services.Num(); ServiceIndex++) { if (CompositeOb->Services[ServiceIndex] == NULL) { UE_LOG(LogBehaviorTree, Warning, TEXT("%s has missing service node! (parent: %s)"), *TreeAsset.GetName(), *UBehaviorTreeTypes::DescribeNodeHelper(CompositeOb)); CompositeOb->Services.RemoveAt(ServiceIndex, 1, false); ServiceIndex--; continue; } UBTService* Service = Cast<UBTService>(StaticDuplicateObject(CompositeOb->Services[ServiceIndex], NodeOuter, TEXT("None")));; CompositeOb->Services[ServiceIndex] = Service; InitList.Add(FNodeInitializationData(Service, CompositeOb, ExecutionIndex, TreeDepth, Service->GetInstanceMemorySize(), Service->GetSpecialMemorySize())); Service->InitializeFromAsset(TreeAsset); ExecutionIndex++; } for (int32 ChildIndex = 0; ChildIndex < CompositeOb->Children.Num(); ChildIndex++) { FBTCompositeChild& ChildInfo = CompositeOb->Children[ChildIndex]; for (int32 DecoratorIndex = 0; DecoratorIndex < ChildInfo.Decorators.Num(); DecoratorIndex++) { if (ChildInfo.Decorators[DecoratorIndex] == NULL) { UE_LOG(LogBehaviorTree, Warning, TEXT("%s has missing decorator node! (parent: %s, branch: %d)"), *TreeAsset.GetName(), *UBehaviorTreeTypes::DescribeNodeHelper(CompositeOb), ChildIndex); ChildInfo.Decorators.RemoveAt(DecoratorIndex, 1, false); DecoratorIndex--; continue; } UBTDecorator* Decorator = Cast<UBTDecorator>(StaticDuplicateObject(ChildInfo.Decorators[DecoratorIndex], NodeOuter, TEXT("None"))); ChildInfo.Decorators[DecoratorIndex] = Decorator; InitList.Add(FNodeInitializationData(Decorator, CompositeOb, ExecutionIndex, TreeDepth, Decorator->GetInstanceMemorySize(), Decorator->GetSpecialMemorySize())); Decorator->InitializeFromAsset(TreeAsset); Decorator->InitializeDecorator(ChildIndex); ExecutionIndex++; } UBTNode* ChildNode = NULL; if (ChildInfo.ChildComposite) { ChildInfo.ChildComposite = Cast<UBTCompositeNode>(StaticDuplicateObject(ChildInfo.ChildComposite, NodeOuter, TEXT("None"))); ChildNode = ChildInfo.ChildComposite; } else if (ChildInfo.ChildTask) { ChildInfo.ChildTask = Cast<UBTTaskNode>(StaticDuplicateObject(ChildInfo.ChildTask, NodeOuter, TEXT("None"))); ChildNode = ChildInfo.ChildTask; } if (ChildNode) { InitializeNodeHelper(CompositeOb, ChildNode, TreeDepth + 1, ExecutionIndex, InitList, TreeAsset, NodeOuter); } } CompositeOb->InitializeComposite(ExecutionIndex - 1); } }
bool UBehaviorTreeGraphNode_SubtreeTask::UpdateInjectedNodes() { bool bUpdated = false; // check if cached data needs to be updated UBTTask_RunBehavior* MyNode = Cast<UBTTask_RunBehavior>(NodeInstance); if (MyNode == NULL) { return bUpdated; } UBehaviorTreeGraph* MyGraph = MyNode->GetSubtreeAsset() ? Cast<UBehaviorTreeGraph>(MyNode->GetSubtreeAsset()->BTGraph) : NULL; int32 MyVersion = MyGraph ? MyGraph->GraphVersion : 0; FString MyPath = MyNode->GetSubtreeAsset() ? MyNode->GetSubtreeAsset()->GetName() : FString(); if (MyPath == SubtreePath && MyVersion == SubtreeVersion) { return bUpdated; } SubtreePath = MyPath; SubtreeVersion = MyVersion; bUpdated = true; // remove existing injected nodes for (int32 Index = Decorators.Num() - 1; Index >= 0; Index--) { if (Decorators[Index] && Decorators[Index]->bInjectedNode) { Decorators.RemoveAt(Index, 1, false); } } // find root graph node of subtree UBehaviorTreeGraphNode* SubRoot = NULL; if (MyGraph && MyNode->GetSubtreeAsset()->RootDecorators.Num()) { for (int32 Index = 0; Index < MyGraph->Nodes.Num(); Index++) { UBehaviorTreeGraphNode_Root* BTNode = Cast<UBehaviorTreeGraphNode_Root>(MyGraph->Nodes[Index]); if (BTNode && BTNode->Pins.IsValidIndex(0) && BTNode->Pins[0]->LinkedTo.IsValidIndex(0)) { SubRoot = Cast<UBehaviorTreeGraphNode>(BTNode->Pins[0]->LinkedTo[0]->GetOwningNode()); break; } } } // add root level subnodes as injected nodes if (SubRoot) { UBehaviorTree* BTAsset = Cast<UBehaviorTree>(GetBehaviorTreeGraph()->GetOuter()); if(BTAsset) { for (int32 Index = 0; Index < SubRoot->Decorators.Num(); Index++) { UBehaviorTreeGraphNode* SubNode = SubRoot->Decorators[Index]; if (SubNode) { SubNode->PrepareForCopying(); UBehaviorTreeGraphNode* InjectedNode = Cast<UBehaviorTreeGraphNode>(StaticDuplicateObject(SubNode, GetOuter(), TEXT(""))); SubNode->PostCopyNode(); InjectedNode->PostCopyNode(); InjectedNode->ParentNode = this; InjectedNode->bInjectedNode = true; UBTDecorator* InjectedInstance = Cast<UBTDecorator>(InjectedNode->NodeInstance); if (InjectedInstance) { InjectedInstance->InitializeFromAsset(*BTAsset); } UBehaviorTreeGraphNode_CompositeDecorator* CompNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(InjectedNode); if (CompNode) { UEdGraph* SubGraph = CompNode->GetBoundGraph(); if (SubGraph) { SubGraph->bEditable = false; for (int32 SubIndex = 0; SubIndex < SubGraph->Nodes.Num(); SubIndex++) { UBehaviorTreeDecoratorGraphNode_Decorator* InjectedDecorator = Cast<UBehaviorTreeDecoratorGraphNode_Decorator>(SubGraph->Nodes[SubIndex]); if (InjectedDecorator) { InjectedInstance = Cast<UBTDecorator>(InjectedDecorator->NodeInstance); if (InjectedInstance) { InjectedInstance->InitializeFromAsset(*BTAsset); } } } } } Decorators.Add(InjectedNode); } } } } UEdGraph* ParentGraph = GetGraph(); if (ParentGraph && bUpdated) { ParentGraph->NotifyGraphChanged(); } return bUpdated; }
void USimpleConstructionScript::PostLoad() { Super::PostLoad(); #if WITH_EDITOR // Get the Blueprint that owns the SCS UBlueprint* Blueprint = GetBlueprint(); if (!Blueprint) { // sometimes the PostLoad can be called, after the object was trashed, we dont want this UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::PostLoad() '%s' cannot find its owner blueprint"), *GetPathName()); return; } for (USCS_Node* Node : GetAllNodes()) { // Fix up any uninitialized category names if(Node->CategoryName.IsEmpty()) { Node->CategoryName = NSLOCTEXT("SCS", "Default", "Default"); } // Fix up components that may have switched from scene to non-scene type and vice-versa if(Node->ComponentTemplate != nullptr) { // Fix up any component template objects whose name doesn't match the current variable name; this ensures that there is always one unique template per node. FString VariableName = Node->GetVariableName().ToString(); FString ComponentTemplateName = Node->ComponentTemplate->GetName(); if(ComponentTemplateName.EndsWith(UActorComponent::ComponentTemplateNameSuffix) && !ComponentTemplateName.StartsWith(VariableName) && !GIsDuplicatingClassForReinstancing) { Node->ComponentTemplate->ConditionalPostLoad(); Node->ComponentTemplate = static_cast<UActorComponent*>(StaticDuplicateObject(Node->ComponentTemplate, Node->ComponentTemplate->GetOuter(), *(VariableName + UActorComponent::ComponentTemplateNameSuffix))); } // Check to see if switched from scene to a non-scene component type if (!Node->ComponentTemplate->IsA<USceneComponent>()) { // Otherwise, check to see if switched from scene to non-scene component type int32 RootNodeIndex = INDEX_NONE; if(!RootNodes.Find(Node, RootNodeIndex)) { // Move the node into the root set if it's currently in the scene hierarchy USCS_Node* ParentNode = FindParentNode(Node); if(ParentNode != nullptr) { ParentNode->RemoveChildNode(Node); } RootNodes.Add(Node); } else { // Otherwise, if it's a root node, promote one of its children (if any) to take its place int32 PromoteIndex = FindPromotableChildNodeIndex(Node); if(PromoteIndex != INDEX_NONE) { // Remove it as a child node USCS_Node* ChildToPromote = Node->GetChildNodes()[PromoteIndex]; Node->RemoveChildNodeAt(PromoteIndex, false); // Insert it as a root node just before its prior parent node; this way if it switches back to a scene type it won't supplant the new root we've just created RootNodes.Insert(ChildToPromote, RootNodeIndex); // Append previous root node's children to the new root ChildToPromote->MoveChildNodes(Node); // Copy any previous external attachment info from the previous root node ChildToPromote->bIsParentComponentNative = Node->bIsParentComponentNative; ChildToPromote->ParentComponentOrVariableName = Node->ParentComponentOrVariableName; ChildToPromote->ParentComponentOwnerClassName = Node->ParentComponentOwnerClassName; } // Clear info for any previous external attachment if set if(Node->ParentComponentOrVariableName != NAME_None) { Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; } } } } } #endif // WITH_EDITOR // Fix up native/inherited parent attachments, in case anything has changed FixupRootNodeParentReferences(); // Ensure that we have a valid scene root ValidateSceneRootNodes(); // Reset non-native "root" scene component scale values, prior to the change in which // we began applying custom scale values to root components at construction time. This // way older, existing Blueprint actor instances won't start unexpectedly getting scaled. if(GetLinkerUE4Version() < VER_UE4_BLUEPRINT_USE_SCS_ROOTCOMPONENT_SCALE) { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass != nullptr) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Check for a native root component USceneComponent* NativeRootComponent = CDO->GetRootComponent(); if(NativeRootComponent == nullptr) { // If no native root component exists, find the first non-native, non-parented SCS node with a // scene component template. This will be designated as the root component at construction time. for (USCS_Node* Node : RootNodes) { if(Node->ParentComponentOrVariableName == NAME_None) { // Note that we have to check for nullptr here, because it may be an ActorComponent type USceneComponent* SceneComponentTemplate = Cast<USceneComponent>(Node->ComponentTemplate); if(SceneComponentTemplate != nullptr && SceneComponentTemplate->RelativeScale3D != FVector(1.0f, 1.0f, 1.0f)) { UE_LOG(LogBlueprint, Warning, TEXT("%s: Found non-native root component custom scale for %s (%s) saved prior to being usable; reverting to default scale."), *BPGeneratedClass->GetName(), *Node->GetVariableName().ToString(), *SceneComponentTemplate->RelativeScale3D.ToString()); SceneComponentTemplate->RelativeScale3D = FVector(1.0f, 1.0f, 1.0f); } // Done - no need to fix up any other nodes. break; } } } } } } if (GetLinkerUE4Version() < VER_UE4_SCS_STORES_ALLNODES_ARRAY) { // Fill out AllNodes if this is an older object if (RootNodes.Num() > 0) { AllNodes.Reset(); for (USCS_Node* RootNode : RootNodes) { if (RootNode != nullptr) { AllNodes.Append(RootNode->GetAllNodes()); } } } } }
void FComponentEditorUtils::CopyComponents(const TArray<UActorComponent*>& ComponentsToCopy) { FStringOutputDevice Archive; const FExportObjectInnerContext Context; // Clear the mark state for saving. UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp)); // Duplicate the selected component templates into temporary objects that we can modify TMap<FName, FName> ParentMap; TMap<FName, UActorComponent*> ObjectMap; for (UActorComponent* Component : ComponentsToCopy) { // Duplicate the component into a temporary object UObject* DuplicatedComponent = StaticDuplicateObject(Component, GetTransientPackage(), Component->GetFName(), RF_AllFlags & ~RF_ArchetypeObject); if (DuplicatedComponent) { // If the duplicated component is a scene component, wipe its attach parent (to prevent log warnings for referencing a private object in an external package) if (auto DuplicatedCompAsSceneComp = Cast<USceneComponent>(DuplicatedComponent)) { DuplicatedCompAsSceneComp->AttachParent = nullptr; } // Find the closest parent component of the current component within the list of components to copy USceneComponent* ClosestSelectedParent = FindClosestParentInList(Component, ComponentsToCopy); if (ClosestSelectedParent) { // If the parent is included in the list, record it into the node->parent map ParentMap.Add(Component->GetFName(), ClosestSelectedParent->GetFName()); } // Record the temporary object into the name->object map ObjectMap.Add(Component->GetFName(), CastChecked<UActorComponent>(DuplicatedComponent)); } } // Export the component object(s) to text for copying for (auto ObjectIt = ObjectMap.CreateIterator(); ObjectIt; ++ObjectIt) { // Get the component object to be copied UActorComponent* ComponentToCopy = ObjectIt->Value; check(ComponentToCopy); // If this component object had a parent within the selected set if (ParentMap.Contains(ComponentToCopy->GetFName())) { // Get the name of the parent component FName ParentName = ParentMap[ComponentToCopy->GetFName()]; if (ObjectMap.Contains(ParentName)) { // Ensure that this component is a scene component USceneComponent* SceneComponent = Cast<USceneComponent>(ComponentToCopy); if (SceneComponent) { // Set the attach parent to the matching parent object in the temporary set. This allows us to preserve hierarchy in the copied set. SceneComponent->AttachParent = Cast<USceneComponent>(ObjectMap[ParentName]); } } } // Export the component object to the given string UExporter::ExportToOutputDevice(&Context, ComponentToCopy, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited, false, ComponentToCopy->GetOuter()); } // Copy text to clipboard FString ExportedText = Archive; FPlatformMisc::ClipboardCopy(*ExportedText); }
void SAnimationCompressionPanel::Construct(const FArguments& InArgs) { ParentWindow = InArgs._ParentWindow.Get(); AnimSequences = InArgs._AnimSequences; CompressionHolder = NewObject<UCompressionHolder>(); CompressionHolder->AddToRoot(); if (AnimSequences.Num() == 1) { UAnimSequence* Seq = AnimSequences[0].Get(); CompressionHolder->Compression = static_cast<UAnimCompress*>(StaticDuplicateObject(Seq->CompressionScheme, CompressionHolder)); } FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked<FPropertyEditorModule>("PropertyEditor"); const bool bAllowSearch = true; FDetailsViewArgs DetailsViewArgs(/*bUpdateFromSelection=*/ false, /*bLockable=*/ false, bAllowSearch, FDetailsViewArgs::HideNameArea, /*bHideSelectionTip=*/ true); TSharedPtr<class IDetailsView> PropertyView = EditModule.CreateDetailView(DetailsViewArgs); TArray<UObject*> SelectedObjects; SelectedObjects.Add(CompressionHolder); PropertyView->SetObjects(SelectedObjects); TSharedRef<SVerticalBox> Box = SNew(SVerticalBox) + SVerticalBox::Slot() .FillHeight(1.f) .Padding(8.0f, 4.0f, 8.0f, 4.0f) [ PropertyView.ToSharedRef() ] +SVerticalBox::Slot() .AutoHeight() .Padding(8.0f, 4.0f, 4.0f, 8.0f) [ SNew(SSeparator) ] +SVerticalBox::Slot() .Padding(4.0f) .HAlign(HAlign_Right) .VAlign(VAlign_Bottom) .AutoHeight() [ SNew(SUniformGridPanel) .SlotPadding(FEditorStyle::GetMargin("StandardDialog.SlotPadding")) .MinDesiredSlotWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth")) .MinDesiredSlotHeight(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotHeight")) + SUniformGridPanel::Slot(0, 0) [ SNew(SButton) .Text(LOCTEXT("AnimCompressionApply", "Apply")) .HAlign(HAlign_Center) .ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding")) .OnClicked(this, &SAnimationCompressionPanel::ApplyClicked) ] ]; this->ChildSlot[Box]; }