void UComponentDelegateBinding::BindDynamicDelegates(AActor* InInstance) const
{
	for(int32 BindIdx=0; BindIdx<ComponentDelegateBindings.Num(); BindIdx++)
	{
		const FBlueprintComponentDelegateBinding& Binding = ComponentDelegateBindings[BindIdx];
		// Get the function we want to bind
		UFunction* FunctionToBind = FindField<UFunction>(InInstance->GetClass(), Binding.FunctionNameToBind);
		// Get the property that points to the component we want to assign to
		UObjectProperty* ObjProp = FindField<UObjectProperty>(InInstance->GetClass(), Binding.ComponentPropertyName);
		// If we have both of those..
		if(ObjProp != NULL && FunctionToBind != NULL)
		{
			// ..see if there is actually a component assigned
			UActorComponent* Component = Cast<UActorComponent>(ObjProp->GetObjectPropertyValue_InContainer(InInstance));
			if(Component != NULL)
			{
				// If there is, find the delegate property on it
				UMulticastDelegateProperty* DelegateProp = FindField<UMulticastDelegateProperty>(Component->GetClass(), Binding.DelegatePropertyName);
				if(DelegateProp)
				{
					// Found that, finally bind function on the actor to this delegate
					FMulticastScriptDelegate* TargetDelegate = DelegateProp->GetPropertyValuePtr_InContainer(Component);

					FScriptDelegate Delegate;
					Delegate.SetFunctionName(Binding.FunctionNameToBind);
					Delegate.SetObject(InInstance);
					TargetDelegate->AddUnique(Delegate);
				}
			}
		}
	}
}
void FAnimBlueprintNodeOptionalPinManager::PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const
{
	check(PropertyAddress != NULL);
	check(!Record.bShowPin);

	if (Record.bCanToggleVisibility && (OldPins != NULL))
	{
		const FString OldPinName = (ArrayIndex != INDEX_NONE) ? FString::Printf(TEXT("%s_%d"), *(Record.PropertyName.ToString()), ArrayIndex) : Record.PropertyName.ToString();
		if (UEdGraphPin* OldPin = OldPinMap.FindRef(OldPinName))
		{
			// Pin was visible but it's now hidden
			UObjectProperty* ObjectProperty = Cast<UObjectProperty>(Property);
			UAnimGraphNode_AssetPlayerBase* AssetPlayerNode = Cast<UAnimGraphNode_AssetPlayerBase>(BaseNode);
			if (AssetPlayerNode && ObjectProperty && ObjectProperty->PropertyClass->IsChildOf<UAnimationAsset>())
			{
				// If this is an anim asset pin, dont store a hard reference to the asset in the node, as this ends up referencing things we might not want to load any more
				UObject* AssetReference = AssetPlayerNode->GetAssetReferenceForPinRestoration();
				if (AssetReference)
				{
					ObjectProperty->SetObjectPropertyValue(PropertyAddress, AssetReference);
				}
					
			}
			else
			{
				// Convert DefaultValue/DefaultValueObject and push back into the struct
				FBlueprintEditorUtils::ImportKismetDefaultValueToProperty(OldPin, Property, PropertyAddress, BaseNode);
			}
		}
	}
}
UK2Node_VariableGet* UGameplayAbilityGraphSchema::SpawnVariableGetNode(const FVector2D GraphPosition, class UEdGraph* ParentGraph, FName VariableName, UStruct* Source) const
{
	// Perform handling to create custom nodes for some classes
	UProperty* VarProp = FindField<UProperty>(Source, VariableName);
	UObjectProperty* ObjProp = Cast<UObjectProperty>(VarProp);
	if (ObjProp)
	{
		UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(ParentGraph);
		TSubclassOf<UObject> GenClass = Blueprint->GeneratedClass;

		UObject* ActiveObject = GenClass->GetDefaultObject();

		// If the variable is a GameplayEffect create a custom node to show it
		FString PropType;
		ObjProp->GetCPPMacroType(PropType);
		if (PropType == "UGameplayEffect")
		{
			UK2Node_GameplayEffectVariable* NodeTemplate = NewObject<UK2Node_GameplayEffectVariable>();
			UEdGraphSchema_K2::ConfigureVarNode(NodeTemplate, VariableName, Source, Blueprint);

			UK2Node_GameplayEffectVariable* VariableNode = FEdGraphSchemaAction_K2NewNode::SpawnNodeFromTemplate<UK2Node_GameplayEffectVariable>(ParentGraph, NodeTemplate, GraphPosition);

			UGameplayEffect* GameplayEffect = Cast<UGameplayEffect>(ObjProp->GetObjectPropertyValue_InContainer(ActiveObject));
			if (GameplayEffect)
			{
				VariableNode->GameplayEffect = GameplayEffect;
			}

			return VariableNode;
		}
	}

	// Couldn't find an appropriate custom node for this variable, use the generic case
	return Super::SpawnVariableGetNode(GraphPosition, ParentGraph, VariableName, Source);
}
USceneComponent* FComponentEditorUtils::GetSceneComponent( UObject* Object, UObject* SubObject /*= NULL*/ )
{
	if( Object )
	{
		AActor* Actor = Cast<AActor>( Object );
		if( Actor )
		{
			if( SubObject )
			{
				if( SubObject->HasAnyFlags( RF_DefaultSubObject ) )
				{
					UObject* ClassDefaultObject = SubObject->GetOuter();
					if( ClassDefaultObject )
					{
						for( TFieldIterator<UObjectProperty> ObjPropIt( ClassDefaultObject->GetClass() ); ObjPropIt; ++ObjPropIt )
						{
							UObjectProperty* ObjectProperty = *ObjPropIt;
							if( SubObject == ObjectProperty->GetObjectPropertyValue_InContainer( ClassDefaultObject ) )
							{
								return CastChecked<USceneComponent>( ObjectProperty->GetObjectPropertyValue_InContainer( Actor ) );
							}
						}
					}
				}
				else if( UBlueprint* Blueprint = Cast<UBlueprint>( SubObject->GetOuter() ) )
				{
					if( Blueprint->SimpleConstructionScript )
					{
						TArray<USCS_Node*> SCSNodes = Blueprint->SimpleConstructionScript->GetAllNodes();
						for( int32 SCSNodeIndex = 0; SCSNodeIndex < SCSNodes.Num(); ++SCSNodeIndex )
						{
							USCS_Node* SCS_Node = SCSNodes[ SCSNodeIndex ];
							if( SCS_Node && SCS_Node->ComponentTemplate == SubObject )
							{
								return SCS_Node->GetParentComponentTemplate( Blueprint );
							}
						}
					}
				}
			}

			return Actor->GetRootComponent();
		}
		else if( Object->IsA<USceneComponent>() )
		{
			return CastChecked<USceneComponent>( Object );
		}
	}

	return NULL;
}
	/**
	* Applies settings to an object by finding UProperties by name and calling ImportText
	*
	* @param InObject - The object to search for matching properties
	* @param PropertyChain - The list UProperty names recursively to search through
	* @param Value - The value to import on the found property
	*/
	void ApplyCustomFactorySetting(UObject* InObject, TArray<FString>& PropertyChain, const FString& Value)
	{
		const FString PropertyName = PropertyChain[0];
		PropertyChain.RemoveAt(0);

		UProperty* TargetProperty = FindField<UProperty>(InObject->GetClass(), *PropertyName);
		if (TargetProperty)
		{
			if (PropertyChain.Num() == 0)
			{
				TargetProperty->ImportText(*Value, TargetProperty->ContainerPtrToValuePtr<uint8>(InObject), 0, InObject);
			}
			else
			{
				UStructProperty* StructProperty = Cast<UStructProperty>(TargetProperty);
				UObjectProperty* ObjectProperty = Cast<UObjectProperty>(TargetProperty);

				UObject* SubObject = NULL;
				bool bValidPropertyType = true;

				if (StructProperty)
				{
					SubObject = StructProperty->Struct;
				}
				else if (ObjectProperty)
				{
					SubObject = ObjectProperty->GetObjectPropertyValue(ObjectProperty->ContainerPtrToValuePtr<UObject>(InObject));
				}
				else
				{
					//Unknown nested object type
					bValidPropertyType = false;
					UE_LOG(LogAutomationEditorCommon, Error, TEXT("ERROR: Unknown nested object type for property: %s"), *PropertyName);
				}

				if (SubObject)
				{
					ApplyCustomFactorySetting(SubObject, PropertyChain, Value);
				}
				else if (bValidPropertyType)
				{
					UE_LOG(LogAutomationEditorCommon, Error, TEXT("Error accessing null property: %s"), *PropertyName);
				}
			}
		}
		else
		{
			UE_LOG(LogAutomationEditorCommon, Error, TEXT("ERROR: Could not find factory property: %s"), *PropertyName);
		}
	}
//------------------------------------------------------------------------------
static bool ContextMenuTargetProfileImpl::HasAnyExposedComponents(UClass* TargetClass)
{
	for (TFieldIterator<UObjectProperty> PropertyIt(TargetClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
	{
		UObjectProperty* ObjectProperty = *PropertyIt;
		if (!ObjectProperty->HasAnyPropertyFlags(CPF_BlueprintVisible) || !ObjectProperty->PropertyClass->IsChildOf<UActorComponent>())
		{
			continue;
		}

		return true;
	}
	return false;
}
	void GetEditableComponents( const AActor* InActor, TArray<UActorComponent*>& OutEditableComponents )
	{
		for( TFieldIterator<UObjectProperty> PropIt(InActor->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt )
		{
			UObjectProperty* ObjectProp = *PropIt;
			if( ObjectProp->HasAnyPropertyFlags(CPF_Edit) )
			{
				UObject* ObjPtr = ObjectProp->GetObjectPropertyValue(ObjectProp->ContainerPtrToValuePtr<void>(InActor));

				if( ObjPtr && ObjPtr->IsA<UActorComponent>() )
				{
					OutEditableComponents.Add( CastChecked<UActorComponent>( ObjPtr ) );
				}
			}
		}
	}
FComponentVisualizer::FPropertyNameAndIndex FComponentVisualizer::GetComponentPropertyName(const UActorComponent* Component)
{
	if (Component)
	{
		const AActor* CompOwner = Component->GetOwner();
		if (CompOwner)
		{
			// Iterate over UObject* fields of this actor
			UClass* ActorClass = CompOwner->GetClass();
			for (TFieldIterator<UObjectProperty> It(ActorClass); It; ++It)
			{
				// See if this property points to the component in question
				UObjectProperty* ObjectProp = *It;
				for (int32 Index = 0; Index < ObjectProp->ArrayDim; ++Index)
				{
					UObject* Object = ObjectProp->GetObjectPropertyValue(ObjectProp->ContainerPtrToValuePtr<void>(CompOwner, Index));
					if (Object == Component)
					{
						// It does! Return this name
						return FPropertyNameAndIndex(ObjectProp->GetFName(), Index);
					}
				}
			}

			// If nothing found, look in TArray<UObject*> fields
			for (TFieldIterator<UArrayProperty> It(ActorClass); It; ++It)
			{
				UArrayProperty* ArrayProp = *It;
				if (UObjectProperty* InnerProp = Cast<UObjectProperty>(It->Inner))
				{
					FScriptArrayHelper ArrayHelper(ArrayProp, ArrayProp->ContainerPtrToValuePtr<void>(CompOwner));
					for (int32 Index = 0; Index < ArrayHelper.Num(); ++Index)
					{
						UObject* Object = InnerProp->GetObjectPropertyValue(ArrayHelper.GetRawPtr(Index));
						if (Object == Component)
						{
							return FPropertyNameAndIndex(ArrayProp->GetFName(), Index);
						}
					}
				}
			}
		}
	}

	// Didn't find actor property referencing this component
	return FPropertyNameAndIndex();
}
FName FComponentEditorUtils::FindVariableNameGivenComponentInstance(UActorComponent* ComponentInstance)
{
	check(ComponentInstance != nullptr);

	// First see if the name just works
	if (AActor* OwnerActor = ComponentInstance->GetOwner())
	{
		UClass* OwnerActorClass = OwnerActor->GetClass();
		if (UObjectProperty* TestProperty = FindField<UObjectProperty>(OwnerActorClass, ComponentInstance->GetFName()))
		{
			if (ComponentInstance->GetClass()->IsChildOf(TestProperty->PropertyClass))
			{
				return TestProperty->GetFName();
			}
		}
	}

	// Name mismatch, try finding a differently named variable pointing to the the component (the mismatch should only be possible for native components)
	if (UActorComponent* Archetype = Cast<UActorComponent>(ComponentInstance->GetArchetype()))
	{
		if (AActor* OwnerActor = Archetype->GetOwner())
		{
			UClass* OwnerClass = OwnerActor->GetClass();
			AActor* OwnerCDO = CastChecked<AActor>(OwnerClass->GetDefaultObject());
			check(OwnerCDO->HasAnyFlags(RF_ClassDefaultObject));

			for (TFieldIterator<UObjectProperty> PropIt(OwnerClass, EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt)
			{
				UObjectProperty* TestProperty = *PropIt;
				if (Archetype->GetClass()->IsChildOf(TestProperty->PropertyClass))
				{
					void* TestPropertyInstanceAddress = TestProperty->ContainerPtrToValuePtr<void>(OwnerCDO);
					UObject* ObjectPointedToByProperty = TestProperty->GetObjectPropertyValue(TestPropertyInstanceAddress);
					if (ObjectPointedToByProperty == Archetype)
					{
						// This property points to the component archetype, so it's an anchor even if it was named wrong
						return TestProperty->GetFName();
					}
				}
			}
		}
	}

	return NAME_None;
}
void FAnimBlueprintNodeOptionalPinManager::PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const
{
	check(PropertyAddress != NULL);
	check(Record.bShowPin);
		


	if (OldPins == NULL)
	{
		// Initial construction of a visible pin; copy values from the struct
		FBlueprintEditorUtils::ExportPropertyToKismetDefaultValue(Pin, Property, PropertyAddress, BaseNode);
	}
	else if (Record.bCanToggleVisibility)
	{
		if (UEdGraphPin* OldPin = OldPinMap.FindRef(Pin->PinName))
		{
			// Was already visible
		}
		else
		{
			// Showing a pin that was previously hidden, during a reconstruction

			UObjectProperty* ObjectProperty = Cast<UObjectProperty>(Property);
			UAnimGraphNode_AssetPlayerBase* AssetPlayerNode = Cast<UAnimGraphNode_AssetPlayerBase>(BaseNode);
			const bool bIsAnimationAsset = AssetPlayerNode != nullptr && ObjectProperty != nullptr && ObjectProperty->PropertyClass->IsChildOf<UAnimationAsset>();

			// Store the old reference to an animation asset in the node's asset reference
			if (bIsAnimationAsset)
			{
				AssetPlayerNode->SetAssetReferenceForPinRestoration(ObjectProperty->GetObjectPropertyValue(PropertyAddress));
			}
		
			// Convert the struct property into DefaultValue/DefaultValueObject
			FBlueprintEditorUtils::ExportPropertyToKismetDefaultValue(Pin, Property, PropertyAddress, BaseNode);

			// clear the asset reference on the node
			if (bIsAnimationAsset)
			{
				ObjectProperty->SetObjectPropertyValue(PropertyAddress, nullptr);
			}
		}
	}
}
//------------------------------------------------------------------------------
static FBlueprintActionFilter BlueprintActionMenuUtilsImpl::MakeCallOnMemberFilter(FBlueprintActionFilter const& MainMenuFilter)
{
	FBlueprintActionFilter CallOnMemberFilter;
	CallOnMemberFilter.Context = MainMenuFilter.Context;
	CallOnMemberFilter.PermittedNodeTypes.Add(UK2Node_CallFunction::StaticClass());
	CallOnMemberFilter.AddRejectionTest(FBlueprintActionFilter::FRejectionTestDelegate::CreateStatic(IsUnBoundSpawner));

	const UBlueprintEditorSettings* BlueprintSettings = GetDefault<UBlueprintEditorSettings>();
	// instead of looking for "ExposeFunctionCategories" on component properties,
	// we just expose functions for all components, but we still need to check
	// for "ExposeFunctionCategories" on any non-component properties... 
	if (BlueprintSettings->bExposeAllMemberComponentFunctions)
	{
		CallOnMemberFilter.AddRejectionTest(FBlueprintActionFilter::FRejectionTestDelegate::CreateStatic(IsUnexposedNonComponentAction));
	}
	else
	{
		CallOnMemberFilter.AddRejectionTest(FBlueprintActionFilter::FRejectionTestDelegate::CreateStatic(IsUnexposedMemberAction));
	}

	for (UClass const* TargetClass : MainMenuFilter.TargetClasses)
	{
		for (TFieldIterator<UObjectProperty> PropertyIt(TargetClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
		{
			UObjectProperty* ObjectProperty = *PropertyIt;

			if (!ObjectProperty->HasAnyPropertyFlags(CPF_BlueprintVisible) ||
				!(ObjectProperty->PropertyClass->IsChildOf<UActorComponent>() || ObjectProperty->HasMetaData(FBlueprintMetadata::MD_ExposeFunctionCategories)))
			{
				continue;
			}
			CallOnMemberFilter.Context.SelectedObjects.Add(ObjectProperty);
		}
	}

	return CallOnMemberFilter;
}
Esempio n. 12
0
bool ANUTActor::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, FInBunch& Bunch)
{
	bool bHandledMessage = false;

	if (MessageType == NMT_NUTControl)
	{
		uint8 CmdType = 0;
		FString Command;
		FNetControlMessage<NMT_NUTControl>::Receive(Bunch, CmdType, Command);

		// Console command
		if (CmdType == ENUTControlCommand::Command_NoResult || CmdType == ENUTControlCommand::Command_SendResult)
		{
			UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Executing command: %s"), *Command);

			FStringOutputDevice CmdResult;
			CmdResult.SetAutoEmitLineTerminator(true);

			bool bCmdSuccess = false;

			bCmdSuccess = GEngine->Exec(GetWorld(), *Command, CmdResult);

			UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Command result: %s"), *CmdResult);


			bool bSendResult = CmdType == ENUTControlCommand::Command_SendResult;

			if (bSendResult)
			{
				uint8 ReturnCmdType = (bCmdSuccess ? ENUTControlCommand::CommandResult_Success :
										ENUTControlCommand::CommandResult_Failed);

				FNetControlMessage<NMT_NUTControl>::Send(Connection, ReturnCmdType, CmdResult);
			}
		}
		// Console command result
		else if (CmdType == ENUTControlCommand::CommandResult_Failed || CmdType == ENUTControlCommand::CommandResult_Success)
		{
			bool bCmdSuccess = CmdType == ENUTControlCommand::CommandResult_Success;

			if (bCmdSuccess)
			{
				UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Got command result:"));
				UE_LOG(LogUnitTest, Log, TEXT("%s"), *Command);
			}
			else
			{
				UE_LOG(LogUnitTest, Log, TEXT("NMT_NUTControl: Failed to execute command"));
			}
		}
		// Ping request
		else if (CmdType == ENUTControlCommand::Ping)
		{
			uint8 TempCmdType = ENUTControlCommand::Pong;
			FString Dud;

			FNetControlMessage<NMT_NUTControl>::Send(Connection, TempCmdType, Dud);
		}
		// Pong reply - this should only be implemented by custom unit tests; hence the assert
		else if (CmdType == ENUTControlCommand::Pong)
		{
			UNIT_ASSERT(false);
		}
		// Custom implemented events, with the result triggered through 'NotifyEvent'
		else if (CmdType == ENUTControlCommand::WatchEvent)
		{
			// NOTE: Only the last NetConnection to request a WatchEvent, will receive notifications
			EventWatcher = Connection;

			// Watch for the end of seamless travel
			if (Command == TEXT("SeamlessTravelEnd"))
			{
				FCoreUObjectDelegates::PostLoadMap.AddStatic(&ANUTActor::NotifyPostLoadMap);
			}
		}
		// Event watch notification - should only be implemented by custom unit tests
		else if (CmdType == ENUTControlCommand::NotifyEvent)
		{
			UNIT_ASSERT(false);
		}
		// Create an actor instance (the 'summon' console command, doesn't work without a cheat manager)
		else if (CmdType == ENUTControlCommand::Summon)
		{
			const TCHAR* Cmd = *Command;
			FString SpawnClassName = FParse::Token(Cmd, false);
			bool bForceBeginPlay = FParse::Param(Cmd, TEXT("ForceBeginPlay"));

			// Hack specifically for getting the GameplayDebugger working - think the mainline code is broken
			bool bGameplayDebuggerHack = FParse::Param(Cmd, TEXT("GameplayDebuggerHack"));

			UClass* SpawnClass = FindObject<UClass>(NULL, *SpawnClassName);

			if (SpawnClass != NULL)
			{
				FActorSpawnParameters SpawnParms;
				SpawnParms.Owner = GetOwner();

				AActor* NewActor = GetWorld()->SpawnActor<AActor>(SpawnClass, SpawnParms);

				if (NewActor != NULL)
				{
					UE_LOG(LogUnitTest, Log, TEXT("Successfully summoned actor of class '%s'"), *SpawnClassName);

					if (bForceBeginPlay && !NewActor->HasActorBegunPlay())
					{
						UE_LOG(LogUnitTest, Log, TEXT("Forcing call to 'BeginPlay' on newly spawned actor."));

						NewActor->BeginPlay();
					}

					if (bGameplayDebuggerHack)
					{
						// Assign the LocalPlayerOwner property, to the PC owning this NUTActor, using reflection (to avoid dependency)
						UObjectProperty* LocalPlayerOwnerProp =
								FindField<UObjectProperty>(NewActor->GetClass(), TEXT("LocalPlayerOwner"));

						if (LocalPlayerOwnerProp != NULL)
						{
							LocalPlayerOwnerProp->SetObjectPropertyValue(
								LocalPlayerOwnerProp->ContainerPtrToValuePtr<UObject*>(NewActor), GetOwner());
						}
						else
						{
							UE_LOG(LogUnitTest, Log, TEXT("WARNING: Failed to find 'LocalPlayerOwner' property. Unit test broken."));
						}

						// Also hack-disable ticking, so that the replicator doesn't spawn a second replicator
						NewActor->SetActorTickEnabled(false);
					}
				}
				else
				{
					UE_LOG(LogUnitTest, Log, TEXT("SpawnActor failed for class '%s'"), *Command);
				}
			}
			else
			{
				UE_LOG(LogUnitTest, Log, TEXT("Could not find actor class '%s'"), *Command);
			}
		}
		// Suspend the game, until a resume request is received (used for giving time, to attach a debugger)
		else if (CmdType == ENUTControlCommand::SuspendProcess)
		{
			UE_LOG(LogUnitTest, Log, TEXT("Suspend start."));


			// Setup a named pipe, to monitor for the resume request
			FString ResumePipeName = FString::Printf(TEXT("%s%u"), NUT_SUSPEND_PIPE, FPlatformProcess::GetCurrentProcessId());
			FPlatformNamedPipe ResumePipe;
			bool bPipeCreated = ResumePipe.Create(ResumePipeName, true, false);

			if (bPipeCreated)
			{
				if (!ResumePipe.OpenConnection())
				{
					UE_LOG(LogUnitTest, Log, TEXT("WARNING: Failed to open pipe connection."));
				}
			}
			else
			{
				UE_LOG(LogUnitTest, Log, TEXT("WARNING: Failed to create resume pipe."));
			}



			// Spin/sleep (effectively suspended) until a resume request is received
			while (true)
			{
				if (bPipeCreated && ResumePipe.IsReadyForRW())
				{
					int32 ResumeVal = 0;

					if (ResumePipe.ReadInt32(ResumeVal) && !!ResumeVal)
					{
						UE_LOG(LogUnitTest, Log, TEXT("Got resume request."));
						break;
					}
				}


				FPlatformProcess::Sleep(1.0f);
			}


			ResumePipe.Destroy();

			UE_LOG(LogUnitTest, Log, TEXT("Suspend end."));
		}

		bHandledMessage = true;
	}

	return bHandledMessage;
}
Esempio n. 13
0
void SKismetInspector::UpdateFromObjects(const TArray<UObject*>& PropertyObjects, struct FKismetSelectionInfo& SelectionInfo, const FShowDetailsOptions& Options)
{
	// If we're using the unified blueprint editor, there's not an explicit point where
	// we ender a kind of component editing mode, so instead, just look at what we're selecting.
	// If we select a component, then enable the customization.
	if ( GetDefault<UEditorExperimentalSettings>()->bUnifiedBlueprintEditor )
	{
		bool bEnableComponentCustomization = false;

		TSharedPtr<FBlueprintEditor> BlueprintEditor = BlueprintEditorPtr.Pin();
		if ( BlueprintEditor.IsValid() )
		{
			if ( BlueprintEditor->CanAccessComponentsMode() )
			{
				for ( UObject* PropertyObject : PropertyObjects )
				{
					if ( PropertyObject->IsA<UActorComponent>() )
					{
						bEnableComponentCustomization = true;
						break;
					}
				}
			}
		}

		EnableComponentDetailsCustomization(bEnableComponentCustomization);
	}

	PropertyView->OnFinishedChangingProperties().Clear();
	PropertyView->OnFinishedChangingProperties().Add( UserOnFinishedChangingProperties );

	if (!Options.bForceRefresh)
	{
		// Early out if the PropertyObjects and the SelectedObjects are the same
		bool bEquivalentSets = (PropertyObjects.Num() == SelectedObjects.Num());
		if (bEquivalentSets)
		{
			// Verify the elements of the sets are equivalent
			for (int32 i = 0; i < PropertyObjects.Num(); i++)
			{
				if (PropertyObjects[i] != SelectedObjects[i].Get())
				{
					bEquivalentSets = false;
					break;
				}
			}
		}

		if (bEquivalentSets)
		{
			return;
		}
	}

	// Proceed to update
	SelectedObjects.Empty();

	for (auto ObjectIt = PropertyObjects.CreateConstIterator(); ObjectIt; ++ObjectIt)
	{
		if (UObject* Object = *ObjectIt)
		{
			if (!Object->IsValidLowLevel())
			{
				ensureMsg(false, TEXT("Object in KismetInspector is invalid, see TTP 281915"));
				continue;
			}

			SelectedObjects.Add(Object);

			if (USCS_Node* SCSNode = Cast<USCS_Node>(Object))
			{
				// Edit the component template
				UActorComponent* NodeComponent = SCSNode->ComponentTemplate;
				if (NodeComponent != NULL)
				{
					SelectionInfo.ObjectsForPropertyEditing.Add(NodeComponent);
					SelectionInfo.EditableComponentTemplates.Add(NodeComponent);
				}
			}
			else if (UK2Node* K2Node = Cast<UK2Node>(Object))
			{
				// Edit the component template if it exists
				if (UActorComponent* Template = K2Node->GetTemplateFromNode())
				{
					SelectionInfo.ObjectsForPropertyEditing.Add(Template);
					SelectionInfo.EditableComponentTemplates.Add(Template);
				}

				// See if we should edit properties of the node
				if (K2Node->ShouldShowNodeProperties())
				{
					SelectionInfo.ObjectsForPropertyEditing.Add(Object);
				}
			}
			else if (UActorComponent* ActorComponent = Cast<UActorComponent>(Object))
			{
				AActor* Owner = ActorComponent->GetOwner();
				if(Owner != NULL && Owner->HasAnyFlags(RF_ClassDefaultObject))
				{
					// We're editing a component that's owned by a CDO, so set the CDO to the property editor (so that propagation works) and then filter to just the component property that we want to edit
					SelectionInfo.ObjectsForPropertyEditing.AddUnique(Owner);
					SelectionInfo.EditableComponentTemplates.Add(ActorComponent);
				}
				else
				{
					// We're editing a component that exists outside of a CDO, so just edit the component instance directly
					SelectionInfo.ObjectsForPropertyEditing.AddUnique(ActorComponent);
				}
			}
			else
			{
				// Editing any UObject*
				SelectionInfo.ObjectsForPropertyEditing.AddUnique(Object);
			}
		}
	}

	// By default, no property filtering
	SelectedObjectProperties.Empty();

	// Add to the property filter list for any editable component templates
	if(SelectionInfo.EditableComponentTemplates.Num())
	{
		for(auto CompIt = SelectionInfo.EditableComponentTemplates.CreateIterator(); CompIt; ++CompIt)
		{
			UActorComponent* EditableComponentTemplate = *CompIt;
			check(EditableComponentTemplate != NULL);

			// Add all properties belonging to the component template class
			for(TFieldIterator<UProperty> PropIt(EditableComponentTemplate->GetClass()); PropIt; ++PropIt)
			{
				UProperty* Property = *PropIt;
				check(Property != NULL);

				AddPropertiesRecursive(Property);
			}

			// Attempt to locate a matching property for the current component template
			for(auto ObjIt = SelectionInfo.ObjectsForPropertyEditing.CreateIterator(); ObjIt; ++ObjIt)
			{
				UObject* Object = *ObjIt;
				check(Object != NULL);

				if(Object != EditableComponentTemplate)
				{
					for(TFieldIterator<UObjectProperty> ObjPropIt(Object->GetClass()); ObjPropIt; ++ObjPropIt)
					{
						UObjectProperty* ObjectProperty = *ObjPropIt;
						check(ObjectProperty != NULL);

						// If the property value matches the current component template, add it as a selected property for filtering
						if(EditableComponentTemplate == ObjectProperty->GetObjectPropertyValue_InContainer(Object))
						{
							SelectedObjectProperties.Add(ObjectProperty);
						}
					}
				}
			}
		}
	}

	PropertyViewTitle = Options.ForcedTitle;
	bShowComponents = Options.bShowComponents;

	// Update our context-sensitive editing widget
	ContextualEditingBorderWidget->SetContent( MakeContextualEditingWidget(SelectionInfo, Options) );
}