I have a grenade actor in my multiplayer game with a root static mesh component that is set to simulate physics as follows:
ThrownMesh = ObjectInitializer.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("ThrownMeshComp"));
ThrownMesh->SetSimulatePhysics(true);
ThrownMesh->BodyInstance.bUseCCD = true;
ThrownMesh->SetCollisionObjectType(ECollisionChannel::ECC_PhysicsBody);
ThrownMesh->SetCollisionResponseToAllChannels(ECR_Block);
ThrownMesh->SetCollisionResponseToChannel(ECC_GameTraceChannel4, ECR_Ignore);
RootComponent = ThrownMesh;
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
SetRemoteRoleForBackwardsCompat(ROLE_SimulatedProxy);
bReplicates = true;
bReplicateMovement = true;
When a player throws the grenade it spawns the actor in the world and gives it an impulse:
FTransform SpawnTM(ShootDir.Rotation() + ThrownConfig.ThrownRotation, Origin);
if (ThrownConfig.ThrownClass)
{
AThrown* Thrown = Cast<AThrown>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ThrownConfig.ThrownClass, SpawnTM));
if (Thrown)
{
Thrown->Instigator = Instigator;
Thrown->SetOwner(this);
Thrown->DroppedOwner = GetPawnOwner();
if (!IsOverCooked && !bIsPlayerDead)
{
Thrown->InitDirectionImpulseAndPercentOfPawnVelocityToAdd(ShootDir, ThrownConfig.ThrownImpulse, ThrownConfig.PercentOfPawnVelocityToAdd);
}
//if this weapon is not primeable then we ignore the amount of time it was held
float TimeHeld = ThrownConfig.bIsPrimeable ? GetWorld()->TimeSeconds - TimeOfPinPull : 0;
float DetonationTime = IsOverCooked ? 0 : WeaponConfig.TimeToDetonation - TimeHeld;
Thrown->InitDetonationTime(DetonationTime);
Thrown->InitPercentTimeToWaitBeforeDispersingSmokeBlindness(WeaponConfig.PercentTimeToWaitBeforeDispersingSmokeBlindness);
UGameplayStatics::FinishSpawningActor(Thrown, SpawnTM);
}
}
Here is the impulse code:
void AThrown::InitDirectionImpulseAndPercentOfPawnVelocityToAdd(FVector& ShootDirection, float Impulse, float PercentOfPawnVelocityToAdd)
{
if (GetInstigatorController())
{
APawn * Pawn = GetInstigatorController()->GetPawn();
if (Pawn)
{
FVector PawnVelocity = Pawn->GetVelocity() * PercentOfPawnVelocityToAdd;
FVector ForwardDirection = ShootDirection;
float DotProduct = FVector::DotProduct(ForwardDirection, PawnVelocity);
ThrownMesh->AddImpulse(ShootDirection * Impulse + ForwardDirection * DotProduct);
ThrownMesh->AddTorque(ThrownMesh->GetRightVector() * 250000.0f);
}
}
}
This works great for the first 30 minutes of gameplay on the server but then it seems the physics simulation begins to slow down such that the grenade is slowly tumbling through the air and it explodes after its 5 second timer in the air. Oddly all character movement replication is unaffected and pings are great. Restarting the server resolves the issue.
Any ideas what could be causing this? I am going to turn off bUseCCD and see if that improves anything.