Ejemplo n.º 1
0
void UK2Node_CustomEvent::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const
{
	Super::ValidateNodeDuringCompilation(MessageLog);

	UBlueprint* Blueprint = GetBlueprint();
	check(Blueprint != NULL);

	UFunction* ParentFunction = FindField<UFunction>(Blueprint->ParentClass, CustomFunctionName);
	// if this custom-event is overriding a function belonging to the blueprint's parent
	if (ParentFunction != NULL)
	{
		UObject const* const FuncOwner = ParentFunction->GetOuter();
		check(FuncOwner != NULL);

		// if this custom-event is attempting to override a native function, we can't allow that
		if (!FuncOwner->IsA(UBlueprintGeneratedClass::StaticClass()))
		{
			MessageLog.Error(*FString::Printf(*LOCTEXT("NativeFunctionConflict", "@@ name conflicts with a native '%s' function").ToString(), *FuncOwner->GetName()), this);
		}
		else 
		{
			UK2Node_CustomEvent const* OverriddenEvent = FindCustomEventNodeFromFunction(ParentFunction);
			// if the function that this is attempting to override is NOT another 
			// custom-event, then we want to error (a custom-event shouldn't override something different)
			if (OverriddenEvent == NULL)
			{
				MessageLog.Error(*FString::Printf(*LOCTEXT("NonCustomEventOverride", "@@ name conflicts with a '%s' function").ToString(), *FuncOwner->GetName()), this);
			}
			// else, we assume the user was attempting to override the parent's custom-event
			// the signatures could still be off, but FKismetCompilerContext::PrecompileFunction() should catch that
		}		
	}
}
void UK2Node_CallArrayFunction::GetArrayPins(TArray< FArrayPropertyPinCombo >& OutArrayPinInfo ) const
{
	OutArrayPinInfo.Empty();

	UFunction* TargetFunction = GetTargetFunction();
	check(TargetFunction);
	FString ArrayPointerMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayParam);
	TArray<FString> ArrayPinComboNames;
	ArrayPointerMetaData.ParseIntoArray(ArrayPinComboNames, TEXT(","), true);

	for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter)
	{
		TArray<FString> ArrayPinNames;
		Iter->ParseIntoArray(ArrayPinNames, TEXT("|"), true);

		FArrayPropertyPinCombo ArrayInfo;
		ArrayInfo.ArrayPin = FindPin(ArrayPinNames[0]);
		if(ArrayPinNames.Num() > 1)
		{
			ArrayInfo.ArrayPropPin = FindPin(ArrayPinNames[1]);
		}

		if(ArrayInfo.ArrayPin)
		{
			OutArrayPinInfo.Add(ArrayInfo);
		}
	}
}
Ejemplo n.º 3
0
// Disassemble all functions in any classes that have matching names.
void FKismetBytecodeDisassembler::DisassembleAllFunctionsInClasses(FOutputDevice& Ar, const FString& ClassnameSubstring)
{
	FKismetBytecodeDisassembler Disasm(Ar);
		
	for (TObjectIterator<UClass> ClassIter; ClassIter; ++ClassIter)
	{
		UClass* Class = *ClassIter;

		FString ClassName = Class->GetName();
		if (FCString::Strfind(*ClassName, *ClassnameSubstring))
		{
			Ar.Logf(TEXT("Processing class %s"), *ClassName);

			for (TFieldIterator<UFunction> FunctionIter(Class, EFieldIteratorFlags::ExcludeSuper); FunctionIter; ++FunctionIter)
			{
				UFunction* Function = *FunctionIter;
				FString FunctionName = Function->GetName();
				Ar.Logf(TEXT("  Processing function %s (%d bytes)"), *FunctionName, Function->Script.Num());

				Disasm.DisassembleStructure(Function);

				Ar.Logf(TEXT(""));
			}

			Ar.Logf(TEXT(""));
			Ar.Logf(TEXT("-----------"));
			Ar.Logf(TEXT(""));
		}

	}
}
/** Finds a property by name, starting in the specified scope; Validates property type and returns NULL along with emitting an error if there is a mismatch. */
UProperty* FKismetCompilerUtilities::FindPropertyInScope(UStruct* Scope, UEdGraphPin* Pin, FCompilerResultsLog& MessageLog, const UEdGraphSchema_K2* Schema, UClass* SelfClass)
{
	while (Scope != NULL)
	{
		for (TFieldIterator<UProperty> It(Scope, EFieldIteratorFlags::IncludeSuper); It; ++It)
		{
			UProperty* Property = *It;

			if (Property->GetName() == Pin->PinName)
			{
				if (FKismetCompilerUtilities::IsTypeCompatibleWithProperty(Pin, Property, MessageLog, Schema, SelfClass))
				{
					return Property;
				}
				else
				{
					// Exit now, we found one with the right name but the type mismatched (and there was a type mismatch error)
					return NULL;
				}
			}
		}

		// Functions don't automatically check their class when using a field iterator
		UFunction* Function = Cast<UFunction>(Scope);
		Scope = (Function != NULL) ? Cast<UStruct>(Function->GetOuter()) : NULL;
	}

	// Couldn't find the name
	MessageLog.Error(*LOCTEXT("PropertyNotFound_Error", "The property associated with @@ could not be found").ToString(), Pin);
	return NULL;
}
Ejemplo n.º 5
0
void FBlueprintStatsModule::DumpBlueprintStats()
{
	TArray<FBlueprintStatRecord> Records;
	for (TObjectIterator<UBlueprint> BlueprintIt; BlueprintIt; ++BlueprintIt)
	{
		UBlueprint* Blueprint = *BlueprintIt;

		new (Records) FBlueprintStatRecord(Blueprint);
	}


	// Now merge them
	FBlueprintStatRecord Aggregate(NULL);
	for (const FBlueprintStatRecord& SourceRecord : Records)
	{
		Aggregate.MergeAnotherRecordIn(SourceRecord);
	}

	// Sort the lists
	Aggregate.NodeCount.ValueSort(TGreater<int32>());
	Aggregate.FunctionCount.ValueSort(TGreater<int32>());
	Aggregate.FunctionOwnerCount.ValueSort(TGreater<int32>());
	Aggregate.RemoteMacroCount.ValueSort(TGreater<int32>());

	// Print out the merged record
	UE_LOG(LogBlueprintStats, Log, TEXT("Blueprint stats for %d blueprints in %s"), Records.Num(), GGameName);
	UE_LOG(LogBlueprintStats, Log, TEXT("%s"), *Aggregate.ToString(true));
	UE_LOG(LogBlueprintStats, Log, TEXT("%s"), *Aggregate.ToString(false));
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));

	// Print out the node list
	UE_LOG(LogBlueprintStats, Log, TEXT("NodeClass,NumInstances"));
	for (const auto& NodePair : Aggregate.NodeCount)
	{
		UE_LOG(LogBlueprintStats, Log, TEXT("%s,%d"), *(NodePair.Key->GetName()), NodePair.Value);
	}
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));

	// Print out the function list
	UE_LOG(LogBlueprintStats, Log, TEXT("FunctionPath,ClassName,FunctionName,NumInstances"));
	for (const auto& FunctionPair : Aggregate.FunctionCount)
	{
		UFunction* Function = FunctionPair.Key;
		UE_LOG(LogBlueprintStats, Log, TEXT("%s,%s,%s,%d"), *(Function->GetPathName()), *(Function->GetOuterUClass()->GetName()), *(Function->GetName()), FunctionPair.Value);
	}
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));

	// Print out the macro list
	UE_LOG(LogBlueprintStats, Log, TEXT("MacroPath,MacroName,NumInstances"));
	for (const auto& MacroPair : Aggregate.RemoteMacroCount)
	{
		UEdGraph* MacroGraph = MacroPair.Key;
		UE_LOG(LogBlueprintStats, Log, TEXT("%s,%s,%d"), *(MacroGraph->GetPathName()), *(MacroGraph->GetName()), MacroPair.Value);
	}
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));
}
		static void SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr)
		{
			UK2Node_LatentGameplayTaskCall* AsyncTaskNode = CastChecked<UK2Node_LatentGameplayTaskCall>(NewNode);
			if (FunctionPtr.IsValid())
			{
				UFunction* Func = FunctionPtr.Get();
				UObjectProperty* ReturnProp = CastChecked<UObjectProperty>(Func->GetReturnProperty());
						
				AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
				AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass();
				AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass;
			}
		}
	/**
	 * Finds the event version of a UFunction for a given Blueprint
	 *
	 * @param InBlueprint			The Blueprint to find the function within
	 * @param InFunction			The Function to find an event version of
	 *
	 * @return						Event Function used by the given Blueprint for the given Function
	 */
	UFunction* FindEventFunctionForClass(const UBlueprint* InBlueprint, const UFunction* InFunction)
	{
		// Look at all of the Blueprint parent's functions for an event
		for (TFieldIterator<UFunction> FunctionIt(InBlueprint->ParentClass, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt)
		{
			UFunction* Function = *FunctionIt;
			if(Function->GetName() == InFunction->GetName())
			{
				return Function;
			}
		}

		return NULL;
	}
Ejemplo n.º 8
0
void ANUTActor::ExecuteOnServer(UObject* InTargetObj, FString InTargetFunc)
{
	if (InTargetObj != NULL && InTargetFunc.Len() > 0)
	{
		// Only static functions can be used, so verify this is referencing a static function
		FName TargetFuncName = *InTargetFunc;
		UFunction* TargetFuncObj = InTargetObj->FindFunction(TargetFuncName);

		if (FString(TargetFuncName.ToString()).StartsWith(TEXT("UnitTestServer_"), ESearchCase::CaseSensitive))
		{
			if (TargetFuncObj != NULL)
			{
				if (TargetFuncObj->HasAnyFunctionFlags(FUNC_Static))
				{
					UObject* TargetObjCDO = (InTargetObj->HasAnyFlags(EObjectFlags::RF_ClassDefaultObject) ?
											InTargetObj :
											InTargetObj->GetClass()->GetDefaultObject());

					// Now that we've verified it's a static function, change the delegate object to the class default object
					// (as that is where static function must be executed, as there is no serverside unit test instance),
					// and then send it to the server
					TempDelegate.BindUFunction(TargetObjCDO, TargetFuncName);

					UDelegateProperty* DelProp = FindField<UDelegateProperty>(GetClass(), TEXT("TempDelegate"));

					FString DelString;
					DelProp->ExportTextItem(DelString, DelProp->ContainerPtrToValuePtr<uint8>(this), NULL, this, 0, NULL);

					ServerExecute(DelString);
				}
				else
				{
					UE_LOG(LogUnitTest, Log, TEXT("ExecuteOnServer: Only static functions can be passed to the server."));
				}
			}
			else
			{
				UE_LOG(LogUnitTest, Log, TEXT("ExecuteOnServer: Could not locate InTarget function."));
			}
		}
		else
		{
			UE_LOG(LogUnitTest, Log, TEXT("ExecuteOnServer: Target functions must be prefixed 'UnitTestServer_FuncName'"));
		}
	}
	else
	{
		UE_LOG(LogUnitTest, Log, TEXT("ExecuteOnServer: Target not specified"));
	}
}
Ejemplo n.º 9
0
void SGraphNodeK2CreateDelegate::CreateBelowWidgetControls(TSharedPtr<SVerticalBox> MainBox)
{
	if(UK2Node_CreateDelegate* Node = Cast<UK2Node_CreateDelegate>(GraphNode))
	{
		UFunction* FunctionSignature = Node->GetDelegateSignature();
		UClass* ScopeClass = Node->GetScopeClass();

		if(FunctionSignature && ScopeClass)
		{
			FunctionDataItems.Empty();
			for(TFieldIterator<UFunction> It(ScopeClass); It; ++It)
			{
				UFunction* Func = *It;
				if (Func && FunctionSignature->IsSignatureCompatibleWith(Func) && 
					UEdGraphSchema_K2::FunctionCanBeUsedInDelegate(Func))
				{
					TSharedPtr<FFunctionItemData> ItemData = MakeShareable(new FFunctionItemData());
					ItemData->Name = Func->GetFName();
					ItemData->Description = FunctionDescription(Func);
					FunctionDataItems.Add(ItemData);
				}
			}

			TSharedRef<SComboButton> SelectFunctionWidgetRef = SNew(SComboButton)
				.Method(EPopupMethod::UseCurrentWindow)
				.ButtonContent()
				[
					SNew(STextBlock)
						.Text(this, &SGraphNodeK2CreateDelegate::GetCurrentFunctionDescription)
				]
				.MenuContent()
				[
					SNew(SListView<TSharedPtr<FFunctionItemData> >)
						.ListItemsSource( &FunctionDataItems )
						.OnGenerateRow(this, &SGraphNodeK2CreateDelegate::HandleGenerateRowFunction)
						.OnSelectionChanged(this, &SGraphNodeK2CreateDelegate::OnFunctionSelected)
				];

			MainBox->AddSlot()
				.AutoHeight()
				.VAlign(VAlign_Fill)
				[
					SelectFunctionWidgetRef
				];

			SelectFunctionWidget = SelectFunctionWidgetRef;
		}
	}
}
Ejemplo n.º 10
0
UFunction* UK2Node_Event::FindEventSignatureFunction()
{
	UFunction* Function = FindField<UFunction>(EventSignatureClass, EventSignatureName);

	// First try remap table
	if ((Function == NULL) && (EventSignatureClass != NULL))
	{
		Function = Cast<UFunction>(FindRemappedField(EventSignatureClass, EventSignatureName));
		if( Function )
		{
			// Found a remapped property, update the node
			EventSignatureName = Function->GetFName();
			EventSignatureClass = Cast<UClass>(Function->GetOuter());
		}
	}

	return Function;
}
Ejemplo n.º 11
0
void UK2Node_Message::AllocateDefaultPins()
{
	UFunction* MessageNodeFunction = GetTargetFunction();
	// since we have branching logic in ExpandNode(), this has to be an impure
	// node with exec pins
	//
	// @TODO: make it so we can have impure message nodes using a custom 
	//        FNodeHandlingFunctor, instead of ExpandNode()
	if (MessageNodeFunction && MessageNodeFunction->HasAnyFunctionFlags(FUNC_BlueprintPure))
	{
		// Input - Execution Pin
		CreatePin(EGPD_Input,  UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, UEdGraphSchema_K2::PN_Execute);
		// Output - Execution Pin
		CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, UEdGraphSchema_K2::PN_Then);
	}

	Super::AllocateDefaultPins();
}
Ejemplo n.º 12
0
CefRefPtr<CefDictionaryValue> FWebJSScripting::ConvertObject(UObject* Object)
{
	CefRefPtr<CefDictionaryValue> Result = CefDictionaryValue::Create();
	RetainBinding(Object);

	UClass* Class = Object->GetClass();
	CefRefPtr<CefListValue> MethodNames = CefListValue::Create();
	int32 MethodIndex = 0;
	for (TFieldIterator<UFunction> FunctionIt(Class, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt)
	{
		UFunction* Function = *FunctionIt;
		MethodNames->SetString(MethodIndex++, *Function->GetName());
	}

	Result->SetString("$type", "uobject");
	Result->SetString("$id", *PtrToGuid(Object).ToString(EGuidFormats::Digits));
	Result->SetList("$methods", MethodNames);
	return Result;
}
Ejemplo n.º 13
0
void ASGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
	// HACK: workaround to inject CheckRelevance() into the BeginPlay sequence
	UFunction* Func = AActor::GetClass()->FindFunctionByName(FName(TEXT("ReceiveBeginPlay")));
	Func->FunctionFlags |= FUNC_Native;
	Func->SetNativeFunc((Native)&ASGameMode::BeginPlayMutatorHack);

	/* Spawn all mutators. */
	for (int32 i = 0; i < MutatorClasses.Num(); i++)
	{
		AddMutator(MutatorClasses[i]);
	}

	if (BaseMutator)
	{
		BaseMutator->InitGame(MapName, Options, ErrorMessage);
	}

	Super::InitGame(MapName, Options, ErrorMessage);
}
void UK2Node_MatineeController::ExpandNode(FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	if (SourceGraph != CompilerContext.ConsolidatedEventGraph)
	{
		CompilerContext.MessageLog.Error(*FString::Printf(*NSLOCTEXT("KismetCompiler", "InvalidNodeOutsideUbergraph_Error", "Unexpected node @@ found outside ubergraph.").ToString()), this);
		return;
	}

	Super::ExpandNode(CompilerContext, SourceGraph);

	if (MatineeActor != NULL)
	{
		UFunction* MatineeEventSig = FindObject<UFunction>(AMatineeActor::StaticClass(), TEXT("OnMatineeEvent__DelegateSignature"));
		check(MatineeEventSig != NULL);

		const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

		// Create event for each exec output pin
		for(int32 PinIdx=0; PinIdx<Pins.Num(); PinIdx++)
		{
			UEdGraphPin* MatineePin = Pins[PinIdx];
			if(MatineePin->Direction == EGPD_Output && MatineePin->PinType.PinCategory == Schema->PC_Exec)
			{
				FName EventFuncName = MatineeActor->GetFunctionNameForEvent( FName(*(MatineePin->PinName)) );

				UK2Node_Event* MatineeEventNode = CompilerContext.SpawnIntermediateNode<UK2Node_Event>(this, SourceGraph);
				MatineeEventNode->EventSignatureName = MatineeEventSig->GetFName();
				MatineeEventNode->EventSignatureClass = AMatineeActor::StaticClass();
				MatineeEventNode->CustomFunctionName = EventFuncName;
				MatineeEventNode->bInternalEvent = true;
				MatineeEventNode->AllocateDefaultPins();

				// Move connection from matinee output to event node output
				UEdGraphPin* EventOutputPin = Schema->FindExecutionPin(*MatineeEventNode, EGPD_Output);
				check(EventOutputPin != NULL);
				CompilerContext.CheckConnectionResponse(Schema->MovePinLinks(*MatineePin, *EventOutputPin), this);
			}
		}
	}

}
void UK2Node_CallArrayFunction::GetArrayTypeDependentPins(TArray<UEdGraphPin*>& OutPins) const
{
	OutPins.Empty();

	UFunction* TargetFunction = GetTargetFunction();
	check(TargetFunction);

	const FString DependentPinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayDependentParam);
	TArray<FString> TypeDependentPinNames;
	DependentPinMetaData.ParseIntoArray(TypeDependentPinNames, TEXT(","), true);

	for(TArray<UEdGraphPin*>::TConstIterator it(Pins); it; ++it)
	{
		UEdGraphPin* CurrentPin = *it;
		int32 ItemIndex = 0;
		if( CurrentPin && TypeDependentPinNames.Find(CurrentPin->PinName, ItemIndex) )
		{
			OutPins.Add(CurrentPin);
		}
	}
}
Ejemplo n.º 16
0
UGameplayAbility::UGameplayAbility(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	CostGameplayEffect = NULL;
	CooldownGameplayEffect = NULL;

	{
		static FName FuncName = FName(TEXT("K2_ShouldAbilityRespondToEvent"));
		UFunction* ShouldRespondFunction = GetClass()->FindFunctionByName(FuncName);
		HasBlueprintShouldAbilityRespondToEvent = ShouldRespondFunction && ShouldRespondFunction->GetOuter()->IsA(UBlueprintGeneratedClass::StaticClass());
	}
	{
		static FName FuncName = FName(TEXT("K2_CanActivateAbility"));
		UFunction* CanActivateFunction = GetClass()->FindFunctionByName(FuncName);
		HasBlueprintCanUse = CanActivateFunction && CanActivateFunction->GetOuter()->IsA(UBlueprintGeneratedClass::StaticClass());
	}
	{
		static FName FuncName = FName(TEXT("K2_ActivateAbility"));
		UFunction* ActivateFunction = GetClass()->FindFunctionByName(FuncName);
		HasBlueprintActivate = ActivateFunction && ActivateFunction->GetOuter()->IsA(UBlueprintGeneratedClass::StaticClass());
	}
	
#if WITH_EDITOR
	/** Autoregister abilities with the blueprint debugger in the editor.*/
	if (!HasAnyFlags(RF_ClassDefaultObject))
	{
		UBlueprint* BP = Cast<UBlueprint>(GetClass()->ClassGeneratedBy);
		if (BP && (BP->GetWorldBeingDebugged() == nullptr || BP->GetWorldBeingDebugged() == GetWorld()))
		{
			BP->SetObjectBeingDebugged(this);
		}
	}
#endif
}
Ejemplo n.º 17
0
// Finds a property by name, starting in the specified scope, returning NULL if it's not found
UProperty* FKismetCompilerUtilities::FindNamedPropertyInScope(UStruct* Scope, FName PropertyName)
{
	while (Scope != NULL)
	{
		for (TFieldIterator<UProperty> It(Scope, EFieldIteratorFlags::IncludeSuper); It; ++It)
		{
			UProperty* Property = *It;

			// If we match by name, and var is not deprecated...
			if (Property->GetFName() == PropertyName && !Property->HasAllPropertyFlags(CPF_Deprecated))
			{
				return Property;
			}
		}

		// Functions don't automatically check their class when using a field iterator
		UFunction* Function = Cast<UFunction>(Scope);
		Scope = (Function != NULL) ? Cast<UStruct>(Function->GetOuter()) : NULL;
	}

	return NULL;
}
	/**
	 * Checks if the passed in function is available as an event for the Blueprint
	 *
	 * @param InBlueprint		The Blueprint to check for validity with
	 * @param InFunction		The Function to check for being available as an event
	 *
	 * @return					Returns true if the function is available as an event in the Blueprint
	 */
	bool IsFunctionAvailableAsEvent(const UBlueprint* InBlueprint, const UFunction* InFunction)
	{
		// Build a list of all interface classes either implemented by this blueprint or through inheritance
		TArray<UClass*> InterfaceClasses;
		FBlueprintEditorUtils::FindImplementedInterfaces(InBlueprint, true, InterfaceClasses);
		InterfaceClasses.Add(InBlueprint->ParentClass);

		// Grab the list of events to be excluded from the override list
		const FString ExclusionListKeyName = TEXT("KismetHideOverrides");
		TArray<FString> ExcludedEventNames;
		if( InBlueprint->ParentClass->HasMetaData(*ExclusionListKeyName) )
		{
			const FString ExcludedEventNameString = InBlueprint->ParentClass->GetMetaData(*ExclusionListKeyName);
			ExcludedEventNameString.ParseIntoArray(ExcludedEventNames, TEXT(","), true);
		}

		const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
		if (K2Schema->FunctionCanBePlacedAsEvent(InFunction) && !ExcludedEventNames.Contains(InFunction->GetName()))
		{
			// Check all potential interface events using the class list we build above
			for(auto It = InterfaceClasses.CreateConstIterator(); It; It++)
			{
				const UClass* Interface = (*It);
				for (TFieldIterator<UFunction> FunctionIt(Interface, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt)
				{
					UFunction* Function = *FunctionIt;

					if(Function->GetName() == InFunction->GetName())
					{
						return true;
					}
				}
			}
		}

		return false;
	}
Ejemplo n.º 19
0
void SGameplayTagGraphPin::ParseDefaultValueData()
{
	FString TagString = GraphPinObj->GetDefaultAsString();

	UK2Node_CallFunction* CallFuncNode = Cast<UK2Node_CallFunction>(GraphPinObj->GetOuter());
	
	FilterString.Empty();
	if (CallFuncNode)
	{
		UFunction* ThisFunction = CallFuncNode->GetTargetFunction();
		if (ThisFunction)
		{
			if (ThisFunction->HasMetaData(TEXT("GameplayTagFilter")))
			{
				FilterString = ThisFunction->GetMetaData(TEXT("GameplayTagFilter"));
			}
		}
	}

	if (TagString.StartsWith(TEXT("(")) && TagString.EndsWith(TEXT(")")))
	{
		TagString = TagString.LeftChop(1);
		TagString = TagString.RightChop(1);
		TagString.Split("=", NULL, &TagString);
		if (TagString.StartsWith(TEXT("\"")) && TagString.EndsWith(TEXT("\"")))
		{
			TagString = TagString.LeftChop(1);
			TagString = TagString.RightChop(1);
		}
	}

	if (!TagString.IsEmpty())
	{
		FGameplayTag Tag = IGameplayTagsModule::Get().GetGameplayTagsManager().RequestGameplayTag(FName(*TagString));
		TagContainer->AddTag(Tag);
	}
}
Ejemplo n.º 20
0
FText UK2Node_Event::GetTooltipText() const
{
	UFunction* Function = FindField<UFunction>(EventSignatureClass, EventSignatureName);
	if (CachedTooltip.IsOutOfDate() && (Function != nullptr))
	{
		CachedTooltip = FText::FromString(UK2Node_CallFunction::GetDefaultTooltipForFunction(Function));

		if (bOverrideFunction || (CustomFunctionName == NAME_None))
		{
			FFormatNamedArguments Args;
			Args.Add(TEXT("FunctionTooltip"), (FText&)CachedTooltip);

			//@TODO: KISMETREPLICATION: Should do this for events with a custom function name, if it's a newly introduced replicating thingy
			if (Function->HasAllFunctionFlags(FUNC_BlueprintCosmetic) || IsCosmeticTickEvent())
			{
				Args.Add(
					TEXT("ClientString"),
					NSLOCTEXT("K2Node", "ClientEvent", "\n\nCosmetic. This event is only for cosmetic, non-gameplay actions.")
				);
				// FText::Format() is slow, so we cache this to save on performance
				CachedTooltip = FText::Format(LOCTEXT("Event_SubtitledTooltip", "{FunctionTooltip}\n\n{ClientString}"), Args);
			} 
			else if(Function->HasAllFunctionFlags(FUNC_BlueprintAuthorityOnly))
			{
				Args.Add(
					TEXT("ClientString"),
					NSLOCTEXT("K2Node", "ServerEvent", "\n\nAuthority Only. This event only fires on the server.")
				);
				// FText::Format() is slow, so we cache this to save on performance
				CachedTooltip = FText::Format(LOCTEXT("Event_SubtitledTooltip", "{FunctionTooltip}\n\n{ClientString}"), Args);
			}			
		}		
	}

	return CachedTooltip;
}
Ejemplo n.º 21
0
void UK2Node_Switch::CreateFunctionPin()
{
	// Set properties on the function pin
	const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
	UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, FunctionName.ToString());
	FunctionPin->bDefaultValueIsReadOnly = true;
	FunctionPin->bNotConnectable = true;
	FunctionPin->bHidden = true;

	UFunction* Function = FindField<UFunction>(FunctionClass, FunctionName);
	const bool bIsStaticFunc = Function->HasAllFunctionFlags(FUNC_Static);
	if (bIsStaticFunc)
	{
		// Wire up the self to the CDO of the class if it's not us
		if (UBlueprint* BP = GetBlueprint())
		{
			UClass* FunctionOwnerClass = Function->GetOuterUClass();
			if (!BP->SkeletonGeneratedClass->IsChildOf(FunctionOwnerClass))
			{
				FunctionPin->DefaultObject = FunctionOwnerClass->GetDefaultObject();
			}
		}
	}
}
Ejemplo n.º 22
0
void UK2Node_LatentAbilityCall::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
	// these nested loops are combing over the same classes/functions the
	// FBlueprintActionDatabase does; ideally we save on perf and fold this in
	// with FBlueprintActionDatabase, but we want to keep the modules separate
	for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
	{
		UClass* Class = *ClassIt;
		if (!Class->IsChildOf<UAbilityTask>() || Class->HasAnyClassFlags(CLASS_Abstract))
		{
			continue;
		}
		
		for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
		{
			UFunction* Function = *FuncIt;
			if (!Function->HasAnyFunctionFlags(FUNC_Static))
			{
				continue;
			}

			// to keep from needlessly instantiating a UBlueprintNodeSpawner, first   
			// check to make sure that the registrar is looking for actions of this type
			// (could be regenerating actions for a specific asset, and therefore the 
			// registrar would only accept actions corresponding to that asset)
			if (!ActionRegistrar.IsOpenForRegistration(Function))
			{
				continue;
			}

			UObjectProperty* ReturnProperty = Cast<UObjectProperty>(Function->GetReturnProperty());
			// see if the function is a static factory method for online proxies
			bool const bIsProxyFactoryMethod = (ReturnProperty != nullptr) && ReturnProperty->PropertyClass->IsChildOf<UAbilityTask>();
			
			if (bIsProxyFactoryMethod)
			{
				UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(Function);
				check(NodeSpawner != nullptr);
				NodeSpawner->NodeClass = GetClass();
				
				auto CustomizeAcyncNodeLambda = [](UEdGraphNode* NewNode, bool bIsTemplateNode, TWeakObjectPtr<UFunction> FunctionPtr)
				{
					UK2Node_LatentAbilityCall* AsyncTaskNode = CastChecked<UK2Node_LatentAbilityCall>(NewNode);
					if (FunctionPtr.IsValid())
					{
						UFunction* Func = FunctionPtr.Get();
						UObjectProperty* ReturnProp = CastChecked<UObjectProperty>(Func->GetReturnProperty());
						
						AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
						AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass();
						AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass;
					}
				};
				
				TWeakObjectPtr<UFunction> FunctionPtr = Function;
				NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(CustomizeAcyncNodeLambda, FunctionPtr);
				
				// @TODO: since this can't be folded into FBlueprintActionDatabase, we
				//        need a way to associate these spawners with a certain class
				ActionRegistrar.AddBlueprintAction(Function, NodeSpawner);
			}
		}
	}
}
Ejemplo n.º 23
0
void UK2Node_LatentAbilityCall::CreatePinsForClass(UClass* InClass)
{
	check(InClass != NULL);

	const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();

	const UObject* const ClassDefaultObject = InClass->GetDefaultObject(false);

	SpawnParmPins.Empty();

	// Tasks can hide spawn parameters by doing meta = (HideSpawnParms="PropertyA,PropertyB")
	// (For example, hide Instigator in situations where instigator is not relevant to your task)
	
	TArray<FString> IgnorePropertyList;
	{
		UFunction* ProxyFunction = ProxyFactoryClass->FindFunctionByName(ProxyFactoryFunctionName);

		FString IgnorePropertyListStr = ProxyFunction->GetMetaData(FName(TEXT("HideSpawnParms")));
	
		if (!IgnorePropertyListStr.IsEmpty())
		{
			IgnorePropertyListStr.ParseIntoArray(IgnorePropertyList, TEXT(","), true);
		}
	}

	for (TFieldIterator<UProperty> PropertyIt(InClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
	{
		UProperty* Property = *PropertyIt;
		UClass* PropertyClass = CastChecked<UClass>(Property->GetOuter());
		const bool bIsDelegate = Property->IsA(UMulticastDelegateProperty::StaticClass());
		const bool bIsExposedToSpawn = UEdGraphSchema_K2::IsPropertyExposedOnSpawn(Property);
		const bool bIsSettableExternally = !Property->HasAnyPropertyFlags(CPF_DisableEditOnInstance);

		if (bIsExposedToSpawn &&
			!Property->HasAnyPropertyFlags(CPF_Parm) &&
			bIsSettableExternally &&
			Property->HasAllPropertyFlags(CPF_BlueprintVisible) &&
			!bIsDelegate && 
			!IgnorePropertyList.Contains(Property->GetName()) &&
			(FindPin(Property->GetName()) == nullptr) )
		{


			UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName());
			const bool bPinGood = (Pin != NULL) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType);
			SpawnParmPins.Add(Pin);

			if (ClassDefaultObject && Pin && K2Schema->PinDefaultValueIsEditable(*Pin))
			{
				FString DefaultValueAsString;
				const bool bDefaultValueSet = FBlueprintEditorUtils::PropertyValueToString(Property, reinterpret_cast<const uint8*>(ClassDefaultObject), DefaultValueAsString);
				check(bDefaultValueSet);
				K2Schema->TrySetDefaultValue(*Pin, DefaultValueAsString);
			}

			// Copy tooltip from the property.
			if (Pin != nullptr)
			{
				K2Schema->ConstructBasicPinTooltip(*Pin, Property->GetToolTipText(), Pin->PinToolTip);
			}
		}
	}
}
Ejemplo n.º 24
0
void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	UEdGraphPin* ExecPin = Schema->FindExecutionPin(*this, EGPD_Input);
	const bool bExecPinConnected = ExecPin && (ExecPin->LinkedTo.Num() > 0);
	UEdGraphPin* ThenPin = Schema->FindExecutionPin(*this, EGPD_Output);
	const bool bThenPinConnected = ThenPin && (ThenPin->LinkedTo.Num() > 0);

	// Skip ourselves if our exec isn't wired up
	if (bExecPinConnected)
	{
		// Make sure our interface is valid
		if (FunctionReference.GetMemberParentClass(this) == NULL)
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalid_Error", "Message node @@ has an invalid interface.").ToString()), this);
			return;
		}

		UFunction* MessageNodeFunction = GetTargetFunction();
		if (MessageNodeFunction == NULL)
		{
			//@TODO: Why do this here in teh compiler, it's already done on AllocateDefaultPins() during on-load node reconstruction
			MessageNodeFunction = Cast<UFunction>(UK2Node::FindRemappedField(FunctionReference.GetMemberParentClass(this), FunctionReference.GetMemberName()));
		}

		if (MessageNodeFunction == NULL)
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalidFunction_Error", "Unable to find function with name %s for Message node @@.").ToString(), *(FunctionReference.GetMemberName().ToString())), this);
			return;
		}

		// Check to make sure we have a target
		UEdGraphPin* MessageSelfPin = Schema->FindSelfPin(*this, EGPD_Input);
		if( !MessageSelfPin || MessageSelfPin->LinkedTo.Num() == 0 )
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeSelfPin_Error", "Message node @@ must have a valid target or reference to self.").ToString()), this);
			return;
		}

		// First, create an internal cast-to-interface node
		UK2Node_DynamicCast* CastToInterfaceNode = CompilerContext.SpawnIntermediateNode<UK2Node_DynamicCast>(this, SourceGraph);
		CastToInterfaceNode->TargetType = MessageNodeFunction->GetOuterUClass();
		CastToInterfaceNode->SetPurity(false);
		CastToInterfaceNode->AllocateDefaultPins();

		UEdGraphPin* CastToInterfaceResultPin = CastToInterfaceNode->GetCastResultPin();
		if( !CastToInterfaceResultPin )
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("InvalidInterfaceClass_Error", "Node @@ has an invalid target interface class").ToString(), this);
			return;
		}

		CastToInterfaceResultPin->PinType.PinSubCategoryObject = *CastToInterfaceNode->TargetType;

		if (ExecPin != nullptr)
		{
			UEdGraphPin* CastExecInput = CastToInterfaceNode->GetExecPin();
			check(CastExecInput != nullptr);

			// Wire up the connections
			CompilerContext.MovePinLinksToIntermediate(*ExecPin, *CastExecInput);
		}

		UEdGraphPin* CastToInterfaceSourceObjectPin = CastToInterfaceNode->GetCastSourcePin();
		CompilerContext.MovePinLinksToIntermediate(*MessageSelfPin, *CastToInterfaceSourceObjectPin);

		// Next, create the function call node
		UK2Node_CallFunction* FunctionCallNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
		FunctionCallNode->bIsInterfaceCall = true;
		FunctionCallNode->FunctionReference = FunctionReference;
		FunctionCallNode->AllocateDefaultPins();

		UEdGraphPin* CastToInterfaceValidPin = CastToInterfaceNode->GetValidCastPin();
		check(CastToInterfaceValidPin != nullptr);

		UEdGraphPin* LastOutCastFaildPin   = CastToInterfaceNode->GetInvalidCastPin();
		check(LastOutCastFaildPin != nullptr);
		UEdGraphPin* LastOutCastSuccessPin = CastToInterfaceValidPin;
		// Wire up the connections
		if (UEdGraphPin* CallFunctionExecPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Input))
		{
			CastToInterfaceValidPin->MakeLinkTo(CallFunctionExecPin);
			LastOutCastSuccessPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Output);
		}
		
		// Self pin
		UEdGraphPin* FunctionCallSelfPin = Schema->FindSelfPin(*FunctionCallNode, EGPD_Input);
		CastToInterfaceResultPin->MakeLinkTo(FunctionCallSelfPin);

		UFunction* ArrayClearFunction = UKismetArrayLibrary::StaticClass()->FindFunctionByName(FName(TEXT("Array_Clear")));
		check(ArrayClearFunction);

		bool const bIsPureFunc = Super::IsNodePure();
		// Variable pins - Try to associate variable inputs to the message node with the variable inputs and outputs to the call function node
		for( int32 i = 0; i < Pins.Num(); i++ )
		{
			UEdGraphPin* CurrentPin = Pins[i];
			if( CurrentPin && (CurrentPin->PinType.PinCategory != Schema->PC_Exec) && (CurrentPin->PinName != Schema->PN_Self) )
			{
				// Try to find a match for the pin on the function call node
				UEdGraphPin* FunctionCallPin = FunctionCallNode->FindPin(CurrentPin->PinName);
				if( FunctionCallPin )
				{
					// Move pin links if the pin is connected...
					CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *FunctionCallPin);

					// when cast fails all return values must be cleared.
					if (EEdGraphPinDirection::EGPD_Output == CurrentPin->Direction)
					{
						UEdGraphPin* VarOutPin = FunctionCallPin;
						if (bIsPureFunc)
						{
							// since we cannot directly use the output from the
							// function call node (since it is pure, and invoking
							// it with a null target would cause an error), we 
							// have to use a temporary variable in it's place...
							UK2Node_TemporaryVariable* TempVar = CompilerContext.SpawnIntermediateNode<UK2Node_TemporaryVariable>(this, SourceGraph);
							TempVar->VariableType = CurrentPin->PinType;
							TempVar->AllocateDefaultPins();

							VarOutPin = TempVar->GetVariablePin();
							// nodes using the function's outputs directly, now
							// use this TempVar node instead
							CompilerContext.MovePinLinksToIntermediate(*FunctionCallPin, *VarOutPin);

							// on a successful cast, the temp var is filled with
							// the function's value, on a failed cast, the var 
							// is filled with a default value (DefaultValueNode, 
							// below)... this is the node for the success case:
							UK2Node_AssignmentStatement* AssignTempVar = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph);
							AssignTempVar->AllocateDefaultPins();
							
							// assign the output from the pure function node to
							// the TempVar (either way, this message node is 
							// returning the TempVar's value, so on a successful 
							// cast we want it to have the function's result)
							UEdGraphPin* ValueInPin = AssignTempVar->GetValuePin();
							Schema->TryCreateConnection(FunctionCallPin, ValueInPin);
							AssignTempVar->PinConnectionListChanged(ValueInPin);

							UEdGraphPin* VarInPin = AssignTempVar->GetVariablePin();
							Schema->TryCreateConnection(VarOutPin, VarInPin);
							AssignTempVar->PinConnectionListChanged(VarInPin);
							// fold this AssignTempVar node into the cast's 
							// success execution chain
							Schema->TryCreateConnection(AssignTempVar->GetExecPin(), LastOutCastSuccessPin);
							LastOutCastSuccessPin = AssignTempVar->GetThenPin();
						}

						UK2Node* DefaultValueNode = NULL;
						UEdGraphPin* DefaultValueThenPin = NULL;
						if (CurrentPin->PinType.bIsArray)
						{
							UK2Node_CallArrayFunction* ClearArray = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph);
							DefaultValueNode = ClearArray;
							ClearArray->SetFromFunction(ArrayClearFunction);
							ClearArray->AllocateDefaultPins();

							UEdGraphPin* ArrayPin = ClearArray->GetTargetArrayPin();
							check(ArrayPin);
							Schema->TryCreateConnection(ArrayPin, VarOutPin);
							ClearArray->PinConnectionListChanged(ArrayPin);

							DefaultValueThenPin = ClearArray->GetThenPin();
						} 
						else
						{
							UK2Node_AssignmentStatement* AssignDefaultValue = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph);
							DefaultValueNode = AssignDefaultValue;
							AssignDefaultValue->AllocateDefaultPins();

							Schema->TryCreateConnection(AssignDefaultValue->GetVariablePin(), VarOutPin);
							AssignDefaultValue->PinConnectionListChanged(AssignDefaultValue->GetVariablePin());
							Schema->SetPinDefaultValueBasedOnType(AssignDefaultValue->GetValuePin());

							DefaultValueThenPin = AssignDefaultValue->GetThenPin();
						}

						UEdGraphPin* DefaultValueExecPin = DefaultValueNode->GetExecPin();
						check(DefaultValueExecPin);
						Schema->TryCreateConnection(DefaultValueExecPin, LastOutCastFaildPin);
						LastOutCastFaildPin = DefaultValueThenPin;
						check(LastOutCastFaildPin);
					}
				}
				else
				{
					UE_LOG(LogK2Compiler, Log, TEXT("%s"), *LOCTEXT("NoPinConnectionFound_Error", "Unable to find connection for pin!  Check AllocateDefaultPins() for consistency!").ToString());
				}
			}
		}

		if( bThenPinConnected )
		{
			check(LastOutCastFaildPin != nullptr);
			// Failure case for the cast runs straight through to the exit
			CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *LastOutCastFaildPin);

			check(LastOutCastSuccessPin != nullptr);
			// Copy all links from the invalid cast case above to the call function node
			CompilerContext.MovePinLinksToIntermediate(*ThenPin, *LastOutCastSuccessPin);
		}
	}

	// Break all connections to the original node, so it will be pruned
	BreakAllNodeLinks();
}
Ejemplo n.º 25
0
bool FWebJSScripting::HandleExecuteUObjectMethodMessage(CefRefPtr<CefListValue> MessageArguments)
{
	FGuid ObjectKey;
	// Message arguments are Name, Value, bGlobal
	if (MessageArguments->GetSize() != 4
		|| MessageArguments->GetType(0) != VTYPE_STRING
		|| MessageArguments->GetType(1) != VTYPE_STRING
		|| MessageArguments->GetType(2) != VTYPE_STRING
		|| MessageArguments->GetType(3) != VTYPE_LIST
		)
	{
		// Wrong message argument types or count
		return false;
	}

	if (!FGuid::Parse(FString(MessageArguments->GetString(0).ToWString().c_str()), ObjectKey))
	{
		// Invalid GUID
		return false;
	}

	// Get the promise callback and use that to report any results from executing this function.
	FGuid ResultCallbackId;
	if (!FGuid::Parse(FString(MessageArguments->GetString(2).ToWString().c_str()), ResultCallbackId))
	{
		// Invalid GUID
		return false;
	}

	UObject* Object = GuidToPtr(ObjectKey);
	if (Object == nullptr)
	{
		// Unknown uobject id
		InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject ID"));
		return true;
	}

	FName MethodName = MessageArguments->GetString(1).ToWString().c_str();
	UFunction* Function = Object->FindFunction(MethodName);
	if (!Function)
	{
		InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject Function"));
		return true;
	}
	// Coerce arguments to function arguments.
	uint16 ParamsSize = Function->ParmsSize;
	TArray<uint8> Params;
	UProperty* ReturnParam = nullptr;
	UProperty* PromiseParam = nullptr;

	// Convert cef argument list to a dictionary, so we can use FStructDeserializer to convert it for us
	if (ParamsSize > 0)
	{
		CefRefPtr<CefDictionaryValue> NamedArgs = CefDictionaryValue::Create();
		int32 CurrentArg = 0;
		CefRefPtr<CefListValue> CefArgs = MessageArguments->GetList(3);
		for ( TFieldIterator<UProperty> It(Function); It; ++It )
		{
			UProperty* Param = *It;
			if (Param->PropertyFlags & CPF_Parm)
			{
				if (Param->PropertyFlags & CPF_ReturnParm)
				{
					ReturnParam = Param;
				}
				else
				{
					UStructProperty *StructProperty = Cast<UStructProperty>(Param);
					if (StructProperty && StructProperty->Struct->IsChildOf(FWebJSResponse::StaticStruct()))
					{
						PromiseParam = Param;
					}
					else
					{
						CopyContainerValue(NamedArgs, CefArgs, CefString(*Param->GetName()), CurrentArg);
						CurrentArg++;
					}
				}
			}
		}

		// UFunction is a subclass of UStruct, so we can treat the arguments as a struct for deserialization
		Params.AddUninitialized(ParamsSize);
		Function->InitializeStruct(Params.GetData());
		FWebJSStructDeserializerBackend Backend = FWebJSStructDeserializerBackend(SharedThis(this), NamedArgs);
		FStructDeserializer::Deserialize(Params.GetData(), *Function, Backend);
	}

	if (PromiseParam)
	{
		FWebJSResponse* PromisePtr = PromiseParam->ContainerPtrToValuePtr<FWebJSResponse>(Params.GetData());
		if (PromisePtr)
		{
			*PromisePtr = FWebJSResponse(SharedThis(this), ResultCallbackId);
		}
	}

	Object->ProcessEvent(Function, Params.GetData());
	CefRefPtr<CefListValue> Results = CefListValue::Create();

	if ( ! PromiseParam ) // If PromiseParam is set, we assume that the UFunction will ensure it is called with the result
	{
		if ( ReturnParam )
		{
			FStructSerializerPolicies ReturnPolicies;
			ReturnPolicies.PropertyFilter = [&](const UProperty* CandidateProperty, const UProperty* ParentProperty)
			{
				return ParentProperty != nullptr || CandidateProperty == ReturnParam;
			};
			FWebJSStructSerializerBackend ReturnBackend(SharedThis(this));
			FStructSerializer::Serialize(Params.GetData(), *Function, ReturnBackend, ReturnPolicies);
			CefRefPtr<CefDictionaryValue> ResultDict = ReturnBackend.GetResult();

			// Extract the single return value from the serialized dictionary to an array
			CopyContainerValue(Results, ResultDict, 0, CefString(*ReturnParam->GetName()));
		}
		InvokeJSFunction(ResultCallbackId, Results, false);
	}
	return true;
}
Ejemplo n.º 26
0
/**
 * Finds the metadata for the property specified
 *
 * @param	Prop	the property to search for
 *
 * @return	pointer to the metadata for the property specified, or NULL
 *			if the property doesn't exist in the list (for example, if it
 *			is declared in a package that is already compiled and has had its
 *			source stripped)
 */
FTokenData* FClassMetaData::FindTokenData( UProperty* Prop )
{
	check(Prop);

	FTokenData* Result = nullptr;
	UObject* Outer = Prop->GetOuter();
	UClass* OuterClass = nullptr;
	if (Outer->IsA<UStruct>())
	{
		Result = GlobalPropertyData.Find(Prop);

		if (Result == nullptr)
		{
			OuterClass = Cast<UClass>(Outer);

			if (Result == nullptr && OuterClass != nullptr && OuterClass->GetSuperClass() != OuterClass)
			{
				OuterClass = OuterClass->GetSuperClass();
			}
		}
	}
	else
	{
		UFunction* OuterFunction = Cast<UFunction>(Outer);
		if ( OuterFunction != NULL )
		{
			// function parameter, return, or local property
			FFunctionData* FuncData = nullptr;
			if (FFunctionData::TryFindForFunction(OuterFunction, FuncData))
			{
				FPropertyData& FunctionParameters = FuncData->GetParameterData();
				Result = FunctionParameters.Find(Prop);
				if ( Result == NULL )
				{
					Result = FuncData->GetReturnTokenData();
				}
			}
			else
			{
				OuterClass = OuterFunction->GetOwnerClass();
			}
		}
		else
		{
			// struct property
			UScriptStruct* OuterStruct = Cast<UScriptStruct>(Outer);
			check(OuterStruct != NULL);

			TScopedPointer<FStructData>* pStructInfo = StructData.Find(OuterStruct);
			if ( pStructInfo != NULL )
			{
				FStructData* StructInfo = pStructInfo->GetOwnedPointer();
				check(StructInfo);

				FPropertyData& StructProperties = StructInfo->GetStructPropertyData();
				Result = StructProperties.Find(Prop);
			}
			else
			{
				OuterClass = OuterStruct->GetOwnerClass();
			}
		}
	}

	if (Result == nullptr && OuterClass != nullptr)
	{
		FClassMetaData* SuperClassData = GScriptHelper.FindClassData(OuterClass);
		if (SuperClassData && SuperClassData != this)
		{
			Result = SuperClassData->FindTokenData(Prop);
		}
	}

	return Result;
}
void FEditorUtilityInstanceDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayoutBuilder)
{
    SelectedObjectsList = DetailLayoutBuilder.GetDetailsView().GetSelectedObjects();

    // Hide some useless categories
    //@TODO: How to hide Actors, Layers, etc...?

    // Build a list of unique selected blutilities
    TArray<UClass*> UniqueBlutilityClasses;
    bool bFoundAnyCDOs = false;

    for (auto SelectedObjectIt = SelectedObjectsList.CreateConstIterator(); SelectedObjectIt; ++SelectedObjectIt)
    {
        UObject* Object = (*SelectedObjectIt).Get();

        if (!Object->HasAnyFlags(RF_ClassDefaultObject))
        {
            UClass* ObjectClass = Object->GetClass();

            if (UEditorUtilityBlueprint* Blutility = Cast<UEditorUtilityBlueprint>(ObjectClass->ClassGeneratedBy))
            {
                UniqueBlutilityClasses.Add(ObjectClass);
            }
        }
        else
        {
            bFoundAnyCDOs = true;
        }
    }

    // Run thru each one
    UniqueBlutilityClasses.Sort(FCompareClassNames());
    for (auto ClassIt = UniqueBlutilityClasses.CreateIterator(); ClassIt; ++ClassIt)
    {
        UClass* Class = *ClassIt;

        FString CategoryName = FString::Printf(TEXT("%sActions"), *Class->ClassGeneratedBy->GetName());
        IDetailCategoryBuilder& ActionsCategory = DetailLayoutBuilder.EditCategory(*CategoryName);

        const APlacedEditorUtilityBase* PlacedActorCDO = Cast<const APlacedEditorUtilityBase>(Class->GetDefaultObject());
        if (PlacedActorCDO)
        {
            ActionsCategory.AddCustomRow( PlacedActorCDO->HelpText )
            [
                SNew(STextBlock)
                .Text(PlacedActorCDO->HelpText)
            ];
        }

        const UGlobalEditorUtilityBase* GlobalBlutilityCDO = Cast<const UGlobalEditorUtilityBase>(Class->GetDefaultObject());
        if (GlobalBlutilityCDO)
        {
            ActionsCategory.AddCustomRow( GlobalBlutilityCDO->HelpText )
            [
                SNew(STextBlock)
                .Text(GlobalBlutilityCDO->HelpText)
            ];
        }

        TSharedRef<SWrapBox> WrapBox = SNew(SWrapBox).UseAllottedWidth(true);
        int32 NumButtons = 0;

        for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::IncludeSuper); FuncIt; ++FuncIt)
        {
            UFunction* Function = *FuncIt;

            const bool bCanExecute = (Function->NumParms == 0) && Function->HasAllFunctionFlags(FUNC_Exec);

            if (bCanExecute)
            {
                ++NumButtons;

                const FString ButtonCaption = FName::NameToDisplayString(*Function->GetName(), false);

                //@TODO: Expose the code in UK2Node_CallFunction::GetUserFacingFunctionName / etc...
                FString Tooltip = Function->GetToolTipText().ToString();
                if (Tooltip.IsEmpty())
                {
                    Tooltip = Function->GetName();
                }

                TWeakObjectPtr<UFunction> WeakFunctionPtr(Function);

                WrapBox->AddSlot()
                [
                    SNew(SButton)
                    .Text(ButtonCaption)
                    .OnClicked(	FOnClicked::CreateSP(this, &FEditorUtilityInstanceDetails::OnExecuteAction, WeakFunctionPtr) )
                    .ToolTipText(Tooltip)
                ];

            }
        }

        if (NumButtons > 0)
        {
            ActionsCategory.AddCustomRow(TEXT(""))
            [
                WrapBox
            ];
        }
    }

    // Hide the hint property
    if (!bFoundAnyCDOs)
    {
        DetailLayoutBuilder.HideProperty(TEXT("HelpText"));
    }
}
Ejemplo n.º 28
0
void UK2Node_LiveEditObject::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	UEdGraphPin *SourceExecPin = GetExecPin();
	UEdGraphPin *SourceThenPin = GetThenPin();
	UEdGraphPin *SourceBlueprintPin = GetBlueprintPin();
	UEdGraphPin *SourceBaseClassPin = GetBaseClassPin();
	UEdGraphPin *SourceDescriptionPin = GetDescriptionPin();
	UEdGraphPin *SourcePermittedBindingsPin = GetPermittedBindingsPin();
	UEdGraphPin *SourceOnMidiInputPin = GetOnMidiInputPin();

	UEdGraphPin *SourceVariablePin = GetVariablePin();
	if(NULL == SourceVariablePin)
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBlueprint_Error", "LiveEdit node @@ must have a blueprint specified and a variable selected to tune.").ToString(), this);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		BreakAllNodeLinks();
		return;
	}

	UClass* SpawnClass = GetClassToSpawn();
	if(NULL == SpawnClass)
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBaseClass_Error", "LiveEdit node @@ must have a Base Class specified.").ToString(), this);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		BreakAllNodeLinks();
		return;
	}

	if ( SourcePermittedBindingsPin->LinkedTo.Num() == 0 )
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBinding_Error", "LiveEdit node @@ must specify Permitted Bindings.").ToString(), this);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		BreakAllNodeLinks();
		return;
	}

	//sanity check the VariablePin value
	{
		UProperty *Property = UK2Node_LiveEditObjectStatics::GetPropertyByName( SpawnClass, *SourceVariablePin->DefaultValue );
		if ( Property == NULL || !Property->IsA(UNumericProperty::StaticClass()) )
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeInvalidVariable_Error", "LiveEdit node @@ must have a valid variable selected.").ToString(), this);
			// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
			BreakAllNodeLinks();
			return;
		}
	}

	//hooks to pins that are generated after a BaseClass is set
	UEdGraphPin *DeltaMultPin = GetDeltaMultPin();
	UEdGraphPin *ShouldClampPin = GetShouldClampPin();
	UEdGraphPin *ClampMinPin = GetClampMinPin();
	UEdGraphPin *ClampMaxPin = GetClampMaxPin();

	UK2Node_Self *SelfNode  = CompilerContext.SpawnIntermediateNode<UK2Node_Self>(this,SourceGraph);
	SelfNode->AllocateDefaultPins();
	UEdGraphPin *SelfNodeThenPin = SelfNode->FindPinChecked(Schema->PN_Self);

	FString EventNameGuid = GetEventName();
		
	//Create the registration part of the LiveEditor binding process
	{
		UK2Node_CallFunction *RegisterForMIDINode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		RegisterForMIDINode->FunctionReference.SetExternalMember( TEXT("RegisterForLiveEditEvent"), ULiveEditorKismetLibrary::StaticClass() );
		RegisterForMIDINode->AllocateDefaultPins();

		UEdGraphPin *ExecPin = RegisterForMIDINode->GetExecPin();
		CompilerContext.MovePinLinksToIntermediate(*SourceExecPin, *ExecPin);

		UEdGraphPin *ThenPin = RegisterForMIDINode->GetThenPin();
		CompilerContext.MovePinLinksToIntermediate(*SourceThenPin, *ThenPin);

		UEdGraphPin *TargetPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("Target")) );
		TargetPin->MakeLinkTo(SelfNodeThenPin);

		UEdGraphPin *EventNamePin = RegisterForMIDINode->FindPinChecked( FString(TEXT("EventName")) );
		EventNamePin->DefaultValue = EventNameGuid;
		
		UEdGraphPin *DescriptionPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("Description")) );
		CompilerContext.CopyPinLinksToIntermediate( *SourceDescriptionPin, *DescriptionPin);

		UEdGraphPin *PermittedBindingsPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("PermittedBindings")) );
		CompilerContext.CopyPinLinksToIntermediate( *SourcePermittedBindingsPin, *PermittedBindingsPin);
	}

	//Create the event handling part of the LiveEditor binding process
	{
		//
		//the event itself
		//
		UFunction *EventMIDISignature = GetEventMIDISignature();
		UK2Node_Event* EventNode = CompilerContext.SpawnIntermediateNode<UK2Node_Event>(this, SourceGraph);
		check(EventNode);
		EventNode->EventSignatureClass = Cast<UClass>(EventMIDISignature->GetOuter());
		EventNode->EventSignatureName = EventMIDISignature->GetFName();
		EventNode->CustomFunctionName = *EventNameGuid;
		EventNode->bInternalEvent = true;
		EventNode->AllocateDefaultPins();

		// Cache these out because we'll connect the sequence to it
		UEdGraphPin *EventThenPin = EventNode->FindPinChecked( Schema->PN_Then );
		UEdGraphPin *EventDeltaPin = EventNode->FindPinChecked( FString(TEXT("Delta")) );
		UEdGraphPin *EventMidiValuePin = EventNode->FindPinChecked( FString(TEXT("MidiValue")) );
		UEdGraphPin *EventControlTypePin = EventNode->FindPinChecked( FString(TEXT("ControlType")) );


		//
		// Check if Blueprint is NULL
		//
		UEdGraphPin *CompareBlueprintToNullBranchThenPin = NULL;
		{
			UK2Node_CallFunction *CompareBlueprintToNullNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
			CompareBlueprintToNullNode->FunctionReference.SetExternalMember( TEXT("NotEqual_ObjectObject"), UKismetMathLibrary::StaticClass() );
			CompareBlueprintToNullNode->AllocateDefaultPins();

			//Set A Pin to the Blueprint Pin
			UEdGraphPin *CompareBlueprintToNullAPin = CompareBlueprintToNullNode->FindPinChecked( FString(TEXT("A")) );
			CompilerContext.CopyPinLinksToIntermediate( *SourceBlueprintPin, *CompareBlueprintToNullAPin);

			// hook for Compare Blueprint to NULL result
			UEdGraphPin *CompareBlueprintToNullResultPin = CompareBlueprintToNullNode->GetReturnValuePin();

			// Create the BRANCH that will drive the comparison
			UK2Node_IfThenElse* CompareBlueprintToNullBranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph);
			CompareBlueprintToNullBranchNode->AllocateDefaultPins();

			//hook up the condition
			CompareBlueprintToNullResultPin->MakeLinkTo( CompareBlueprintToNullBranchNode->GetConditionPin() );

			//hook event to the branck input
			EventThenPin->MakeLinkTo( CompareBlueprintToNullBranchNode->GetExecPin() );

			//cache ot the THEN pin for later linkup
			CompareBlueprintToNullBranchThenPin = CompareBlueprintToNullBranchNode->GetThenPin();
		}

		//
		// Get Class Default Object
		//
		UK2Node_CallFunction *GetClassDefaultObjectNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		GetClassDefaultObjectNode->FunctionReference.SetExternalMember( TEXT("GetBlueprintClassDefaultObject"), ULiveEditorKismetLibrary::StaticClass() );
		GetClassDefaultObjectNode->AllocateDefaultPins();

		UEdGraphPin *GetClassDefaultObjectBlueprintPin = GetClassDefaultObjectNode->FindPinChecked( TEXT("Blueprint") );
		CompilerContext.CopyPinLinksToIntermediate( *SourceBlueprintPin, *GetClassDefaultObjectBlueprintPin);

		//hook for later -> the pointer to the ClassDefaultObject of our BlueprintPin
		UEdGraphPin *GetClassDefaultObjectResultPin = GetClassDefaultObjectNode->GetReturnValuePin();


		//
		// Compare to BaseClass to make sure that the target Blueprint IsA(BaseClass)
		//
		UEdGraphPin *ClassIsChildOfBranchThenPin = NULL;
		{
			//
			//we need to get the class of the Blueprint pin
			UK2Node_CallFunction *GetClassNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
			GetClassNode->FunctionReference.SetExternalMember( TEXT("GetObjectClass"), UGameplayStatics::StaticClass() );
			GetClassNode->AllocateDefaultPins();

			//Pin in the GetClassDefaultObjectResultPin to the Object Parameter of the GetObjectClass FUNCTION
			//we want to make sure that the Class of the DEFAULT_OBJECT IsA( BaseClass )
			UEdGraphPin *GetClassObjectPin = GetClassNode->FindPinChecked( FString(TEXT("Object")) );
			GetClassDefaultObjectResultPin->MakeLinkTo( GetClassObjectPin );

			//hook for the Class result
			UEdGraphPin *GetClassReturnValuePin = GetClassNode->GetReturnValuePin();

			//
			//the ClassIsChildOf FUNCTION
			UK2Node_CallFunction *ClassIsChildOfNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
			ClassIsChildOfNode->FunctionReference.SetExternalMember( TEXT("ClassIsChildOf"), UKismetMathLibrary::StaticClass() );
			ClassIsChildOfNode->AllocateDefaultPins();

			//hook up the test pin
			UEdGraphPin *ClassIsChildOfTestPin = ClassIsChildOfNode->FindPinChecked( FString(TEXT("TestClass")) );
			GetClassReturnValuePin->MakeLinkTo( ClassIsChildOfTestPin );

			//copy our BaseClass Pin into the ClassIsChildOf Parameter
			UEdGraphPin *ClassIsChildOfParentPin = ClassIsChildOfNode->FindPinChecked( FString(TEXT("ParentClass")) );
			CompilerContext.CopyPinLinksToIntermediate( *SourceBaseClassPin, *ClassIsChildOfParentPin);

			//hook for return value
			UEdGraphPin *ClassIsChildOfResultPin = ClassIsChildOfNode->GetReturnValuePin();

			//
			// Create the BRANCH that will drive the comparison
			UK2Node_IfThenElse* ClassIsChildOfBranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph);
			ClassIsChildOfBranchNode->AllocateDefaultPins();

			//hook up the previous branch to this one
			check( CompareBlueprintToNullBranchThenPin != NULL );
			CompareBlueprintToNullBranchThenPin->MakeLinkTo( ClassIsChildOfBranchNode->GetExecPin() );

			//hook up our condition
			ClassIsChildOfResultPin->MakeLinkTo( ClassIsChildOfBranchNode->GetConditionPin() );

			//cache ot the THEN pin for later linkup
			ClassIsChildOfBranchThenPin = ClassIsChildOfBranchNode->GetThenPin();
		}


		//
		//The set variable function (to set LiveEdited new value)
		//
		UK2Node_CallFunction *ModifyVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		ModifyVarNode->FunctionReference.SetExternalMember( TEXT("ModifyPropertyByName"), ULiveEditorKismetLibrary::StaticClass() );
		ModifyVarNode->AllocateDefaultPins();

		// Make link from the event to the Set variable node
		UEdGraphPin *ModifyVarExecPin = ModifyVarNode->GetExecPin();
		ClassIsChildOfBranchThenPin->MakeLinkTo( ModifyVarExecPin );

		//link up the Target Pin
		UEdGraphPin *ModifyVarNodeTargetPin = ModifyVarNode->FindPinChecked( TEXT("Target") );
		GetClassDefaultObjectResultPin->MakeLinkTo( ModifyVarNodeTargetPin );

		//link up the PropertyName Pin
		UEdGraphPin *ModifyVarNodePropertyNamePin = ModifyVarNode->FindPinChecked( TEXT("PropertyName") );
		ModifyVarNodePropertyNamePin->DefaultValue = SourceVariablePin->DefaultValue;

		//link up the MIDI Value Pin
		UEdGraphPin *ModifyVarNodeMidiValuePin = ModifyVarNode->FindPinChecked( TEXT("MidiValue") );
		EventMidiValuePin->MakeLinkTo(ModifyVarNodeMidiValuePin);

		//link up the ControlType Pin
		UEdGraphPin *ModifyVarNodeControlTypePin = ModifyVarNode->FindPinChecked( TEXT("ControlType") );
		EventControlTypePin->MakeLinkTo(ModifyVarNodeControlTypePin);

		//hook for the Delta Pin
		UEdGraphPin *ModifyVarNodeDeltaPin = ModifyVarNode->FindPinChecked( TEXT("Delta") );

		//Clamping
		if ( ShouldClampPin->DefaultValue == FString(TEXT("true")) )
		{
			UEdGraphPin *ModifyVarNodeShouldClampPin = ModifyVarNode->FindPinChecked( TEXT("bShouldClamp") );
			CompilerContext.CopyPinLinksToIntermediate( *ShouldClampPin, *ModifyVarNodeShouldClampPin);

			check( ClampMinPin != NULL );
			UEdGraphPin *ModifyVarNodeClampMinPin = ModifyVarNode->FindPinChecked( TEXT("ClampMin") );
			CompilerContext.CopyPinLinksToIntermediate( *ClampMinPin, *ModifyVarNodeClampMinPin);

			check( ClampMaxPin != NULL );
			UEdGraphPin *ModifyVarNodeClampMaxPin = ModifyVarNode->FindPinChecked( TEXT("ClampMax") );
			CompilerContext.CopyPinLinksToIntermediate( *ClampMaxPin, *ModifyVarNodeClampMaxPin);
		}

		//hook for ModifyVar THEN
		UEdGraphPin *ModifyVarNodeThenPin = ModifyVarNode->GetThenPin();

		//
		// The Multiply Delta * DeltaMult function
		//
		UK2Node_CallFunction *MultiplyNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		MultiplyNode->FunctionReference.SetExternalMember( TEXT("Multiply_FloatFloat"), UKismetMathLibrary::StaticClass() );
		MultiplyNode->AllocateDefaultPins();

		//cache this out. it will be linked to from the output of the (int)Delta -> (float)Delta Conversion function
		UEdGraphPin *MultiplyNodeFirstPin = MultiplyNode->FindPinChecked( FString(TEXT("A")) );

		// 2nd input to the Add function comes from the Current variable value
		UEdGraphPin *MultiplyNodeSecondPin = MultiplyNode->FindPinChecked( FString(TEXT("B")) );
		CompilerContext.CopyPinLinksToIntermediate( *DeltaMultPin, *MultiplyNodeSecondPin);

		UEdGraphPin *MultiplyNodeReturnValuePin = MultiplyNode->GetReturnValuePin();
		MultiplyNodeReturnValuePin->MakeLinkTo( ModifyVarNodeDeltaPin );

		//
		// The Convert function to go from (int)Delta to ULiveEditorKismetLibrary::ModifyPropertyByName(... float Delta ...)
		//
		FName ConvertFunctionName;
		bool success = Schema->SearchForAutocastFunction( EventDeltaPin, MultiplyNodeFirstPin, ConvertFunctionName );
		check( success );
		UK2Node_CallFunction *ConvertDeltaNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		ConvertDeltaNode->FunctionReference.SetExternalMember( ConvertFunctionName, UKismetMathLibrary::StaticClass() );
		ConvertDeltaNode->AllocateDefaultPins();

		FName PinName;
		success = UK2Node_LiveEditObjectStatics::SearchForConvertPinName( Schema, EventDeltaPin, PinName );
		check( success );
		UEdGraphPin *ConvertDeltaInputPin = ConvertDeltaNode->FindPinChecked( PinName.ToString() );
		EventDeltaPin->MakeLinkTo( ConvertDeltaInputPin );

		UEdGraphPin *ConvertDeltaOutputPin = ConvertDeltaNode->GetReturnValuePin();
		ConvertDeltaOutputPin->MakeLinkTo( MultiplyNodeFirstPin );

		//
		// TODO - markDirty
		//

		//
		// send out the object value updates
		//
		UK2Node_CallFunction *ReplicationNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		ReplicationNode->FunctionReference.SetExternalMember( TEXT("ReplicateChangesToChildren"), ULiveEditorKismetLibrary::StaticClass() );
		ReplicationNode->AllocateDefaultPins();

		UEdGraphPin *ReplicationNodeVarNamePin = ReplicationNode->FindPinChecked( TEXT("PropertyName") );
		ReplicationNodeVarNamePin->DefaultValue = SourceVariablePin->DefaultValue;

		UEdGraphPin *ReplicationNodeArchetypePin = ReplicationNode->FindPinChecked( FString(TEXT("Archetype")) );
		GetClassDefaultObjectResultPin->MakeLinkTo( ReplicationNodeArchetypePin );

		UEdGraphPin *ReplicationNodeExecPin = ReplicationNode->GetExecPin();
		ModifyVarNodeThenPin->MakeLinkTo( ReplicationNodeExecPin );

		UEdGraphPin *ReplicationNodeThenPin = ReplicationNode->FindPinChecked( FString(TEXT("then")) );

		//
		// Finally, activate our OnMidiInput pin
		//
		CompilerContext.CopyPinLinksToIntermediate( *SourceOnMidiInputPin, *ReplicationNodeThenPin);
			
	}

	// Break any links to the expanded node
	BreakAllNodeLinks();
}
void IGameplayCueInterface::HandleGameplayCue(AActor *Self, FGameplayTag GameplayCueTag, EGameplayCueEvent::Type EventType, FGameplayCueParameters Parameters)
{
	SCOPE_CYCLE_COUNTER(STAT_GameplayCueInterface_HandleGameplayCue);

	// Look up a custom function for this gameplay tag. 
	UClass* Class = Self->GetClass();
	IGameplayTagsModule& GameplayTagsModule = IGameplayTagsModule::Get();
	FGameplayTagContainer TagAndParentsContainer = GameplayTagsModule.GetGameplayTagsManager().RequestGameplayTagParents(GameplayCueTag);

	Parameters.OriginalTag = GameplayCueTag;

	//Find entry for the class
	FGameplayCueTagFunctionList& GameplayTagFunctionList = PerClassGameplayTagToFunctionMap.FindOrAdd(Class);
	TArray<FCueNameAndUFunction>* FunctionList = GameplayTagFunctionList.Find(GameplayCueTag);
	if (FunctionList == NULL)
	{
		//generate new function list
		FunctionList = &GameplayTagFunctionList.Add(GameplayCueTag);

		for (auto InnerTagIt = TagAndParentsContainer.CreateConstIterator(); InnerTagIt; ++InnerTagIt)
		{
			UFunction* Func = NULL;
			FName CueName = InnerTagIt->GetTagName();

			Func = Class->FindFunctionByName(CueName, EIncludeSuperFlag::IncludeSuper);
			// If the handler calls ForwardGameplayCueToParent, keep calling functions until one consumes the cue and doesn't forward it
			while (Func)
			{
				FCueNameAndUFunction NewCueFunctionPair;
				NewCueFunctionPair.Tag = *InnerTagIt;
				NewCueFunctionPair.Func = Func;
				FunctionList->Add(NewCueFunctionPair);

				Func = Func->GetSuperFunction();
			}

			// Native functions cant be named with ".", so look for them with _. 
			FName NativeCueFuncName = *CueName.ToString().Replace(TEXT("."), TEXT("_"));
			Func = Class->FindFunctionByName(NativeCueFuncName, EIncludeSuperFlag::IncludeSuper);

			while (Func)
			{
				FCueNameAndUFunction NewCueFunctionPair;
				NewCueFunctionPair.Tag = *InnerTagIt;
				NewCueFunctionPair.Func = Func;
				FunctionList->Add(NewCueFunctionPair);

				Func = Func->GetSuperFunction();
			}
		}
	}

	//Iterate through all functions in the list until we should no longer continue
	check(FunctionList);
		
	bool bShouldContinue = true;
	for (int32 FunctionIndex = 0; bShouldContinue && (FunctionIndex < FunctionList->Num()); ++FunctionIndex)
	{
		FCueNameAndUFunction& CueFunctionPair = FunctionList->GetData()[FunctionIndex];
		UFunction* Func = CueFunctionPair.Func;
		Parameters.MatchedTagName = CueFunctionPair.Tag;

		// Reset the forward parameter now, so we can check it after function
		bForwardToParent = false;
		IGameplayCueInterface::DispatchBlueprintCustomHandler(Self, Func, EventType, Parameters);

		bShouldContinue = bForwardToParent;
	}

	if (bShouldContinue)
	{
		TArray<UGameplayCueSet*> Sets;
		GetGameplayCueSets(Sets);
		for (UGameplayCueSet* Set : Sets)
		{
			bShouldContinue = Set->HandleGameplayCue(Self, GameplayCueTag, EventType, Parameters);
			if (!bShouldContinue)
			{
				break;
			}
		}
	}

	if (bShouldContinue)
	{
		Parameters.MatchedTagName = GameplayCueTag;
		GameplayCueDefaultHandler(EventType, Parameters);
	}
}
Ejemplo n.º 30
0
void UConsole::BuildRuntimeAutoCompleteList(bool bForce)
{
#if !UE_BUILD_SHIPPING
	if (!bForce)
	{
		// unless forced delay updating until needed
		bIsRuntimeAutoCompleteUpToDate = false;
		return;
	}

	// clear the existing tree
	//@todo - probably only need to rebuild the tree + partial command list on level load
	for (int32 Idx = 0; Idx < AutoCompleteTree.ChildNodes.Num(); Idx++)
	{
		FAutoCompleteNode *Node = AutoCompleteTree.ChildNodes[Idx];
		delete Node;
	}

	AutoCompleteTree.ChildNodes.Empty();

	const UConsoleSettings* ConsoleSettings = GetDefault<UConsoleSettings>();

	// copy the manual list first
	AutoCompleteList.Empty();
	AutoCompleteList.AddZeroed(ConsoleSettings->ManualAutoCompleteList.Num());
	for (int32 Idx = 0; Idx < ConsoleSettings->ManualAutoCompleteList.Num(); Idx++)
	{
		AutoCompleteList[Idx] = ConsoleSettings->ManualAutoCompleteList[Idx];
	}

	// console variables
	{
		IConsoleManager::Get().ForEachConsoleObject(
			FConsoleObjectVisitor::CreateStatic< TArray<struct FAutoCompleteCommand>& >(
				&FConsoleVariableAutoCompleteVisitor::OnConsoleVariable,
				AutoCompleteList ) );
	}

	// iterate through script exec functions and append to the list
	int32 ScriptExecCnt = 0;
	for (TObjectIterator<UFunction> It; It; ++It)
	{
		UFunction *Func = *It;

		// Determine whether or not this is a level script event that we can call (must be defined in the level script actor and not in parent, and has no return value)
		const UClass* FuncOuter = Cast<UClass>(Func->GetOuter());
		const bool bIsLevelScriptFunction = FuncOuter 
			&& (FuncOuter->IsChildOf(ALevelScriptActor::StaticClass()))
			&& (FuncOuter != ALevelScriptActor::StaticClass())
			&& (Func->ReturnValueOffset == MAX_uint16) 
			&& (Func->GetSuperFunction() == NULL);

		// exec functions that either have no parent, level script events, or are in the global state (filtering some unnecessary dupes)
		if ( (Func->HasAnyFunctionFlags(FUNC_Exec) && (Func->GetSuperFunction() == NULL || FuncOuter))
			|| bIsLevelScriptFunction)
		{
			FString FuncName = Func->GetName();
			if(FDefaultValueHelper::HasWhitespaces(FuncName))
			{
				FuncName = FString::Printf(TEXT("\"%s\""), *FuncName);
			}
			if( bIsLevelScriptFunction )
			{
				FuncName = FString(TEXT("ce ")) + FuncName;
			}

			int32 NewIdx = AutoCompleteList.AddZeroed(1);
			AutoCompleteList[NewIdx].Command = FuncName;
			// build a help string
			// append each property (and it's type) to the help string
			for (TFieldIterator<UProperty> PropIt(Func); PropIt && (PropIt->PropertyFlags & CPF_Parm); ++PropIt)
			{
				UProperty *Prop = *PropIt;
				FuncName = FString::Printf(TEXT("%s %s[%s]"),*FuncName,*Prop->GetName(),*Prop->GetCPPType());
			}
			AutoCompleteList[NewIdx].Desc = FuncName;
			ScriptExecCnt++;
		}
	}

	// enumerate maps
	TArray<FString> Packages;
	for (int32 PathIdx = 0; PathIdx < ConsoleSettings->AutoCompleteMapPaths.Num(); ++PathIdx)
	{
		FPackageName::FindPackagesInDirectory(Packages, FString::Printf(TEXT("%s%s"), *FPaths::GameDir(), *ConsoleSettings->AutoCompleteMapPaths[PathIdx]));
	}
	
	// also include maps in this user's developer dir
	FPackageName::FindPackagesInDirectory(Packages, FPaths::GameUserDeveloperDir());

	for (int32 PackageIndex = 0; PackageIndex < Packages.Num(); PackageIndex++)
	{
		FString Pkg = Packages[PackageIndex];
		int32 ExtIdx = Pkg.Find(*FPackageName::GetMapPackageExtension(),ESearchCase::IgnoreCase, ESearchDir::FromEnd);
		
		FString MapName;
		if (ExtIdx != INDEX_NONE && Pkg.Split(TEXT("/"),NULL,&MapName,ESearchCase::CaseSensitive, ESearchDir::FromEnd))
		{
			// try to peel off the extension
			FString TrimmedMapName;
			if (!MapName.Split(TEXT("."),&TrimmedMapName,NULL,ESearchCase::CaseSensitive, ESearchDir::FromEnd))
			{
				TrimmedMapName = MapName;
			}
			int32 NewIdx;
			// put _P maps at the front so that they match early, since those are generally the maps we want to actually open
			if (TrimmedMapName.EndsWith(TEXT("_P")))
			{
				NewIdx = 0;
				AutoCompleteList.InsertZeroed(0,3);
			}
			else
			{
				NewIdx = AutoCompleteList.AddZeroed(3);
			}
			AutoCompleteList[NewIdx].Command = FString::Printf(TEXT("open %s"),*TrimmedMapName);
			AutoCompleteList[NewIdx].Desc = FString::Printf(TEXT("open %s"),*TrimmedMapName);
			AutoCompleteList[NewIdx+1].Command = FString::Printf(TEXT("travel %s"),*TrimmedMapName);
			AutoCompleteList[NewIdx+1].Desc = FString::Printf(TEXT("travel %s"),*TrimmedMapName);
			AutoCompleteList[NewIdx+2].Command = FString::Printf(TEXT("servertravel %s"),*TrimmedMapName);
			AutoCompleteList[NewIdx+2].Desc = FString::Printf(TEXT("servertravel %s"),*TrimmedMapName);
			//MapNames.AddItem(Pkg);
		}
	}
	// misc commands
	{
		int32 NewIdx = AutoCompleteList.AddZeroed(1);
		AutoCompleteList[NewIdx].Command = FString(TEXT("open 127.0.0.1"));
		AutoCompleteList[NewIdx].Desc = FString(TEXT("open 127.0.0.1 (opens connection to localhost)"));
	}

#if STATS
	// stat commands
	{
		const TSet<FName>& StatGroupNames = FStatGroupGameThreadNotifier::Get().StatGroupNames;

		int32 NewIdx = AutoCompleteList.AddZeroed(StatGroupNames.Num());
		for (const FName& StatGroupName : StatGroupNames)
		{
			FString Command = FString(TEXT("Stat "));
			Command += StatGroupName.ToString().RightChop(sizeof("STATGROUP_") - 1);

			AutoCompleteList[NewIdx].Command = Command;
			AutoCompleteList[NewIdx].Desc = FString();
			NewIdx++;
		}
	}
#endif

	// build the magic tree!
	for (int32 ListIdx = 0; ListIdx < AutoCompleteList.Num(); ListIdx++)
	{
		FString Command = AutoCompleteList[ListIdx].Command.ToLower();
		FAutoCompleteNode *Node = &AutoCompleteTree;
		for (int32 Depth = 0; Depth < Command.Len(); Depth++)
		{
			int32 Char = Command[Depth];
			int32 FoundNodeIdx = INDEX_NONE;
			TArray<FAutoCompleteNode*> &NodeList = Node->ChildNodes;
			for (int32 NodeIdx = 0; NodeIdx < NodeList.Num(); NodeIdx++)
			{
				if (NodeList[NodeIdx]->IndexChar == Char)
				{
					FoundNodeIdx = NodeIdx;
					Node = NodeList[FoundNodeIdx];
					NodeList[FoundNodeIdx]->AutoCompleteListIndices.Add(ListIdx);
					break;
				}
			}
			if (FoundNodeIdx == INDEX_NONE)
			{
				FAutoCompleteNode *NewNode = new FAutoCompleteNode(Char);
				NewNode->AutoCompleteListIndices.Add(ListIdx);
				Node->ChildNodes.Add(NewNode);
				Node = NewNode;
			}
		}
	}
	bIsRuntimeAutoCompleteUpToDate = true;
	//PrintNode(&AutoCompleteTree);
#endif
}