LoadMap

跟踪分析

  1. TRACE_LOADTIME_REQUEST_GROUP_SCOPE LoadTime
    1. LLM_SCOPE 低级内存跟踪器 | Unreal Engine Documentation
    2. NETWORK_PROFILER 网络分析器(Network Profiler) | Unreal Engine Documentation
    3. MALLOC_PROFILER

卸载资源

  1. 检查level streaming isn’t frozen

  2. FCoreUObjectDelegates::PreLoadMap.Broadcast(URL.Map); 回调事件通知

  3. 注册析构函数PostLoadMap().

  4. 取消等待中的纹理流送请求UTexture2D::CancelPendingTextureStreaming(); 纹理流送概述 | Unreal Engine Documentation

  5. 卸载packageUEngine::CleanupPackagesToFullyLoad | Unreal Engine Documentation

    1
    2
    3
    4
    5
    6
    7
    if (WorldContext.World() && WorldContext.World()->PersistentLevel)
    {
    CleanupPackagesToFullyLoad(WorldContext, FULLYLOAD_Map, WorldContext.World()->PersistentLevel->GetOutermost()->GetName());
    }
    CleanupPackagesToFullyLoad(WorldContext, FULLYLOAD_Game_PreLoadClass, TEXT(""));
    CleanupPackagesToFullyLoad(WorldContext, FULLYLOAD_Game_PostLoadClass, TEXT(""));
    CleanupPackagesToFullyLoad(WorldContext, FULLYLOAD_Mutator, TEXT(""));
  6. 强制同步阻塞处理异步加载, 确保没有异步加载还在进行FlushAsyncLoading();

  7. 取消所有等待中的地图异步更改CancelPendingMapChange(WorldContext);, 需要保证FlushAsyncLoading();在这之前执行

  8. 卸载当前world

    1. 关闭网络ShutdownWorldNetDriver(WorldContext.World());

    2. 同步阻塞处理level streamingFlushLevelStreaming, UWorld::FlushLevelStreaming | Unreal Engine Documentation

    3. 向所有level广播卸载事件FWorldDelegates::LevelRemovedFromWorld.Broadcast(nullptr, WorldContext.World());

    4. 将玩家与玩家控制器断开

      1
      2
      3
      WorldContext.World()->DestroyActor(Player->PlayerController->GetPawn(), true);
      WorldContext.World()->DestroyActor(Player->PlayerController, true);
      Player->PlayerController = nullptr;
    5. 清除玩家的view state, 防止world不能彻底cleanPlayer->CleanupViewState(); ULocalPlayer::CleanupViewState | Unreal Engine Documentation

    6. 销毁world中的ActorActorIt->RouteEndPlay(EEndPlayReason::LevelTransition);

    7. 执行CleanupWorld, WorldContext.World()->CleanupWorld();, 需在销毁pawns/playercontrollers后, 防止生成新的事物(如丢掉的武器)

    8. 将world从root set移除WorldContext.World()->RemoveFromRoot();

    9. 标记object删除CastChecked<UWorld>(Level->GetOuter())->MarkObjectsPendingKill();

    10. 标记level删除CastChecked<UWorld>(LevelStreaming->GetLoadedLevel()->GetOuter())->MarkObjectsPendingKill();

    11. 移除audioAudioDevice->Flush(WorldContext.World());

    12. 设置当前world为空WorldContext.SetCurrentWorld(nullptr);

  9. 同步阻塞进行全量GC TrimMemory();.

  10. 移除强制驻留的资源IStreamingManager::Get().CancelForcedResources();

  11. 检查world是否清理完毕VerifyLoadMapWorldCleanup();

加载资源

  1. 调用注册函数预加载资源CurrentWorld->GetGameInstance()->PreloadContentForURL(PendingTravelURL);

  2. 检查如果是PIE instance, 就修改PIERemapPrefix来加载这份world拷贝, 而不是直接加载PIE world.

    1
    2
    NewWorld = UWorld::DuplicateWorldForPIE(SourceWorldPackage, nullptr);
    NewWorld->StreamingLevelsPrefix = UWorld::BuildPIEPackagePrefix(WorldContext.PIEInstance);
  3. 如果是minimal net rpc world则创建UGameInstance::CreateMinimalNetRPCWorld(*URL.Map, WorldPackage, NewWorld);

  4. 常规地图加载

    1. 设置world typeUWorld::WorldTypePreLoadMap.FindOrAdd( URLMapFName ) = WorldContext.WorldType; WorldTypePreLoadMap | Unreal Engine Documentation

    2. 检查level是否已经在内存中WorldPackage = FindPackage(nullptr, *URL.Map);

    3. 如果level不在地图中, 则从磁盘进行加载WorldPackage = LoadPackage(nullptr, *URL.Map, (WorldContext.WorldType == EWorldType::PIE ? LOAD_PackageForPIE : LOAD_None));

    4. PostLoad执行完毕后, 清理world type list.UWorld::WorldTypePreLoadMap.Remove( URLMapFName );

    5. 拿到加载完的worldNewWorld = UWorld::FindWorldInPackage(WorldPackage);

    6. persistent level初始化NewWorld->PersistentLevel->HandleLegacyMapBuildData();

    7. 如果是world type是PIE, 尝试复制一份PIE worldNewWorld = CreatePIEWorldByDuplication(WorldContext, NewWorld, URL.Map);. NewWorld = CreatePIEWorldByLoadingFromPackage(WorldContext, URL.Map, WorldPackage);

    8. 设置world的context

      1
      2
      3
      4
      NewWorld->SetGameInstance(WorldContext.OwningGameInstance);
      GWorld = NewWorld;
      WorldContext.SetCurrentWorld(NewWorld);
      WorldContext.World()->WorldType = WorldContext.WorldType;
    9. 如果不是PIE, 将world加入root节点WorldContext.World()->AddToRoot();, 并进行world初始化WorldContext.World()->InitWorld();

    10. 将PendingNetGame中的NetDriver对象赋值给新的world的NetDriverMovePendingLevel(WorldContext);

    11. 设置game modeWorldContext.World()->SetGameMode(URL); Game Mode 和 Game State | Unreal Engine Documentation

    12. audio device 初始化AudioDevice->SetDefaultBaseSoundMix(WorldContext.World()->GetWorldSettings()->DefaultBaseSoundMix);

    13. 监听客户端WorldContext.World()->Listen(URL)

    14. 处理异步完成的shader map, 并将其分配到对应的材质上GShaderCompilingManager->ProcessAsyncResults(false, true);

    15. 加载需要fully load的packageLoadPackagesFully(WorldContext.World(), FULLYLOAD_Map, WorldContext.World()->PersistentLevel->GetOutermost()->GetName());

    16. 确保”always loaded”子关卡已经全部加载完毕WorldContext.World()->FlushLevelStreaming(EFlushLevelStreamingType::Visibility);

    17. 在source level 完成创建后复制动态levelWorldContext.World()->DuplicateRequestedLevels(FName(*URL.Map));

    18. 初始化AI systemWorldContext.World()->CreateAISystem();

    19. 初始化level中的gameplayWorldContext.World()->InitializeActorsForPlay(URL, true, &Context);

    20. 初始化navigation systemFNavigationSystem::AddNavigationSystemToWorld(*WorldContext.World(), FNavigationSystemRunMode::GameMode);

    21. 为所有的local players创建player actor(*It)->SpawnPlayActor(URL.ToString(1),Error2,WorldContext.World())

    22. 通知stream manager开始texture streamingIStreamingManager::Get().NotifyLevelChange();

    23. XRsystem初始化GEngine->XRSystem->OnBeginPlay(WorldContext); XRSystem | Unreal Engine Documentation

  5. 开始game playWorldContext.World()->BeginPlay();

  6. 发送回调信息PostLoadMapCaller.Broadcast(WorldContext.World());

  7. 更新streamRedrawViewports(false);

  8. 从streaming manager中移除所有streaming views IStreamingManager::Get().RemoveStreamingViews( RemoveStreamingViews_All );