PyObject *py_ue_bind_key(ue_PyUObject *self, PyObject * args) { ue_py_check(self); char *key_name; int key; PyObject *py_callable; if (!PyArg_ParseTuple(args, "siO:bind_key", &key_name, &key, &py_callable)) { return NULL; } if (!PyCallable_Check(py_callable)) { return PyErr_Format(PyExc_Exception, "object is not a callable"); } UInputComponent *input = nullptr; if (self->ue_object->IsA<AActor>()) { input = ((AActor *)self->ue_object)->InputComponent; } else if (self->ue_object->IsA<UActorComponent>()) { UActorComponent *component = (UActorComponent *)self->ue_object; if (!component->GetOwner()) return PyErr_Format(PyExc_Exception, "component is still not mapped to an Actor"); input = component->GetOwner()->InputComponent; } else { return PyErr_Format(PyExc_Exception, "uobject is not an actor or a component"); } if (!input) { return PyErr_Format(PyExc_Exception, "no input manager for this uobject"); } UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(input, py_callable, nullptr); FInputKeyBinding input_key_binding(FKey(UTF8_TO_TCHAR(key_name)), (const EInputEvent)key); input_key_binding.KeyDelegate.BindDelegate(py_delegate, &UPythonDelegate::PyInputHandler); input->KeyBindings.Add(input_key_binding); Py_RETURN_NONE; }
void FBlueprintCompileReinstancer::ReconstructOwnerInstances(TSubclassOf<UActorComponent> ComponentClass) { if (ComponentClass == nullptr) { return; } TArray<UObject*> ComponentInstances; GetObjectsOfClass(ComponentClass, ComponentInstances, /*bIncludeDerivedClasses =*/false); TSet<AActor*> OwnerInstances; for (UObject* ComponentObj : ComponentInstances) { UActorComponent* Component = CastChecked<UActorComponent>(ComponentObj); if (AActor* OwningActor = Component->GetOwner()) { // we don't just rerun construction here, because we could end up // doing it twice for the same actor (if it had multiple components // of this kind), so we put that off as a secondary pass OwnerInstances.Add(OwningActor); } } for (AActor* ComponentOwner : OwnerInstances) { ComponentOwner->RerunConstructionScripts(); } }
void FComponentMaterialCategory::OnGetMaterialsForView( IMaterialListBuilder& MaterialList ) { const bool bAllowNullEntries = true; // Iterate over every material on the actors for( FMaterialIterator It( SelectedComponents ); It; ++It ) { int32 MaterialIndex = It.GetMaterialIndex(); UActorComponent* CurrentComponent = It.GetComponent(); if( CurrentComponent ) { UMaterialInterface* Material = It.GetMaterial(); AActor* Actor = CurrentComponent->GetOwner(); // Component materials can be replaced if the component supports material overrides const bool bCanBeReplaced = ( CurrentComponent->IsA( UMeshComponent::StaticClass() ) || CurrentComponent->IsA( UTextRenderComponent::StaticClass() ) || CurrentComponent->IsA( ULandscapeComponent::StaticClass() ) ); // Add the material if we allow null materials to be added or we have a valid material if( bAllowNullEntries || Material ) { MaterialList.AddMaterial( MaterialIndex, Material, bCanBeReplaced ); } } } }
UObject* ULevelSequence::GetParentObject(UObject* Object) const { UActorComponent* Component = Cast<UActorComponent>(Object); if (Component != nullptr) { return Component->GetOwner(); } return nullptr; }
PyObject *py_ue_get_owner(ue_PyUObject *self, PyObject * args) { ue_py_check(self); UActorComponent *component = ue_py_check_type<UActorComponent>(self); if (!component) return PyErr_Format(PyExc_Exception, "uobject is not a component"); Py_RETURN_UOBJECT(component->GetOwner()); }
void SDetailNameArea::Refresh( const TArray< TWeakObjectPtr<AActor> >& SelectedActors, const TArray< TWeakObjectPtr<UObject> >& SelectedObjects, FDetailsViewArgs::ENameAreaSettings NameAreaSettings ) { // Convert the actor array to base object type TArray< TWeakObjectPtr<UObject> > FinalSelectedObjects; if(NameAreaSettings == FDetailsViewArgs::ActorsUseNameArea) { for(auto Actor : SelectedActors) { const TWeakObjectPtr<UObject> ObjectWeakPtr = Actor.Get(); FinalSelectedObjects.Add(ObjectWeakPtr); } } else if( NameAreaSettings == FDetailsViewArgs::ComponentsAndActorsUseNameArea ) { for(auto Actor : SelectedActors) { const TWeakObjectPtr<UObject> ObjectWeakPtr = Actor.Get(); FinalSelectedObjects.Add(ObjectWeakPtr); } // Note: assumes that actors and components are not selected together. if( FinalSelectedObjects.Num() == 0 ) { for(auto Object : SelectedObjects) { UActorComponent* ActorComp = Cast<UActorComponent>(Object.Get()); if(ActorComp && ActorComp->GetOwner()) { FinalSelectedObjects.AddUnique(ActorComp->GetOwner()); } } } } Refresh( FinalSelectedObjects ); }
PyObject *py_ue_get_owner(ue_PyUObject *self, PyObject * args) { ue_py_check(self); if (!self->ue_object->IsA<UActorComponent>()) { return PyErr_Format(PyExc_Exception, "uobject is not a component"); } UActorComponent *component = (UActorComponent *)self->ue_object; ue_PyUObject *ret = ue_get_python_wrapper(component->GetOwner()); if (!ret) return PyErr_Format(PyExc_Exception, "uobject is in invalid state"); Py_INCREF(ret); return (PyObject *)ret; }
PyObject *py_ue_get_actor_label(ue_PyUObject *self, PyObject * args) { ue_py_check(self); if (self->ue_object->IsA<AActor>()) { AActor *actor = (AActor *)self->ue_object; return PyUnicode_FromString(TCHAR_TO_UTF8(*(actor->GetActorLabel()))); } if (self->ue_object->IsA<UActorComponent>()) { UActorComponent *component = (UActorComponent *)self->ue_object; return PyUnicode_FromString(TCHAR_TO_UTF8(*(component->GetOwner()->GetActorLabel()))); } return PyErr_Format(PyExc_Exception, "uobject is not an actor or a component"); }
PyObject *py_ue_simple_move_to_location(ue_PyUObject *self, PyObject * args) { ue_py_check(self); FVector vec; if (!py_ue_vector_arg(args, vec)) return NULL; UWorld *world = ue_get_uworld(self); if (!world) return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject"); APawn *pawn = nullptr; if (self->ue_object->IsA<APawn>()) { pawn = (APawn *)self->ue_object; } else if (self->ue_object->IsA<UActorComponent>()) { UActorComponent *component = (UActorComponent *)self->ue_object; AActor *actor = component->GetOwner(); if (actor) { if (actor->IsA<APawn>()) { pawn = (APawn *)actor; } } } if (!pawn) return PyErr_Format(PyExc_Exception, "uobject is not a pawn"); AController *controller = pawn->GetController(); if (!controller) return PyErr_Format(PyExc_Exception, "Pawn has no controller"); world->GetNavigationSystem()->SimpleMoveToLocation(controller, vec); Py_INCREF(Py_None); return Py_None; }
void FBlueprintCompileReinstancer::ReplaceInstancesOfClass(UClass* OldClass, UClass* NewClass, UObject* OriginalCDO, TSet<UObject*>* ObjectsThatShouldUseOldStuff) { USelection* SelectedActors; bool bSelectionChanged = false; TArray<UObject*> ObjectsToReplace; const bool bLogConversions = false; // for debugging // Map of old objects to new objects TMap<UObject*, UObject*> OldToNewInstanceMap; TMap<UClass*, UClass*> OldToNewClassMap; OldToNewClassMap.Add(OldClass, NewClass); TMap<FStringAssetReference, UObject*> ReinstancedObjectsWeakReferenceMap; // actors being replace TArray<FActorReplacementHelper> ReplacementActors; // A list of objects (e.g. Blueprints) that potentially have editors open that we need to refresh TArray<UObject*> PotentialEditorsForRefreshing; // A list of component owners that need their construction scripts re-ran (because a component of theirs has been reinstanced) TSet<AActor*> OwnersToReconstruct; // Set global flag to let system know we are reconstructing blueprint instances TGuardValue<bool> GuardTemplateNameFlag(GIsReconstructingBlueprintInstances, true); struct FObjectRemappingHelper { void OnObjectsReplaced(const TMap<UObject*, UObject*>& InReplacedObjects) { ReplacedObjects.Append(InReplacedObjects); } TMap<UObject*, UObject*> ReplacedObjects; } ObjectRemappingHelper; FDelegateHandle OnObjectsReplacedHandle = GEditor->OnObjectsReplaced().AddRaw(&ObjectRemappingHelper,&FObjectRemappingHelper::OnObjectsReplaced); { BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_ReplaceInstancesOfClass); const bool bIncludeDerivedClasses = false; GetObjectsOfClass(OldClass, ObjectsToReplace, bIncludeDerivedClasses); SelectedActors = GEditor->GetSelectedActors(); SelectedActors->BeginBatchSelectOperation(); SelectedActors->Modify(); // Then fix 'real' (non archetype) instances of the class for (UObject* OldObject : ObjectsToReplace) { // Skip non-archetype instances, EXCEPT for component templates const bool bIsComponent = NewClass->IsChildOf(UActorComponent::StaticClass()); if ((!bIsComponent && OldObject->IsTemplate()) || OldObject->IsPendingKill()) { continue; } UBlueprint* CorrespondingBlueprint = Cast<UBlueprint>(OldObject->GetClass()->ClassGeneratedBy); UObject* OldBlueprintDebugObject = nullptr; // If this object is being debugged, cache it off so we can preserve the 'object being debugged' association if ((CorrespondingBlueprint != nullptr) && (CorrespondingBlueprint->GetObjectBeingDebugged() == OldObject)) { OldBlueprintDebugObject = OldObject; } AActor* OldActor = Cast<AActor>(OldObject); UObject* NewUObject = nullptr; // if the object to replace is an actor... if (OldActor != nullptr) { FVector Location = FVector::ZeroVector; FRotator Rotation = FRotator::ZeroRotator; if (USceneComponent* OldRootComponent = OldActor->GetRootComponent()) { Location = OldActor->GetActorLocation(); Rotation = OldActor->GetActorRotation(); } // If this actor was spawned from an Archetype, we spawn the new actor from the new version of that archetype UObject* OldArchetype = OldActor->GetArchetype(); UWorld* World = OldActor->GetWorld(); AActor* NewArchetype = Cast<AActor>(OldToNewInstanceMap.FindRef(OldArchetype)); // Check that either this was an instance of the class directly, or we found a new archetype for it check(OldArchetype == OldClass->GetDefaultObject() || NewArchetype); // Spawn the new actor instance, in the same level as the original, but deferring running the construction script until we have transferred modified properties ULevel* ActorLevel = OldActor->GetLevel(); UClass** MappedClass = OldToNewClassMap.Find(OldActor->GetClass()); UClass* SpawnClass = MappedClass ? *MappedClass : NewClass; FActorSpawnParameters SpawnInfo; SpawnInfo.OverrideLevel = ActorLevel; SpawnInfo.Template = NewArchetype; SpawnInfo.bNoCollisionFail = true; SpawnInfo.bDeferConstruction = true; // Temporarily remove the deprecated flag so we can respawn the Blueprint in the level const bool bIsClassDeprecated = SpawnClass->HasAnyClassFlags(CLASS_Deprecated); SpawnClass->ClassFlags &= ~CLASS_Deprecated; AActor* NewActor = World->SpawnActor(SpawnClass, &Location, &Rotation, SpawnInfo); // Reassign the deprecated flag if it was previously assigned if (bIsClassDeprecated) { SpawnClass->ClassFlags |= CLASS_Deprecated; } check(NewActor != nullptr); NewUObject = NewActor; // store the new actor for the second pass (NOTE: this detaches // OldActor from all child/parent attachments) // // running the NewActor's construction-script is saved for that // second pass (because the construction-script may reference // another instance that hasn't been replaced yet). ReplacementActors.Add(FActorReplacementHelper(NewActor, OldActor)); ReinstancedObjectsWeakReferenceMap.Add(OldObject, NewUObject); OldActor->DestroyConstructedComponents(); // don't want to serialize components from the old actor // Unregister native components so we don't copy any sub-components they generate for themselves (like UCameraComponent does) OldActor->UnregisterAllComponents(); // Unregister any native components, might have cached state based on properties we are going to overwrite NewActor->UnregisterAllComponents(); UEditorEngine::CopyPropertiesForUnrelatedObjects(OldActor, NewActor); // reset properties/streams NewActor->ResetPropertiesForConstruction(); // register native components NewActor->RegisterAllComponents(); // // clean up the old actor (unselect it, remove it from the world, etc.)... if (OldActor->IsSelected()) { GEditor->SelectActor(OldActor, /*bInSelected =*/false, /*bNotify =*/false); bSelectionChanged = true; } if (GEditor->Layers.IsValid()) // ensure(NULL != GEditor->Layers) ?? While cooking the Layers is NULL. { GEditor->Layers->DisassociateActorFromLayers(OldActor); } World->EditorDestroyActor(OldActor, /*bShouldModifyLevel =*/true); OldToNewInstanceMap.Add(OldActor, NewActor); } else { FName OldName(OldObject->GetFName()); OldObject->Rename(NULL, OldObject->GetOuter(), REN_DoNotDirty | REN_DontCreateRedirectors); NewUObject = NewObject<UObject>(OldObject->GetOuter(), NewClass, OldName); check(NewUObject != nullptr); UEditorEngine::CopyPropertiesForUnrelatedObjects(OldObject, NewUObject); if (UAnimInstance* AnimTree = Cast<UAnimInstance>(NewUObject)) { // Initialising the anim instance isn't enough to correctly set up the skeletal mesh again in a // paused world, need to initialise the skeletal mesh component that contains the anim instance. if (USkeletalMeshComponent* SkelComponent = Cast<USkeletalMeshComponent>(AnimTree->GetOuter())) { SkelComponent->InitAnim(true); } } OldObject->RemoveFromRoot(); OldObject->MarkPendingKill(); OldToNewInstanceMap.Add(OldObject, NewUObject); if (bIsComponent) { UActorComponent* Component = Cast<UActorComponent>(NewUObject); AActor* OwningActor = Component->GetOwner(); if (OwningActor) { OwningActor->ResetOwnedComponents(); // Check to see if they have an editor that potentially needs to be refreshed if (OwningActor->GetClass()->ClassGeneratedBy) { PotentialEditorsForRefreshing.AddUnique(OwningActor->GetClass()->ClassGeneratedBy); } // we need to keep track of actor instances that need // their construction scripts re-ran (since we've just // replaced a component they own) OwnersToReconstruct.Add(OwningActor); } } } // If this original object came from a blueprint and it was in the selected debug set, change the debugging to the new object. if ((CorrespondingBlueprint) && (OldBlueprintDebugObject) && (NewUObject)) { CorrespondingBlueprint->SetObjectBeingDebugged(NewUObject); } if (bLogConversions) { UE_LOG(LogBlueprint, Log, TEXT("Converted instance '%s' to '%s'"), *OldObject->GetPathName(), *NewUObject->GetPathName()); } } } GEditor->OnObjectsReplaced().Remove(OnObjectsReplacedHandle); // Now replace any pointers to the old archetypes/instances with pointers to the new one TArray<UObject*> SourceObjects; TArray<UObject*> DstObjects; OldToNewInstanceMap.GenerateKeyArray(SourceObjects); OldToNewInstanceMap.GenerateValueArray(DstObjects); // Also look for references in new spawned objects. SourceObjects.Append(DstObjects); FReplaceReferenceHelper::IncludeCDO(OldClass, NewClass, OldToNewInstanceMap, SourceObjects, OriginalCDO); FReplaceReferenceHelper::FindAndReplaceReferences(SourceObjects, ObjectsThatShouldUseOldStuff, ObjectsToReplace, OldToNewInstanceMap, ReinstancedObjectsWeakReferenceMap); { BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_ReplacementConstruction); // the process of setting up new replacement actors is split into two // steps (this here, is the second)... // // the "finalization" here runs the replacement actor's construction- // script and is left until late to account for a scenario where the // construction-script attempts to modify another instance of the // same class... if this were to happen above, in the ObjectsToReplace // loop, then accessing that other instance would cause an assert in // UProperty::ContainerPtrToValuePtrInternal() (which appropriatly // complains that the other instance's type doesn't match because it // hasn't been replaced yet... that's why we wait until after // FArchiveReplaceObjectRef to run construction-scripts). for (FActorReplacementHelper& ReplacementActor : ReplacementActors) { ReplacementActor.Finalize(ObjectRemappingHelper.ReplacedObjects); } } SelectedActors->EndBatchSelectOperation(); if (bSelectionChanged) { GEditor->NoteSelectionChange(); } if (GEditor) { // Refresh any editors for objects that we've updated components for for (auto BlueprintAsset : PotentialEditorsForRefreshing) { FBlueprintEditor* BlueprintEditor = static_cast<FBlueprintEditor*>(FAssetEditorManager::Get().FindEditorForAsset(BlueprintAsset, /*bFocusIfOpen =*/false)); if (BlueprintEditor) { BlueprintEditor->RefreshEditors(); } } } // in the case where we're replacing component instances, we need to make // sure to re-run their owner's construction scripts for (AActor* ActorInstance : OwnersToReconstruct) { ActorInstance->RerunConstructionScripts(); } }
void UUnrealEdEngine::UpdatePivotLocationForSelection( bool bOnChange ) { // Pick a new common pivot, or not. AActor* SingleActor = nullptr; USceneComponent* SingleComponent = nullptr; if (GetSelectedComponentCount() > 0) { for (FSelectedEditableComponentIterator It(*GetSelectedComponents()); It; ++It) { UActorComponent* Component = CastChecked<UActorComponent>(*It); AActor* ComponentOwner = Component->GetOwner(); if (ComponentOwner != nullptr) { auto SelectedActors = GetSelectedActors(); const bool bIsOwnerSelected = SelectedActors->IsSelected(ComponentOwner); check(bIsOwnerSelected); if (ComponentOwner->GetWorld() == GWorld) { SingleActor = ComponentOwner; if (Component->IsA<USceneComponent>()) { SingleComponent = CastChecked<USceneComponent>(Component); } const bool IsTemplate = ComponentOwner->IsTemplate(); const bool LevelLocked = !FLevelUtils::IsLevelLocked(ComponentOwner->GetLevel()); check(IsTemplate || LevelLocked); } } } } else { for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) { AActor* Actor = static_cast<AActor*>(*It); checkSlow(Actor->IsA(AActor::StaticClass())); if (Actor->GetWorld() == GWorld) { const bool IsTemplate = Actor->IsTemplate(); const bool LevelLocked = !FLevelUtils::IsLevelLocked(Actor->GetLevel()); check(IsTemplate || LevelLocked); SingleActor = Actor; } } } if (SingleComponent != NULL) { SetPivot(SingleComponent->GetComponentLocation(), false, true); } else if( SingleActor != NULL ) { // For geometry mode use current pivot location as it's set to selected face, not actor FEditorModeTools& Tools = GLevelEditorModeTools(); if( Tools.IsModeActive(FBuiltinEditorModes::EM_Geometry) == false || bOnChange == true ) { // Set pivot point to the actor's location FVector PivotPoint = SingleActor->GetActorLocation(); // If grouping is active, see if this actor is part of a locked group and use that pivot instead if(GEditor->bGroupingActive) { AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(SingleActor, true, true); if(ActorGroupRoot) { PivotPoint = ActorGroupRoot->GetActorLocation(); } } SetPivot( PivotPoint, false, true ); } } else { ResetPivot(); } }
/** * Enacts the transaction. */ void FTransaction::Apply() { checkSlow(Inc==1||Inc==-1); // Figure out direction. const int32 Start = Inc==1 ? 0 : Records.Num()-1; const int32 End = Inc==1 ? Records.Num() : -1; // Init objects. for( int32 i=Start; i!=End; i+=Inc ) { FObjectRecord& Record = Records[i]; Record.bRestored = false; UObject* Object = Record.Object.Get(); if (Object) { if (!ChangedObjects.Contains(Object)) { Object->CheckDefaultSubobjects(); Object->PreEditUndo(); } ChangedObjects.Add(Object, Record.ObjectAnnotation); } } if (bFlip) { for (int32 i = Start; i != End; i += Inc) { Records[i].Save(this); } for (int32 i = Start; i != End; i += Inc) { Records[i].Load(this); } } else { for (int32 i = Start; i != End; i += Inc) { Records[i].Restore(this); } } // An Actor's components must always get its PostEditUndo before the owning Actor so do a quick sort ChangedObjects.KeySort([](UObject& A, UObject& B) { UActorComponent* BAsComponent = Cast<UActorComponent>(&B); return (BAsComponent ? (BAsComponent->GetOwner() != &A) : true); }); TArray<ULevel*> LevelsToCommitModelSurface; NumModelsModified = 0; // Count the number of UModels that were changed. for (auto ChangedObjectIt : ChangedObjects) { UObject* ChangedObject = ChangedObjectIt.Key; UModel* Model = Cast<UModel>(ChangedObject); if (Model && Model->Nodes.Num()) { FBSPOps::bspBuildBounds(Model); ++NumModelsModified; } if (UModelComponent* ModelComponent = Cast<UModelComponent>(ChangedObject)) { ULevel* Level = ModelComponent->GetTypedOuter<ULevel>(); check(Level); LevelsToCommitModelSurface.AddUnique(Level); } TSharedPtr<ITransactionObjectAnnotation> ChangedObjectTransactionAnnotation = ChangedObjectIt.Value; if (ChangedObjectTransactionAnnotation.IsValid()) { ChangedObject->PostEditUndo(ChangedObjectTransactionAnnotation); } else { ChangedObject->PostEditUndo(); } } // Commit model surfaces for unique levels within the transaction for (ULevel* Level : LevelsToCommitModelSurface) { Level->CommitModelSurfaces(); } // Flip it. if (bFlip) { Inc *= -1; } for (auto ChangedObjectIt : ChangedObjects) { UObject* ChangedObject = ChangedObjectIt.Key; ChangedObject->CheckDefaultSubobjects(); } ChangedObjects.Empty(); }