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); } } }
// 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; }
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; }
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")); } }
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; } } }
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; }
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(); }
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; }
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); } } }
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 }
// 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; }
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); } }
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; }
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(); } } } }
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); } } } }
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); } } } }
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(); }
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; }
/** * 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")); } }
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); } }
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 }