Description

If you have a blueprint A with a child blueprint B, and child of the child blueprint C, overriding a function with a return parameter originally declared in blueprint A in the blueprint C, and then overriding the same function in blueprint B, unintentionally renames the function in blueprint C.

Seems like it could be addressed by modifying the code in FBlueprintEditorUtils::ValidateAllFunctionGraphs() that renames the child function if you add a function of the same name to the parent to only rename it if the two functions aren't both overriding the same function in a shared ancestor.

For example, something along the lines of this code:
(not great code, but maybe along the lines of what is needed)

bool FBlueprintEditorUtils::ValidateAllFunctionGraphs(UBlueprint* InBlueprint, UBlueprint* InParentBlueprint, const FName& InVariableName)
{
	for (int32 FunctionIndex=0; FunctionIndex < InBlueprint->FunctionGraphs.Num(); ++FunctionIndex)
	{
		UEdGraph* FunctionGraph = InBlueprint->FunctionGraphs[FunctionIndex];

		TSharedPtr<FKismetNameValidator> ParentBPNameValidator = MakeShareable(new FKismetNameValidator(InParentBlueprint));

		if( FunctionGraph->GetFName() == InVariableName )
		{
			bool bRename = true;

			TArray<const UK2Node_FunctionEntry*> ChildFunctionEntryPoints;
			FunctionGraph->GetNodesOfClass(ChildFunctionEntryPoints);

			for (int32 EntryPointsIdx = 0; EntryPointsIdx < ChildFunctionEntryPoints.Num(); EntryPointsIdx++)
			{
				const UK2Node_FunctionEntry* EventNode = ChildFunctionEntryPoints[EntryPointsIdx];
				check(NULL != EventNode);

				const UClass* FuncClass = *EventNode->SignatureClass;
				for (UEdGraph* ParentFunctionGraph : InParentBlueprint->FunctionGraphs)
				{
					if (ParentFunctionGraph->GetName().Equals(FunctionGraph->GetName()))
					{
						TArray<const UK2Node_FunctionEntry*> ParentFunctionEntryPoints;
						ParentFunctionGraph->GetNodesOfClass(ParentFunctionEntryPoints);
						for (const UK2Node_FunctionEntry* ParentEventNode : ParentFunctionEntryPoints)
						{
							const UClass* ParentFuncClass = *ParentEventNode->SignatureClass;
							if (ParentFuncClass == FuncClass)
							{
								//Signatures based on same class
								bRename = false;
							}
						}
					}
				}

				if (bRename)
				{

					FName NewName = FBlueprintEditorUtils::FindUniqueKismetName(InBlueprint, FunctionGraph->GetName());
					FBlueprintEditorUtils::RenameGraph(FunctionGraph, NewName.ToString());

					UE_LOG(LogBlueprint, Warning, TEXT("Blueprint %s (child of/implements %s) has a function graph with a conflicting name (%s). Changing to %s."), *InBlueprint->GetName(), *InParentBlueprint->GetName(), *InVariableName.ToString(), *NewName.ToString());
					return true;
				}
			}
		}
	}
	return false;
}
Steps to Reproduce
  1. Create Blueprint "Class A"
  2. Right click blueprint "Class A" and select "Create Child Blueprint"
    • Call this "Class B"
  3. Right click blueprint "Class B" and select "Create Child Blueprint"
    • Call this "class C"
  4. Open Class A and create a function called "TestFunction". Give it an output variable of any type (important!)
    • Compile Class A
  5. Open Class C and override "TestFunction"
    • Compile Class C
  6. Open Class B and override "TestFunction"
    • Compile Class B
  7. Notice warning in Output log:
    • "LogBlueprint: Warning: Blueprint ClassC (child of/implements ClassB) has a function graph with a conflicting name (TestFunction). Changing to TestFunction_0."
  8. Notice the "TestFunction" in ClassC is now TestFunction_0

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-52744 in the post.

0
Login to Vote

Cannot Reproduce
ComponentUE - Gameplay - Blueprint
Affects Versions4.17.24.18.1
Target Fix4.19
Fix Commit3806617
Main Commit3967553
CreatedNov 28, 2017
ResolvedDec 19, 2017
UpdatedApr 27, 2018