Devlog 4 - Client Inputs and Server Processing
So this is going to be a shorter post, but I just wanted to give a quick outline on how I'm handling client to server communication specfically for inputs.
First how do we handle client to server communication using UE5? It's actually quite simple on the outside Unreal let's us declare certain function on our PlayerController class that are designated to be RPC Calls
UFUNCTION(Server, Reliable)
void QueueInput(const FXYZInputMessage& InputMessage);
void QueueInput_Implementation(const FXYZInputMessage& InputMessage);
Assigning a UFUNCTION
to be Server
means that when this function is called on the client it will be executed on the remote server. Making it quite easy to send a payload of information from our client to the server on every input.
I created the payload as a Struct called XYZInputMessage
and it looks as follows
struct FXYZInputMessage
FString PlayerId;
TArray<int32> SelectedActors;
int32 XYZTargetActor;
FVector TargetLocation;
EXYZInputType InputType;
bool bQueueInput;
int32 AbilityIndex;
int32 ActiveActorId;
PlayerId
is the UniqueNetId that a player controller has this will help us know if the player that sent it is really the player that sent it :)SelectedActors
Let's us know which Units are to be handled in this current input you can learn more about that in my devlog about BlobsTargetActor
is what actor is being targetted this could be a follow, attack, etc inputTargetLocation
what location is this input targetting this is used for many things like moving, attack moving, etcbQueueInput
let's us know if this input should be added into the queue of a blob or if it should clear the blob queue and override the current actionAbilityIndex
let's us know what ability id is being told we are usingActiveActorId
is the type of actor that the ability id corresponds for example if in starcraft I have marines and marauders selected and I pressed stim the marines would be the active actor idInputType
is what kind of input are we telling the server it is there's many but ill give a few examples. MOVE, HOLD, STOP, FOLLOW, ATTACK_TARGET, ATTACK_MOVE, ABILITY
When the QueueInput function is executed on the remote server it then passes it along to the server's InputManager
which is processed every tick
InputManager->QueueInput(TickInput);
The InputManager
every process goes through it's InputQueue
and executes inputs that are valid
void Process(float DeltaTime)
{
for(;InputQueueIndex < InputQueue.Num();InputQueueIndex++)
{
ExecuteInput(InputQueue[InputQueueIndex]);
}
}
But what do these inputs turn into? Well every Input that a client does that the server needs to know is turned into an XYZAction
in our not so pretty XYZActionFactory
The factory takes in an InputMessage
and spits out one of the many actions
These actions are passed onto our blobs (group of units structure) which then processes the actions.
Here's a beautifully drawn diagram to show the flow
Thanks for reading!