Skip to content

[UE] Bug: 蓝图基类Mixin基类ts,蓝图子类Mixin子类ts, ts用extends继承mixin ts类,ts分别实现ReceiveBeginPlay函数,必现crash #2331

@Edenlia

Description

@Edenlia

前置阅读 | Pre-reading

Puer的版本 | Puer Version

master

UE的版本 | UE Version

5.4.4

发生在哪个平台 | Platform

Editor(win)

错误信息 | Error Message

BP_TestParent 父类蓝图,BP_TestChild 子类蓝图,ts mixin类分别mixin蓝图类,然后TestParent和TestChild蓝图中均无实现ReceiveBeginPlay,会直接出现crash

测试发现只要子类BP_TestChild在蓝图中定义了ReceiveBeginPlay方法即不会crash了

0x0000000000000000
UFunction::Invoke(UObject *, FFrame &, void *const) Class.cpp:6847
[Blueprint] BP_TestChild: ReceiveBeginPlay Function /Game/Blueprints/BP_TestChild.BP_TestChild_C:ReceiveBeginPlay
UObject::ProcessEvent(UFunction *, void *) ScriptCore.cpp:2142
AActor::ProcessEvent(UFunction *, void *) Actor.cpp:1092
AActor::BeginPlay() Actor.cpp:4251
AActor::DispatchBeginPlay(bool) Actor.cpp:4191
AWorldSettings::NotifyBeginPlay() WorldSettings.cpp:305
AGameStateBase::HandleBeginPlay() GameStateBase.cpp:227
AGameModeBase::StartPlay() GameModeBase.cpp:205
UWorld::BeginPlay() World.cpp:5329
UGameInstance::StartPlayInEditorGameInstance(ULocalPlayer *, const FGameInstancePIEParameters &) GameInstance.cpp:566
UEditorEngine::CreateInnerProcessPIEGameInstance(FRequestPlaySessionParams &, const FGameInstancePIEParameters &, int) PlayLevel.cpp:3141
UEditorEngine::OnLoginPIEComplete_Deferred(int, bool, FString, FPieLoginStruct) PlayLevel.cpp:1589
UEditorEngine::CreateNewPlayInEditorInstance(FRequestPlaySessionParams &, const bool, EPlayNetMode) PlayLevel.cpp:1853
UEditorEngine::StartPlayInEditorSession(FRequestPlaySessionParams &) PlayLevel.cpp:2868
UEditorEngine::StartQueuedPlaySessionRequestImpl() PlayLevel.cpp:1167
UEditorEngine::StartQueuedPlaySessionRequest() PlayLevel.cpp:1064
UEditorEngine::Tick(float, bool) EditorEngine.cpp:1901
UUnrealEdEngine::Tick(float, bool) UnrealEdEngine.cpp:547
FEngineLoop::Tick() LaunchEngineLoop.cpp:5915
[Inlined] EngineTick() Launch.cpp:61
GuardedMain(const wchar_t *) Launch.cpp:182
LaunchWindowsStartup(HINSTANCE__ *, HINSTANCE__ *, char *, int, const wchar_t *) LaunchWindows.cpp:247
WinMain(HINSTANCE__ *, HINSTANCE__ *, char *, int) LaunchWindows.cpp:298

看了相关代码后感觉原因应该是子类在UJSGeneratedClass::Mixin时,由于蓝图没有ReceiveBeginPlay函数,Duplicate了父类已经被Mixin了的ReceiveBeginPlay函数,然后误认为子类已经Mixin过了,直接用了父类这个Mixin函数,状态出现了些问题,麻烦帮忙看看这里这样设计是否合理

UFunction* UJSGeneratedClass::Mixin(v8::Isolate* Isolate, UClass* Class, UFunction* Super,
    TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool TakeJsObjectRef, bool Warning)
{
    bool Existed = Super->GetOuter() == Class;
    if (!Existed)
    {
        UFunction* Tmp =
            Cast<UFunction>(StaticDuplicateObject(Super, Class, Super->GetFName(), RF_AllFlags, UFunction::StaticClass()));
        Tmp->SetSuperStruct(Super);
        Tmp->Next = Class->Children;
        Class->Children = Tmp;
        Class->AddFunctionToFunctionMap(Tmp, Tmp->GetFName());
        Tmp->SetFlags(Tmp->GetFlags() | RF_Transient);
        Super = Tmp;
        Super->ClearInternalFlags(EInternalObjectFlags::Native);
        Super->StaticLink(true);
    }
    auto MaybeJSFunction = Cast<UJSGeneratedFunction>(Super);
    if (!MaybeJSFunction)
    {
        MaybeJSFunction = UJSGeneratedFunction::GetJSGeneratedFunctionFromScript(Super);
    }
    if (MaybeJSFunction)
    {
        if (Warning)
        {
            UE_LOG(Puerts, Warning, TEXT("Try to mixin a function[%s:%s] already mixin by anthor vm"), *Class->GetName(),
                *Super->GetName());
        }
        return MaybeJSFunction;
    }
...
}

问题重现 | Bug reproduce

复现用demo项目:https://github.com/Edenlia/puerts_unreal_demo_edenlia

BP_TestParent_C.ts

import * as UE from 'ue'
import {argv, blueprint} from 'puerts';

let BP_TestParent_UClass = UE.Class.Load('/Game/Blueprints/BP_TestParent.BP_TestParent_C');
const BP_TestParent_JsProxyClass = blueprint.tojs<typeof UE.Game.Blueprints.BP_TestParent.BP_TestParent_C>(BP_TestParent_UClass);
interface BP_TestParent_TS extends UE.Game.Blueprints.BP_TestParent.BP_TestParent_C {}

class BP_TestParent_TS {
    ReceiveBeginPlay():void {
        console.log(`BP_TestParent Ts ReceiveBeginPlay`);
    }

    ReceiveTick(DeltaSeconds: number) {
        // console.log(`BP_TestParent Ts ReceiveTick`);
    }
}

const BP_TestParent = blueprint.mixin(BP_TestParent_JsProxyClass, BP_TestParent_TS);

export {BP_TestParent_TS, BP_TestParent};
export default BP_TestParent;

BP_TestChild_C.ts

import * as UE from 'ue'
import {argv, blueprint} from 'puerts';
import {BP_TestParent_TS, BP_TestParent} from './BP_TestParent_C';

let BP_TestChild_UClass = UE.Class.Load('/Game/Blueprints/BP_TestChild.BP_TestChild_C');
const BP_TestChild_JsProxyClass = blueprint.tojs<typeof UE.Game.Blueprints.BP_TestChild.BP_TestChild_C>(BP_TestChild_UClass);
interface BP_TestChild_TS extends UE.Game.Blueprints.BP_TestChild.BP_TestChild_C {}

class BP_TestChild_TS extends BP_TestParent_TS {
    ReceiveBeginPlay():void {
        // super.ReceiveBeginPlay();
        console.log(`BP_TestChild Ts ReceiveBeginPlay`);
    }

    // ReceiveTick(DeltaSeconds: number) {
    //     // console.log(`BP_TestChild Ts ReceiveTick`);
    // }
}

const BP_TestChild = blueprint.mixin(BP_TestChild_JsProxyClass, BP_TestChild_TS);

export {BP_TestChild_TS, BP_TestChild};
export default BP_TestChild;

QuickStart.ts

import "./BP_TestParent_C"
import "./BP_TestChild_C"

BP_TestChild蓝图中删除ReceiveBeginPlay函数

将BP_TestChild_C拖入场景,点击PIE Crash

Metadata

Metadata

Assignees

Labels

UnrealbugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions