Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion unreal/Puerts/PuertsEditor/CodeAnalyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,20 @@ function watch(configFilePath:string) {
flags |= Number(getDecoratorFlagsValue(symbol.valueDeclaration, "set_flags", FunctionFlags));
clearFlags = Number(getDecoratorFlagsValue(symbol.valueDeclaration, "clear_flags", FunctionFlags));
}


// static methods are only allowed on BlueprintFunctionLibrary derived classes
// (enforced above). Map the static modifier to FUNC_Static, otherwise the
// generated UFunction is an instance function: blueprint call nodes then
// require a Target pin, and the runtime only wires JS dispatch for
// FUNC_Static functions, so the TS implementation would never be invoked.
// Explicitly clear the flag for non-static methods so regeneration
// converges when the static modifier is added or removed.
if (ts.getCombinedModifierFlags(symbol.valueDeclaration) & ts.ModifierFlags.Static) {
flags |= FunctionFlags.FUNC_Static;
} else {
clearFlags |= FunctionFlags.FUNC_Static;
}

if (symbol.valueDeclaration.type && (ts.SyntaxKind.VoidKeyword === symbol.valueDeclaration.type.kind)) {
// bp.AddFunction(symbol.getName(), true, undefined, undefined, flags, clearFlags);
bp.AddFunctionWithMetaData(symbol.getName(), true, undefined, undefined, flags, clearFlags, uemeta.compileFunctionMetaData(symbol));
Expand Down
23 changes: 20 additions & 3 deletions unreal/Puerts/Source/PuertsEditor/Private/PEBlueprintAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,32 @@ bool UPEBlueprintAsset::LoadOrCreate(
HasConstructor = TypeScriptGeneratedClass->HasConstructor;
}
Package = Cast<UPackage>(Blueprint->GetOuter());
NeedSave = false;
if (Blueprint->ParentClass != ParentClass)
{
CanChangeCheckWithBoolRet();
Blueprint->ParentClass = ParentClass;
NeedSave = true;
}
else
{
NeedSave = false;

// BlueprintType has to keep tracking the parent class. Only the create path below derives it, so an asset
// generated before its TypeScript class became a BlueprintFunctionLibrary derivative would stay
// BPTYPE_Normal forever. That desync is not cosmetic: UEdGraphSchema_K2::IsStaticFunctionGraph then falls
// back to probing FUNC_Static on the function entry node, so the implicit hidden __WorldContext parameter
// appears or disappears together with that flag, and the function library fallbacks in
// FastGenerateSkeletonClass stay disabled. The serialized generated class and the skeleton class (rebuilt
// on every load) end up disagreeing on the signature, which makes callers fail to compile with
// "Could not find a pin for the parameter __WorldContext".
if (ParentClass)
{
const EBlueprintType DesiredBlueprintType =
ParentClass->IsChildOf(UBlueprintFunctionLibrary::StaticClass()) ? BPTYPE_FunctionLibrary : BPTYPE_Normal;
if (Blueprint->BlueprintType != DesiredBlueprintType)
{
CanChangeCheckWithBoolRet();
Blueprint->BlueprintType = DesiredBlueprintType;
NeedSave = true;
}
}
return true;
}
Expand Down
20 changes: 15 additions & 5 deletions unreal/Puerts/Source/PuertsEditor/Private/PEBlueprintMetaData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,21 @@ bool UPEClassMetaData::SyncClassToBlueprint(UClass* InClass, UBlueprint* InBluep
InBlueprint->BlueprintDisplayName = newDisplayName;
onChange = true;
}
EBlueprintType newType = (InClass->ClassFlags & CLASS_Const) ? BPTYPE_Const : BPTYPE_Normal;
if (InBlueprint->BlueprintType != newType)
{
InBlueprint->BlueprintType = newType;
onChange = true;
// BPTYPE_FunctionLibrary is derived from the parent class by UPEBlueprintAsset::LoadOrCreate and cannot be
// expressed through @uclass flags, so this sync only owns the Const / Normal distinction and must not downgrade
// a function library blueprint. Downgrading it would make UEdGraphSchema_K2::IsStaticFunctionGraph fall back to
// probing FUNC_Static on the function entry node, so the implicit hidden __WorldContext parameter would follow
// that flag instead of the blueprint type while the function library fallbacks in FastGenerateSkeletonClass stay
// disabled - the serialized generated class and the skeleton class then disagree on the signature and callers
// fail to compile with "Could not find a pin for the parameter __WorldContext".
if (InBlueprint->BlueprintType != BPTYPE_FunctionLibrary)
{
const EBlueprintType newType = (InClass->ClassFlags & CLASS_Const) ? BPTYPE_Const : BPTYPE_Normal;
if (InBlueprint->BlueprintType != newType)
{
InBlueprint->BlueprintType = newType;
onChange = true;
}
}
FString newCategory = InClass->HasMetaData(TEXT("Category")) ? InClass->GetMetaData(TEXT("Category")) : FString{};
if (InBlueprint->BlueprintCategory != newCategory)
Expand Down
Loading