Clients won't move character mesh relatively.

**[SOLVED]
**
I’m reaching to the community for help after hours of failures.
Quick summary of what I wanted to achieve:

  1. Client wants to prone so it calls a server function.
  2. Server sets bIsProned to true and replicates it clients, additionaly it sets additional parameters localy ( presented in code below )
  3. Clients call OnRep_bIsProned function locally to adjust the parameters aswell
  4. Both Server and Clients see the same thing:
    *main collision capsule is resized to a ball size
    *mesh sits right in the center of the secondary collision capsule
    *mesh also is visible above the ground

What I got:
1.-3. is the same.
4.a ( when local server wants to prone )
0584e0ecb4b0918985fc50daeceb90c11bbbe0e7.jpeg
4.b ( when client 1 wants to prone )
61b6217e6bc2dadeb17925e9c9652a5388b65756.jpeg

I also attach some code for further investigation of the problem


UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_IsProned, Category = Character)
		bool bIsProned = false;

	UFUNCTION()
		void OnRep_IsProned();


bool AToW_PlayerCharacter::CanProne()
{
	TArray< AActor * > OverlappingActors;
	ProneCapsuleCollision->GetOverlappingActors(OverlappingActors);
	return !bIsProned && GetRootComponent() && !GetRootComponent()->IsSimulatingPhysics() && (OverlappingActors.Num() <= 1);
}

bool AToW_PlayerCharacter::CanUnProne()
{
	TArray< AActor * > OverlappingActors;
	GetCapsuleComponent()->GetOverlappingActors(OverlappingActors);
	return bIsProned && GetRootComponent() && !GetRootComponent()->IsSimulatingPhysics() && (OverlappingActors.Num() <= 1);
}

void AToW_PlayerCharacter::ProneToggle()
{
	if (!bIsProned && CanProne() && bCanChangeState)
	{
		bCanChangeState = false;
		GetCharacterMovement()->MaxWalkSpeed = 0.0f;
		bIsProned = true;
		UpdateProneCollisionCapsule();
		bIsStanding = false;
		CurrentMovementState = PRONING;
		if (!bIsCrouching) RefreshMovementSpeedDelayed(fStandToProneTime);
		else
		{
			RefreshMovementSpeedDelayed(fCrouchToProneTime);
			bIsCrouching = false;
		}
	}
	else if (bIsProned && CanUnProne() && bCanChangeState)
	{
		bCanChangeState = false;
		GetCharacterMovement()->MaxWalkSpeed = 0.0f;
		bIsProned = false;
		UpdateProneCollisionCapsule();
		bIsStanding = true;
		CurrentMovementState = JOGGING;
		RefreshMovementSpeedDelayed(fStandToProneTime);
	}
	if (Role < ROLE_Authority)
	{
		ServerProne();
	}
}

void AToW_PlayerCharacter::ServerProne_Implementation()
{
	ProneToggle();
}

bool AToW_PlayerCharacter::ServerProne_Validate()
{
	return true;
}

void AToW_PlayerCharacter::OnRep_IsProned()
{
	if (Role < ROLE_Authority)
	{
		UpdateProneCollisionCapsule();
	}
}


void AToW_PlayerCharacter::UpdateProneCollisionCapsule()
{
	if (bIsProned)
	{
		ProneCapsuleCollision->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
		GetCapsuleComponent()->SetCapsuleHalfHeight(10.0f);
		ProneCapsuleCollision->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
		GetMesh()->AddRelativeLocation(FVector(0.0f, 0.0f, 60.0f));
		SetActorLocation(GetActorLocation() + FVector(0.0f, 0.0f, -25.0f));
	}
	else if (!bIsProned)
	{
		ProneCapsuleCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
		GetCapsuleComponent()->SetCapsuleHalfHeight(88.0f);
		ProneCapsuleCollision->SetRelativeLocation(FVector(0.0f, 0.0f, -60.0f));
		GetMesh()->AddRelativeLocation(FVector(0.0f, 0.0f, -60.0f));
		SetActorLocation(GetActorLocation() + FVector(0.0f, 0.0f, 25.0f));
	}
}


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

	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, RepRootMotion, COND_SimulatedOnly);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, ReplicatedBasedMovement, COND_SimulatedOnly);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, ReplicatedMovementMode, COND_SimulatedOnly);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, bIsCrouching, COND_SkipOwner);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, bIsProned, COND_SkipOwner);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, bIsStanding, COND_SkipOwner);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, bIsAiming, COND_SkipOwner);
	DOREPLIFETIME_CONDITION(AToW_PlayerCharacter, bCanChangeState, COND_SkipOwner);

	DOREPLIFETIME(AToW_PlayerCharacter, fAimingPitch);
	DOREPLIFETIME(AToW_PlayerCharacter, fAimingYaw);
}

Hope to hear a response soon!

Could it be a prediction issue?

Any relative location set on the character mesh which will not have a lasting effect because the client-side prediction of the CharacterMovementComponent overwrites the relative location every frame. The intended way to specify a relative offset for the client-side mesh in this case is to set the value of the Character’s BaseTranslationOffset FVector value. For the server you can still use AddRelativeOffset.



void AToW_PlayerCharacter::UpdateProneCollisionCapsule()
{
	if (bIsProned)
	{
		ProneCapsuleCollision->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
		GetCapsuleComponent()->SetCapsuleHalfHeight(10.0f);
		ProneCapsuleCollision->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
		GetMesh()->AddRelativeLocation(FVector(0.0f, 0.0f, 60.0f));
		**BaseTranslationOffset = FVector(0.0f, 0.0f, SomeZ);**
		SetActorLocation(GetActorLocation() + FVector(0.0f, 0.0f, -25.0f));
	}
	else if (!bIsProned)
	{
		ProneCapsuleCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
		GetCapsuleComponent()->SetCapsuleHalfHeight(88.0f);
		ProneCapsuleCollision->SetRelativeLocation(FVector(0.0f, 0.0f, -60.0f));
		GetMesh()->AddRelativeLocation(FVector(0.0f, 0.0f, -60.0f));
		**BaseTranslationOffset = FVector(0.0f, 0.0f, SomeOtherZ);**
		SetActorLocation(GetActorLocation() + FVector(0.0f, 0.0f, 25.0f));
	}
}


Thank you very much, NishokuZK! It worked like a charm :slight_smile:
Problem solved.

You’re welcome, glad I could help. :slight_smile:

How did you get UE4 to allow two different collision Spheres? When i add another it completely ignores it?