多客户端出现时间不同步的情况,,
由于每个客户端本地的时间,时区不同或者存在网络延迟造成的。所以为了能够使每个客户端显示的时间相同,就需要在Server上利用GetWorld()->GetTimeSeconds()获取服务器时间,然后传给客户端显示。
在传输过程中,要考虑到每个客户端的延迟需要做一些计算偏移,才能实现最终每个客户端的时间一致
利用RPC实现同步
UE中提过了RPC实现服务器和客户端的网络连接功能,其中ServerRPC表示在客户端调用,服务器执行,ClientRPC表示服务器调用,客户端执行。
在这里默认从客户端到服务器,从服务器到客户端的时间传输是一样的。
计算时间差
该时间差是指从客户端请求当前时间到服务器上调用ClientRPC后Client执行计算到的时间的差值,而该时间差就是产生每个客户端时间不同步的那些主要因素导致的。
- 首先在客户端上调用ServerRPC函数,该函数将接受客户端当前的时间GetTimeSeconds()作为参数,该时间作为起始时间,在服务器执行该函数,将得到服务器上当前时间
- 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;
}
}
标签:float,GetWorld,GetTimeSeconds,时间,UE,服务器,客户端
From: https://www.cnblogs.com/XTG111/p/17981048