UE 客户端和服务器上的时间同步

多客户端出现时间不同步的情况,,

由于每个客户端本地的时间,时区不同或者存在网络延迟造成的。所以为了能够使每个客户端显示的时间相同,就需要在Server上利用GetWorld()->GetTimeSeconds()获取服务器时间,然后传给客户端显示。
在传输过程中,要考虑到每个客户端的延迟需要做一些计算偏移,才能实现最终每个客户端的时间一致

利用RPC实现同步

UE中提过了RPC实现服务器和客户端的网络连接功能,其中ServerRPC表示在客户端调用,服务器执行,ClientRPC表示服务器调用,客户端执行。
在这里默认从客户端到服务器,从服务器到客户端的时间传输是一样的。

计算时间差

该时间差是指从客户端请求当前时间到服务器上调用ClientRPC后Client执行计算到的时间的差值,而该时间差就是产生每个客户端时间不同步的那些主要因素导致的。

  1. 首先在客户端上调用ServerRPC函数,该函数将接受客户端当前的时间GetTimeSeconds()作为参数,该时间作为起始时间,在服务器执行该函数,将得到服务器上当前时间
  2. ClientRPC将接受两个参数分别是客户端的起始时间和服务器当前时间,其中起始时间是用来计算RTT的,服务器当前时间是用来计算需要显示的时间的。
    Time_RTT = PreClientTime - NowClientTime。
    通过该RTT可以计算得到当服务器调用的ClientRPC函数在得到NowClientTime后,即该函数命令传递到客户端时,此时的ServerTime。
    NowServerTime = PreServerTime + RTT/2;
    当前的这个时间就应该是每个客户端最后应该显示的时间。为了分离,利用一个变量来接受差值NowServerTime - NowClientTime而不是直接的数值
void AXBlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequese)
{
	//获取接受时服务器的时刻
	float SeverTimeOfReceipt = GetWorld()->GetTimeSeconds();
	ClientReportServerTime(TimeOfClientRequese, SeverTimeOfReceipt);
}
//Client Run GetWorld()->GetTimeSeconds() is ClientCurrentTime
void AXBlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest)
{
	//计算RTT
	float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest;
	SingleTripTime = RoundTripTime * 0.5f;
	//ServerCurrentTime
	float CurrentServerTime = TimeServerReceivedClientRequest + SingleTripTime;

	ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds();
}

Tick调用

该过程是确保客户端始终保持同步,通过设置的时间间隔调用

void AXBlasterPlayerController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	SetHUDTime();
	CheckTimeSync(DeltaTime);
}
//在游戏过程中每隔一段时间同步服务器时间到客户端
void AXBlasterPlayerController::CheckTimeSync(float DeltaTime)
{

	TimeSyncRunningTime += DeltaTime;
	if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency)
	{
		ServerRequestServerTime(GetWorld()->GetTimeSeconds());
		TimeSyncRunningTime = 0.f;
	}
}

HUD显示时间

通过对不同游戏状态(比如游戏中,中途加入游戏或者等待)提供相应的偏移,然后加上之前获得的NowServerTime即可

获取ServerTime

float AXBlasterPlayerController::GetSeverTime()
{
  //服务器上执行
	if (HasAuthority())
	{
		return GetWorld()->GetTimeSeconds();

	}
//客户端上执行需要加上偏移量,最终显现的是服务器上时间
	else
	{
		return GetWorld()->GetTimeSeconds() + ClientServerDelta;
	}
}

作者:XTG111

出处:https://www.cnblogs.com/XTG111/p/17981048

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   XTG111  阅读(176)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示