I’m trying to have the character who goes ragdoll when killed, then can be revived by another player. Everything works fine, but sometimes different players see the character in different places after he went ragdoll. The problem is that the physics simulation ends up with different location of the mesh on different clients. I don’t want to replicate the exact pose of the mesh, but at least have the root bone in the same place, so when the character is revived, he appears in the same place for everybody.
I’ve also noticed that - as also mentioned in another post - during the ragdoll the CapsuleComponent is detached from the Mesh and I’ve to attach it back manually.
Here my code:
void AMyCharacterPlayer::OnDeath(float KillingDamage, struct FDamageEvent const& DamageEvent, class APawn* PawnInstigator, class AActor* DamageCauser)
{
if (bIsDying)
{
return;
}
bIsDying = true;
APlayerController* PC = Cast<APlayerController>(Controller);
if (Role == ROLE_Authority)
{
if (PC)
{
PC->SetIgnoreMoveInput(true);
}
// disable collisions on capsule
ReviveCollision = CapsuleComponent->GetCollisionEnabled();
ReviveCollisionResponse = CapsuleComponent->GetCollisionResponseToChannels();
CapsuleComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
CapsuleComponent->SetCollisionResponseToAllChannels(ECR_Ignore);
CharacterMovement->StopMovementImmediately();
CharacterMovement->SetMovementMode(EMovementMode::MOVE_None);
RepDeath();
}
}
void AMyCharacterPlayer::RepDeath_Implementation()
{
ReviveActorCollision = GetActorEnableCollision();
SetActorEnableCollision(true);
if (Mesh)
{
ReviveCollisionProfileName = Mesh->GetCollisionProfileName();
static FName CollisionProfileName(TEXT("Ragdoll"));
Mesh->SetCollisionProfileName(CollisionProfileName);
ReviveTransform = Mesh->GetRelativeTransform();
Mesh->SetAllBodiesBelowSimulatePhysics(Mesh->GetBoneName(1), true);
Mesh->SetSimulatePhysics(true);
Mesh->SetEnablePhysicsBlending(true);
Mesh->WakeAllRigidBodies();
}
}
void AMyCharacterPlayer::Revive()
{
if (!bIsDying)
{
return;
}
bIsDying = false;
APlayerController* PC = Cast<APlayerController>(Controller);
if (PC)
{
PC->SetIgnoreMoveInput(false);
}
CapsuleComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
CapsuleComponent->SetCollisionProfileName(TEXT("Pawn"));
CharacterMovement->SetMovementMode(EMovementMode::MOVE_Falling);
SetActorLocation(Mesh->GetSocketLocation(Mesh->GetBoneName(0)) + FVector(0.0f, 0.0f, CapsuleComponent->GetScaledCapsuleHalfHeight()));
RepRevive();
}
void AMyCharacterPlayer::RepRevive_Implementation()
{
if (Mesh)
{
Mesh->SetSimulatePhysics(false);
Mesh->PutRigidBodyToSleep();
Mesh->AttachTo(CapsuleComponent);
Mesh->SetRelativeTransform(ReviveTransform);
}
}