World TimeSeconds vs. ServerWorld TimeSeconds

uem_s04_unacknowledged_move_queue

#1

Recently I revisited the idea of throwing out acknowledged moves and replaying a local simulation and it dawned on me that the client’s local world time and the server’s world time would likely be different because of a world start time delta. In this lecture, when we decide which moves to throw out based on time, we’re actually comparing the client’s local world time to the server’s world time. Since we’re essentially starting both up at the same time using the editor’s built-in server/client feature, the difference in world time is likely very small.

However, in a case where client and server might be a considerable distance from each other, I’m wondering what the effect would be in our Move.Time comparison. I attempted to draw this out and I think if the client and server timelines deviated too far due to a large enough start-up time delta, the server might actually appear to be running ahead of the client, and thus all moves would be thrown out and we might get some ‘jerk’ because we’re still resetting the actor to an out-of-date position.

Again this is all theoretical - client and server world times may never deviate far enough to matter. However, I did want to point out some interesting functions in GameState:

float AGameStateBase::GetServerWorldTimeSeconds() const
{
	UWorld* World = GetWorld();
	if (World)
	{
		return World->GetTimeSeconds() + ServerWorldTimeSecondsDelta;
	}

	return 0.f;
}

void AGameStateBase::UpdateServerTimeSeconds()
{
	UWorld* World = GetWorld();
	if (World)
	{
		ReplicatedWorldTimeSeconds = World->GetTimeSeconds();
	}
}

void AGameStateBase::OnRep_ReplicatedWorldTimeSeconds()
{
	UWorld* World = GetWorld();
	if (World)
	{
		ServerWorldTimeSecondsDelta = ReplicatedWorldTimeSeconds - World->GetTimeSeconds();
	}
}

As well as this property in GameStateBase.h:

/** Server TimeSeconds. Useful for syncing up animation and gameplay. */
UPROPERTY(Transient, ReplicatedUsing=OnRep_ReplicatedWorldTimeSeconds)
float ReplicatedWorldTimeSeconds;

In theory, if we’re the client we could use GetServerWorldTimeSeconds() instead of GetWorld()->TimeSeconds, and then when we’re comparing move times in ClearAcknowledgedMoves we’d actually be comparing two times that exist relative to the server’s timeline.

Again it’s hard to determine how much this would matter in a real-world simulation without observing the extreme cases. As a side project, I was thinking about adding some logic to KrazyKarts to dump time and position to a csv file so I can actually plot the movement-over-time graphs in a spreadsheet and observe the effects of using different timelines. I’ll post the results if I find anything interesting.

Anyway, I wanted to bring this up for discussion if anybody is interested. I’d love to hear your feedback.


#2

Very good point. I had naively assumed the times were being synchronised but it seems like one should indeed use the above functions instead. Nice find!

I mentioned this post in this text lecture


#3

How do I correctly implement this method call?

I included “GameFramework/GameStateBase.h” and tried using like this:

AGameStateBase* GameState;
Move.Time = GameState->GetServerWorldTimeSeconds();

And got this error: error C4700: uninitialized local variable ‘GameState’ used.
I also tried using AGameStateBase::GetServerWorldTimeSeconds() but it says it’s nonstatic.

Note: using AGameStateBase instead of AGameStateBase* results in 100% of memory use hence editor crash without the window with log and send info option.


#4

You can’t just create a null pointer and try to access it. You need to get hold of the actual game state object:

GetWorld()->GetGameState()

#5

Thanks, Sam! I’ll try it out. Now I have another question, this is probably not the apropriate place to ask it, but in one of the first lectures about Menu System you told you were going to show how to export our system to other projects and you ended up not showing it. I tried to do by myself manually moving the source code(menu system and game instance) and migrating the maps and the WBPs. I did the whole process by changing “PuzzlePlatforms” ocurrencies in the codes to the name of my new project. I also built the blueprints parts again(level BP on MainMenu map and ServerRow - hovering and click stuff). I also changed the default maps, transition maps and default game instance. But when I click play the Menu doesn’t appear. There is an important step that I’m missing?
Note: the compilation succeeded.
Note2: I already finished the course and loved it! Great job.
Note3: I managed this to work by only copying the MenuSystem files and creating the whole blueprint stuff from scratch and copying the gameinstance to a new game instance class. I was missing the reparenting of WBPs.


#6

Don’t we do just that in the 3rd section?


#7

Congratulations on finishing! Nice job.