Mapz's Blog

可以递归的函数指针

UE4:游戏关闭流程

有时候我们需要在 UE4 关闭游戏的时候,处理一些事情,那么可以重写 UGameInstance::ShutDown()

但是有时候在游戏关闭的时候,这个函数并未调用,于是我有必要探究一番他的调用链

这里仅讨论 Engine 而不讨论 EditorEngine

调用栈

  • UGameInstance::ShutDown()
  • UGameEngine::PreExit()
  • FEngineLoop::Exit()
  • 调用 EngineExit 或者平台调用退出
  • EngineExit 被放在了 GuardedMain 函数中定义的一个结构体中
1
2
3
4
5
6
7
8
   // make sure GEngineLoop::Exit() is always called.
struct EngineLoopCleanupGuard
{
~EngineLoopCleanupGuard()
{
EngineExit();
}
} CleanupGuard;

也就是说游戏 Main 函数结束执行的时候,一定会执行 ShutDown

那么为什么我测试的时候日志中没有出现 ShutDown 相关内容呢

检查发现我们调用关闭游戏的时候用的是

1
FPlatformMisc::RequestExit(true);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void FWindowsPlatformMisc::RequestExit( bool Force )
{
UE_LOG(LogWindows, Log, TEXT("FPlatformMisc::RequestExit(%i)"), Force );

RequestEngineExit(TEXT("Win RequestExit"));
FCoreDelegates::ApplicationWillTerminateDelegate.Broadcast();

if( Force )
{
// Force immediate exit. In case of an error set the exit code to 3.
// Dangerous because config code isn't flushed, global destructors aren't called, etc.
// Suppress abort message and MS reports.
//_set_abort_behavior( 0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT );
//abort();

// Make sure the log is flushed.
if( GLog )
{
// This may be called from other thread, so set this thread as the master.
GLog->SetCurrentThreadAsMasterThread();
GLog->TearDown();
}

TerminateProcess(GetCurrentProcess(), GIsCriticalError ? 3 : 0);
}
else
{
// Tell the platform specific code we want to exit cleanly from the main loop.
PostQuitMessage( 0 );
}
}

可见传入 true 为参数的时候,直接把进程杀了,导致未执行 UGameInstance::ShutDown()