Making the TopDown example multiplayer ready

I have some problems to make the TopDown example multiplayer ready.


// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/PlayerController.h"
#include "ArenaPlayerController.generated.h"

UCLASS()
class AArenaPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	AArenaPlayerController();

protected:
	/** True if the controlled character should navigate to the mouse cursor. */
	uint32 bMoveToMouseCursor : 1;

	// Begin PlayerController interface
	virtual void PlayerTick(float DeltaTime) override;
	virtual void SetupInputComponent() override;
	// End PlayerController interface

	/** Navigate player to the current mouse cursor location. */
	void MoveToMouseCursor();

	/** Navigate player to the given world location. */
	void SetNewMoveDestination(const FVector DestLocation);

	/** Input handlers for SetDestination action. */
	void OnSetDestinationPressed();
	void OnSetDestinationReleased();
	UFUNCTION(Server,WithValidation,Unreliable)
	void ServerMoveTo(const FVector Dest);
	void ServerMoveTo_Implementation(const FVector Dest);
	bool ServerMoveTo_Validate(const FVector Dest);

	void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override;
};



// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "Arena.h"
#include "Engine.h"
#include "ArenaPlayerController.h"
#include "AI/Navigation/NavigationSystem.h"

AArenaPlayerController::AArenaPlayerController()
{
	bShowMouseCursor = true;
	DefaultMouseCursor = EMouseCursor::Crosshairs;
	SetReplicates(true);
}

void AArenaPlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);

	// keep updating the destination every tick while desired
	if (bMoveToMouseCursor)
	{
		MoveToMouseCursor();
	}
}

void AArenaPlayerController::SetupInputComponent()
{
	// set up gameplay key bindings
	Super::SetupInputComponent();

	InputComponent->BindAction("SetDestination", IE_Pressed, this, &AArenaPlayerController::OnSetDestinationPressed);
	InputComponent->BindAction("SetDestination", IE_Released, this, &AArenaPlayerController::OnSetDestinationReleased);
}

void AArenaPlayerController::MoveToMouseCursor()
{
	// Trace to see what is under the mouse cursor
	FHitResult Hit;
	GetHitResultUnderCursor(ECC_Visibility, false, Hit);

	if (Hit.bBlockingHit)
	{
		// We hit something, move there
		ServerMoveTo(Hit.ImpactPoint);
	}
}


void AArenaPlayerController::SetNewMoveDestination(const FVector DestLocation)
{
	APawn* const Pawn = GetPawn();
	if (Pawn)
	{
		UNavigationSystem* const NavSys = UNavigationSystem::GetCurrent(this);
		float const Distance = FVector::Dist(DestLocation, Pawn->GetActorLocation());

		// We need to issue move command only if far enough in order for walk animation to play correctly
		if (NavSys && (Distance > 120.0f))
		{
			NavSys->SimpleMoveToLocation(this, DestLocation);
		}
	}
}

void AArenaPlayerController::OnSetDestinationPressed()
{
	// set flag to keep updating destination until released
	bMoveToMouseCursor = true;
}

void AArenaPlayerController::OnSetDestinationReleased()
{
	// clear flag to indicate we should stop updating the destination
	bMoveToMouseCursor = false;
}

void AArenaPlayerController::ServerMoveTo_Implementation(const FVector Dest)
{
	SetNewMoveDestination(Dest);
}

void AArenaPlayerController::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
}

bool AArenaPlayerController::ServerMoveTo_Validate(const FVector Dest)
{
	return true;
}


The basic idea was to just send the move destination to the server, then move the pawn on the server and replicate the move back to all clients.

The first problem is that the rotation and animation is not played on the owning client. It works on the simulated clients.

The second problem is that the movement is stuttering.

Could someone explain to me why this happens? Doesn’t the MovementComponent replicate the rotation position automatically or do I need to do this manually?

It took me way too long but I finally got it working. I will upload it in the next couple of days to GitHub if anyone is interested in this.

Hi maikklein. Did you manage to sort out the stuttering issue?