Replication problems

So i am following ue4 multiplayer guide, but i want to make first person game, rather than vehicle, so i tried to adapt it to my needs. But it does not work, logs are saying that client updates the position, but server does not, so it rolls client back and i dont why. Here is the part of code that should replicate movement, would appreciate any tips.


AIgoraCharacter::AIgoraCharacter()
{

	PrimaryActorTick.bCanEverTick = true;
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f);
	bReplicates = true;

	//Create a body
	//Body = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Body1P"));
	//Body->SetOnlyOwnerSee(false);
	//Body->SetupAttachment(GetCapsuleComponent());

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Create a CameraComponent	
	FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
	FirstPersonCameraComponent->SetupAttachment(GetMesh());
	FirstPersonCameraComponent->bUsePawnControlRotation = true;

	BootsComp = CreateDefaultSubobject<UIgoraClothingComponent>(TEXT("BootsComp"));
	BootsComp->SetupAttachment(GetMesh());

	HatComp = CreateDefaultSubobject<UIgoraClothingComponent>(TEXT("HatComp"));
	HatComp->SetupAttachment(GetMesh());

	MaskComp = CreateDefaultSubobject<UIgoraClothingComponent>(TEXT("MaskComp"));
	MaskComp->SetupAttachment(GetMesh());

	ShirtComp = CreateDefaultSubobject<UIgoraClothingComponent>(TEXT("ShirtComp"));
	ShirtComp->SetupAttachment(GetMesh());

	PantsComp = CreateDefaultSubobject<UIgoraClothingComponent>(TEXT("PantsComp"));
	PantsComp->SetupAttachment(GetMesh());

	//Set a base value for the sphere radis
	UsableDistance = 400.0f;

	//Setting up raycasting for picking things up
	CollisionParams.AddIgnoredActor(this);

	GunComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("GunComp"));
	GunComp->SetupAttachment(GetMesh());
}


void AIgoraCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(AIgoraCharacter, ServerState);
	DOREPLIFETIME(AIgoraCharacter, bIsAiming);
	DOREPLIFETIME(AIgoraCharacter, UsableDistance);
	DOREPLIFETIME(AIgoraCharacter, CameraStartLoc);
	DOREPLIFETIME(AIgoraCharacter, EndLocation);
	DOREPLIFETIME(AIgoraCharacter, Hit);
	DOREPLIFETIME(AIgoraCharacter, ActorHit);
	DOREPLIFETIME(AIgoraCharacter, CameraRot);
}


void AIgoraCharacter::BeginPlay()
{
	// Call the base class  
	Super::BeginPlay();

	if (HasAuthority())
	{
		NetUpdateFrequency = 100;
	}
	
	FirstPersonCameraComponent->AttachToComponent(GetMesh(), FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true), FName("HeadSocket"));

	GunComp->AttachToComponent(GetMesh(), FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true), FName("GripPoint"));

}

//////////////////////////////////////////////////////////////////////////
// Input

void AIgoraCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// set up gameplay key bindings
	check(PlayerInputComponent);

	// Bind jump events
	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	// Bind fire event
	PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AIgoraCharacter::ServerFire);

	// Bind movement events
	PlayerInputComponent->BindAxis("MoveForward", this, &AIgoraCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AIgoraCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);

	//handle collecting pickups button
	PlayerInputComponent->BindAction("Interact", IE_Pressed, this, &AIgoraCharacter::Interact);

	//Handle the open inventory button
	PlayerInputComponent->BindAction("ToggleInventory", IE_Pressed, this, &AIgoraCharacter::ToggleInventory);

	//Handle the aiming
	PlayerInputComponent->BindAction("Aim", IE_Pressed, this, &AIgoraCharacter::BeginAim);
	PlayerInputComponent->BindAction("Aim", IE_Released, this, &AIgoraCharacter::EndAim);

}

void AIgoraCharacter::ServerFire_Implementation()
{
	if (bIsAiming)
	{
		PlayGunParticles();
	}
}

void AIgoraCharacter::MoveForward(float Value)
{
	if (Value != 0.0f)
	{
		// add movement in that direction
		AddMovementInput(GetActorForwardVector(), Value);
		MovementValue = Value;
		bMoveForward = true;
	}
}

void AIgoraCharacter::MoveRight(float Value)
{
	if (Value != 0.0f)
	{
		// add movement in that direction
		AddMovementInput(GetActorRightVector(), Value);
		MovementValue = Value;
		bMoveRight = true;
	}
}

void AIgoraCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
	RotationRate = Rate;
	bAddYaw = true;
}

void AIgoraCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
	RotationRate = Rate;
	bAddPitch = true;
}

void AIgoraCharacter::Server_SendMove_Implementation(FCharacterMove Move)
{
	SimulateMove(Move);

	ServerState.LastMove = Move;
	ServerState.Transform = Move.Character->GetTransform();
}

bool AIgoraCharacter::Server_SendMove_Validate(FCharacterMove Move)
{
	if(Move.MovementValue > 1.01 || Move.MovementValue < -1.01)
		return false;
	if(Move.RotationRate > 1.01 || Move.RotationRate < -1.01)
		return false;
	if(Move.BaseTurnRate > 90.f || Move.BaseTurnRate < -90.f)
		return false;
	if(Move.BaseLookUpRate > 90.f || Move.BaseLookUpRate < -90.f)
		return false;
	return true;
}

void AIgoraCharacter::SimulateMove(FCharacterMove Move)
{
	if(Move.bMoveForward)
	{
		AddMovementInput(Move.Character->GetActorForwardVector(), Move.MovementValue); // tried Move.Character->AddMovementInput, same result
		UE_LOG(LogTemp, Warning, TEXT("Character Name: %s"), *Move.Character->GetName())
		UE_LOG(LogTemp, Warning, TEXT("Server state: %f"), ServerState.Transform.GetLocation().X)
		UE_LOG(LogTemp, Warning, TEXT("Character transform: %f"), Move.Character->GetTransform().GetLocation().X)
		UE_LOG(LogTemp, Warning, TEXT("Move.MovementValue: %f"), Move.MovementValue)
		UE_LOG(LogTemp, Warning, TEXT("Move.Character->GetActorForwardVector(): %f"),Move.Character->GetActorForwardVector().X)
		UE_LOG(LogTemp, Warning, TEXT("moved forward"))
	}
	if(Move.bMoveRight)
		Move.Character->AddMovementInput(Move.Character->GetActorRightVector(), Move.MovementValue);
	if(Move.bAddYaw)
		Move.Character->AddControllerYawInput(Move.RotationRate * Move.BaseTurnRate * Move.DeltaTime);
	if(Move.bAddPitch)
		Move.Character->AddControllerPitchInput(Move.RotationRate * Move.BaseLookUpRate * Move.DeltaTime);
}

void AIgoraCharacter::OnRep_ServerState()
{
	SetActorTransform(ServerState.Transform);
}

bool AIgoraCharacter::ShouldTickIfViewportsOnly() const
{
	return true;
}

void AIgoraCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	CheckForInteractable();
	if(IsLocallyControlled())
	{
		FCharacterMove Move;
		Move.Character = this;
		Move.DeltaTime = DeltaTime;
		Move.MovementValue = MovementValue;
		Move.RotationRate = RotationRate;
		Move.BaseLookUpRate = BaseLookUpRate;
		Move.BaseTurnRate = BaseTurnRate;
		Move.bMoveForward = bMoveForward;
		Move.bMoveRight = bMoveRight;
		Move.bAddPitch = bAddPitch;
		Move.bAddYaw = bAddYaw;
		Server_SendMove(Move);
		SimulateMove(Move);
		bMoveForward = false;
		bMoveRight = false;
		bAddYaw = false;
		bAddPitch = false;
	}
}

Logs:

c0959c214dce0e7ad62e856d0bc5a5a8

You don’t have to do any of this for character movement. If you are using AddMovementInput then that passes through to the movement component and that handles replication of movement for you.

Yes, i checked source code and figured it out, i cant understand how to add cheat protection tho, because i cant see anything like that in default movement replication.