在C++定义了一个继承UObject的类型UTestObject后,当蓝图继承UTestObject时没有办法访问带有WorldContextObject的函数,而访问子系统时将会有编译错误:ContextObject must have a connect。

在找了一番解决方案后解决了该问题,由此记录一下。

先看UE源码两处关键代码,其一是UObject::GetWorld(),可以看到默认获取outer的World,如果我们的UObject在NewObject时都正常传入outer的情况下是可以获取到world的,但在下面会有个bGetWorldOverridden的变量,如果为false则表示着调用到了该UObject基类上来了,派生类没有重写这个函数。

class UWorld* UObject::GetWorld() const
{
    if (UObject* Outer = GetOuter())
    {
        return Outer->GetWorld();
    }

#if DO_CHECK
    bGetWorldOverridden = false;
#endif
    return nullptr;
}

在看另一个函数UObject::ImplementsGetWorld(),这个函数会返回一个布尔值,其中会先将bGetWorldOverriden默认设置为true,然后调用GetWorld,如果派生类没有重写GetWorld函数则会调用上面介绍的UObject自身的GetWorld,这样bGetWorldOveridden就会被置为false并返回。UE就是通过调用这个函数来确定一个类型有没有重写GetWorld函数的,所以我们只需要想办法让这个函数返回true即可。

bool UObject::ImplementsGetWorld() const
{
#if DO_CHECK
    bGetWorldOverridden = true;
    GetWorld();
    return bGetWorldOverridden;
#else
    return true;
#endif	
}

我们对自己定义的类型进行重写GetWorld函数,结果获取Outer的World即可。另外还有一种情况就是没有Outer或者当前对象是CDO,CDO对象的outer为UPackage对象,所以要对这两种情况进行特殊判断并返回空值。

UWorld* UTestObject::GetWorld() const
{
    auto Outer = GetOuter();
    if (!Outer || Cast<UPackage>(Outer))
    {
        return nullptr;
    }
    return Outer->GetWorld();
}