In order to reduce the amount of RPC’s sent over the network in my game, I have tried to make one of my RPC’s that was previously called on Tick, called by a Timer instead. Very simply:
void ABZGame_HoverCraft::UpdateState()
{
ServerUpdateState(InputStates);
}
bool ABZGame_HoverCraft::ServerUpdateState_Validate(FHoverMovementStates InInputStates)
{
return true;
}
void ABZGame_HoverCraft::ServerUpdateState_Implementation(FHoverMovementStates InInputStates)
{
ReplicatedInputStates = InInputStates;
}
void ABZGame_HoverCraft::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ABZGame_HoverCraft, ReplicatedInputStates);
}
All this does, is send a struct of the Input from the Clients keyboard (InputStates), to the Server. On doing so, the Server sets the Replicated Version of that input and subsequently sends that out to ALL clients, so that all clients are on the same page. Unless the Client is Locally Controlled (I.e, it’s the client that send that data) - in which case it uses the original states from the Keyboard.
What I want to do is simulate movement both Locally and on the Server, so that clients get instant feedback and can have their position regularly checked and updated from the Server via ReplicatedMovement.
The problem I’m facing is that simply putting this RPC on a timer prevents the Client from updating that struct. While that RPC is queued up in the Timer, I can’t seem to change the Input at all - so I have to wait for the RPC timer to go to the server before I can make a change, which at the moment is every second or so. In reality, this will be about every 0.1 - 0.2 seconds, but even then, that’s not fast enough. Previously, the input RPC was sent on Tick so it wasn’t a problem, but naturally it’s eating up bandwidth and needs to change.
This is how I’m setting the Timer, this is currently run on Tick, but I will likely drop it into OnRep_Controller so that it only checks when it needs to:
void ABZGame_HoverCraft::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
/* If we're the client, we want the server to simulate our input too, and update our position / rotation via Replicated Movement based on that. */
/* We simulate locally too, so the client gets instant feedback. 99% of the time these should be pretty much in sync - depending on latency. */
if (IsLocallyControlled())
{
if (!GetWorldTimerManager().TimerExists(TH_InputRPC))
{
GetWorldTimerManager().SetTimer(TH_InputRPC, this, &ABZGame_HoverCraft::UpdateState, TH_InputRPCDelay, true);
}
}
else if (GetWorldTimerManager().TimerExists(TH_InputRPC))
{
GetWorldTimerManager().ClearTimer(TH_InputRPC);
}
/* If we're not the local player, set the states from the replicated states so we see and hear engine stuff */
if (!IsLocallyControlled())
{
InputStates = ReplicatedInputStates;
}
}
So, any ideas why the input for the client is still so latent, even though the movement component uses InputStates and not ReplicatedInputStates?
It’s not really acceptable for me to have to send an RPC on tick so that the Client get’s instant feedback. I don’t see any reason why this wouldn’t work.