• UE4实现断线重连功能


    断线重连的整体逻辑是 设备离线后,根据需要决定是否保留pawn,还是设备重连后再重新生成一个,然后是断线重连时的验证方式,最后是playerstate重连后的属性保留

    1. 重载Playercontroller的PawnLeavingGame,这里是设备断线后,不会删除pawn,根据自己的需求决定是否需要修改,如果不需要保存pawn,没有必要重载该函数。
    void AMVNControllerBase::PawnLeavingGame()
    {
    	if (GetPawn() != NULL)
    	{
    		//GetPawn()->Destroy();
    		//SetPawn(NULL);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.如果要保留pawn的话,可以重载GameMode的AddInactivePlayer,这个函数原本是保留断线的playerstate的,如果也要保留pawn的话,可以在这个函数里参照保留PlayerState的方式,保存pawn,如果不需要保存pawn,没有必要重载该函数。

    void AVTTSGameModeBase::AddInactivePlayer(APlayerState* PlayerState, APlayerController* PC)
    {
    	check(PlayerState)
    		UWorld* LocalWorld = GetWorld();
    	// don't store if it's an old PlayerState from the previous level or if it's a spectator... or if we are shutting down
    	if (!PlayerState->IsFromPreviousLevel() && !MustSpectate(PC) && !LocalWorld->bIsTearingDown)
    	{
    		APlayerState* const NewPlayerState = PlayerState->Duplicate();
    		APawn* PolicePawn = PC->GetPawn();
    		if (NewPlayerState && PolicePawn)
    		{
    			// Side effect of Duplicate() adding PlayerState to PlayerArray (see APlayerState::PostInitializeComponents)
    			GameState->RemovePlayerState(NewPlayerState);
    
    			// make PlayerState inactive
    			NewPlayerState->SetReplicates(false);
    
    			// delete after some time
    			NewPlayerState->SetLifeSpan(InactivePlayerStateLifeSpan);
    			//设置自动删除的时间
    			PolicePawn->SetLifeSpan(InactivePlayerStateLifeSpan);
    			// On console, we have to check the unique net id as network address isn't valid
    			const bool bIsConsole = !PLATFORM_DESKTOP;
    			// Assume valid unique ids means comparison should be via this method
    			const bool bHasValidUniqueId = NewPlayerState->GetUniqueId().IsValid();
    			// Don't accidentally compare empty network addresses (already issue with two clients on same machine during development)
    			const bool bHasValidNetworkAddress = !NewPlayerState->SavedNetworkAddress.IsEmpty();
    			const bool bUseUniqueIdCheck = bIsConsole || bHasValidUniqueId;
    
    			// make sure no duplicates
    			for (int32 Idx = 0; Idx < InactivePlayerArray.Num(); ++Idx)
    			{
    				APlayerState* const CurrentPlayerState = InactivePlayerArray[Idx];
    				if ((CurrentPlayerState == nullptr) || CurrentPlayerState->IsPendingKill())
    				{
    					// already destroyed, just remove it
    					InactivePlayerArray.RemoveAt(Idx, 1);
    					InactivePawnArray.RemoveAt(Idx, 1);
    					Idx--;
    				}
    				else if ((!bUseUniqueIdCheck && bHasValidNetworkAddress && (CurrentPlayerState->SavedNetworkAddress == NewPlayerState->SavedNetworkAddress))
    					|| (bUseUniqueIdCheck && (CurrentPlayerState->GetUniqueId() == NewPlayerState->GetUniqueId())))
    				{
    					// destroy the playerstate, then remove it from the tracking
    					CurrentPlayerState->Destroy();
    					InactivePlayerArray.RemoveAt(Idx, 1);
    					InactivePawnArray.RemoveAt(Idx, 1);  //保存角色
    					Idx--;
    				}
    			}
    			InactivePlayerArray.Add(NewPlayerState);
    			InactivePawnArray.Add(PolicePawn);
    			// make sure we dont go over the maximum number of inactive players allowed
    			if (InactivePlayerArray.Num() > MaxInactivePlayers)
    			{
    				int32 const NumToRemove = InactivePlayerArray.Num() - MaxInactivePlayers;
    
    				// destroy the extra inactive players
    				for (int Idx = 0; Idx < NumToRemove; ++Idx)
    				{
    					APlayerState* const PS = InactivePlayerArray[Idx];
    					if (PS != nullptr)
    					{
    						PS->Destroy();
    					}
    				}
    
    				// and then remove them from the tracking array
    				InactivePlayerArray.RemoveAt(0, NumToRemove);
    				InactivePawnArray.RemoveAt(0, NumToRemove);
    			}
    		}
    	}
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    1. 同理如果需要重新获得之前保留的pawn的话,重载gamemode的restartPlayerAtPlayerStart,默认的话是直接生成新的pawn,如果你想直接使用就的pawn修改响应的逻辑
    2. 重载时设备的验证,GameMode的FindInactivePlayer函数,默认设备重连时会比较网络的UniqueId,如果一致那么会复制原本的设备的playerstate数据,但是如果你的客户端设备经过重启的话,是会识别成新的客户端,所以根据需要自己去决定是否修改验证方式。
    3. 重载PlayerState的CopyProperties,将你自定义的变量进行重新复制

    以上就是断线重连基本的涉及的函数了,这一切的前提是gamemode必须继承自AGameMode,然后如果你没有保留pawn,或者自己验证重新登录逻辑的话,只需要修改第5条对应的内容就可以实现断线重连了

  • 相关阅读:
    ROS1和ROS2的区别
    Go 文件操作
    2024如何恢复旧版的Chrome的主题样式
    springboot项目结构命名规范
    SVGRenderer 是 three.js 中的一个渲染器,用于将 3D 场景渲染到 SVG(可缩放矢量图形)元素中。
    嵌入式Linux应用开发-基础知识-第十九章驱动程序基石④
    基于SSM的志愿者管理系统
    linux mysql数据库备份
    Java手写背包问题算法应用拓展案例
    前端性能优化
  • 原文地址:https://blog.csdn.net/maxiaosheng521/article/details/132735892