Need help on multiplayer c++ movement code

Hi I think I have a code that pretty much does the job but something is wrong. Characters are not moving at all and unexpected log output for Client’s path points. They never change. Server outputs seemingly good pathpoints. Also, distance between click location and pawn location is always about 85. Strange. The RPC calls get called many times for one click. Not sure why. Could just be repeated legitimate calls because mouse was held down. I haven’t check that yet.

It’s hard to explain, if you feel like analyzing just one 100 line cpp and offering help please do.

.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MobaScapeServerPlayerController.generated.h"


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

public:
	AMobaScapeServerPlayerController();

protected:
	TArray<FNavPathPoint> PathPoints;
	int32 PathPointsIndex;
	bool bMoveToMouseCursor;

	virtual void PlayerTick(float DeltaTime) override;
	virtual void SetupInputComponent() override;

	void LeftClickPressed();
	void LeftClickReleased();
	
	UFUNCTION(Reliable, Server, WithValidation)
	void ClientToServerMoveTo(const FVector DestLocation);

	UFUNCTION(Reliable, Client)
	void ServerToClientMoveTo(const float Distance, const FVector Direction, const FVector DestLocation);

	void MoveToCurrentPathPoint();
	void MoveToMouseCursor();
};

.cpp

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

#include "MobaScapeServerPlayerController.h"
#include "AI/Navigation/NavigationSystem.h"
#include "Runtime/Engine/Classes/Components/DecalComponent.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "MobaScapeServerCharacter.h"
#include "UnrealNetwork.h"
#include "AI/Navigation/NavigationPath.h"

//easily get my pawn
#define MyPawn						GetPawn()

//easily get this controller's pawn location
#define MyLocation					MyPawn->GetActorLocation()

//easily get the current path point
#define CurrentPathPoint			PathPoints[PathPointsIndex].Location

//Gets the path to a destination in a TArray<FNavPathPoint>
#define GetPathPoints(DestLocation) GetWorld()->GetNavigationSystem()->FindPathToLocationSynchronously(GetWorld(), MyLocation, (DestLocation), MyPawn)->GetPath()->GetPathPoints()

//Moves this controller's pawn on the server to the destination location the client sent and then moves the client
#define MoveMe(DestLocation)		float Distance = FVector::Dist(MyLocation, CurrentPathPoint);	\
									FVector Direction = CurrentPathPoint - MyLocation;				\
									MyPawn->AddMovementInput(Direction, Distance, false);			\
									ServerToClientMoveTo(Distance, Direction, (DestLocation))


//The Constructor
AMobaScapeServerPlayerController::AMobaScapeServerPlayerController()
{
	bShowMouseCursor = true;
	DefaultMouseCursor = EMouseCursor::Crosshairs;

	bReplicates = true;

	bMoveToMouseCursor = false;

	PathPointsIndex = 0;
	PathPoints = TArray<FNavPathPoint>();
}

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

	//Player clicked or is holding left click
	if (bMoveToMouseCursor)
	{
		MoveToMouseCursor();
	}
	//We aren't there yet
	else if (PathPointsIndex < PathPoints.Num())
	{
		if (MyPawn)
		{
			//Wait did we just get there?
			UE_LOG(LogTemp, Warning, TEXT("Distance: %f"), FVector::Dist(CurrentPathPoint, MyLocation));
			if (FVector::Dist(CurrentPathPoint, MyLocation) < .03f)
			{
				MoveMe(CurrentPathPoint);
				PathPointsIndex++;
			}
		}
	}
}

void AMobaScapeServerPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	InputComponent->BindAction("SetDestination", IE_Pressed, this, &AMobaScapeServerPlayerController::LeftClickPressed);
	InputComponent->BindAction("SetDestination", IE_Released, this, &AMobaScapeServerPlayerController::LeftClickReleased);
}

void AMobaScapeServerPlayerController::MoveToMouseCursor()
{
	if (Role < ROLE_Authority)
	{
		FHitResult Hit;
		GetHitResultUnderCursor(ECC_Visibility, false, Hit);

		if (Hit.bBlockingHit)
		{
			ClientToServerMoveTo(Hit.ImpactPoint);
		}
	}
}

void AMobaScapeServerPlayerController::ClientToServerMoveTo_Implementation(const FVector DestLocation)
{
	if (MyPawn)
	{
		PathPoints = GetPathPoints(DestLocation);
		for (int i = 0; i < PathPoints.Num(); i++)
		{
			UE_LOG(LogTemp, Warning, TEXT("PathPoints on server #%d: %s"), i, PathPoints[i].Location.ToString());
		}		
		PathPointsIndex = 0;
		MoveMe(CurrentPathPoint);
	}
}

bool AMobaScapeServerPlayerController::ClientToServerMoveTo_Validate(const FVector DestLocation)
{
	return true;
}

void AMobaScapeServerPlayerController::ServerToClientMoveTo_Implementation(const float Distance, const FVector Direction, const FVector DestLocation)
{
	if (MyPawn)
	{
		UE_LOG(LogTemp, Warning, TEXT("Checking NavSys on Client"));
		if (GetWorld()->GetNavigationSystem())
		{
			UE_LOG(LogTemp, Warning, TEXT("Good NavSys"));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Bad NavSys"));
		}

		PathPoints = GetPathPoints(DestLocation);
		for (int i = 0; i < PathPoints.Num(); i++)
		{
			UE_LOG(LogTemp, Warning, TEXT("PathPoints on client #%d: %s"), i, PathPoints[i].Location.ToString());
		}
		PathPointsIndex = 0;
		MyPawn->AddMovementInput(Direction, Distance, false);
	}
}

void AMobaScapeServerPlayerController::LeftClickPressed()
{
	bMoveToMouseCursor = true;
}

void AMobaScapeServerPlayerController::LeftClickReleased()
{
	bMoveToMouseCursor = false;
}

Maybe this is what’s going on. I’m not doing it right lol!

bReplicates

This property is actually required
for
the variable streaming that we covered in
the last section.
If
there is data to be synced, we enable this bool.

bReplicateMovement
This property will only be relevant to
actors
like the player or dwarf.
For
instance, the
AddMovementInput() and MoveToActor()
function
s
are
already network
ready.
So once we enable this and move our player, this
will stream
player movement correctly.

bReplicateInstigator
This property syncs the
Ownership
of an object.
This is important for 2
reasons: 1)
it lets the server know who owns the object in case it’
s trying to
call TakeD
amage
()
or a similar server
side function.
2)
it enables us to write code within the class that is Server
specific and Client
specific.