void ACharacter::OnRep_ReplicatedBasedMovement() { if (Role != ROLE_SimulatedProxy) { return; } // Skip base updates while playing root motion, it is handled inside of OnRep_RootMotion if (IsPlayingNetworkedRootMotionMontage()) { return; } TGuardValue<bool> bInBaseReplicationGuard(bInBaseReplication, true); const bool bBaseChanged = (BasedMovement.MovementBase != ReplicatedBasedMovement.MovementBase || BasedMovement.BoneName != ReplicatedBasedMovement.BoneName); if (bBaseChanged) { // Even though we will copy the replicated based movement info, we need to use SetBase() to set up tick dependencies and trigger notifications. SetBase(ReplicatedBasedMovement.MovementBase, ReplicatedBasedMovement.BoneName); } // Make sure to use the values of relative location/rotation etc from the server. BasedMovement = ReplicatedBasedMovement; if (ReplicatedBasedMovement.HasRelativeLocation()) { // Update transform relative to movement base const FVector OldLocation = GetActorLocation(); const FQuat OldRotation = GetActorQuat(); MovementBaseUtility::GetMovementBaseTransform(ReplicatedBasedMovement.MovementBase, ReplicatedBasedMovement.BoneName, CharacterMovement->OldBaseLocation, CharacterMovement->OldBaseQuat); const FVector NewLocation = CharacterMovement->OldBaseLocation + ReplicatedBasedMovement.Location; if (ReplicatedBasedMovement.HasRelativeRotation()) { // Relative location, relative rotation FRotator NewRotation = (FRotationMatrix(ReplicatedBasedMovement.Rotation) * FQuatRotationMatrix(CharacterMovement->OldBaseQuat)).Rotator(); // TODO: need a better way to not assume we only use Yaw. NewRotation.Pitch = 0.f; NewRotation.Roll = 0.f; SetActorLocationAndRotation(NewLocation, NewRotation); } else { // Relative location, absolute rotation SetActorLocationAndRotation(NewLocation, ReplicatedBasedMovement.Rotation); } // When position or base changes, movement mode will need to be updated. This assumes rotation changes don't affect that. CharacterMovement->bJustTeleported |= (bBaseChanged || GetActorLocation() != OldLocation); INetworkPredictionInterface* PredictionInterface = Cast<INetworkPredictionInterface>(GetMovementComponent()); if (PredictionInterface) { PredictionInterface->SmoothCorrection(OldLocation, OldRotation); } } }
void ADynamicWeather::AdjustSunPositionBasedOnActorRotation() { const FVector Direction = - GetActorQuat().GetForwardVector(); const FVector2D SphericalCoords = Direction.UnitCartesianToSpherical(); Weather.SunPolarAngle = FMath::RadiansToDegrees(SphericalCoords.X); Weather.SunAzimuthAngle = FMath::RadiansToDegrees(SphericalCoords.Y); }
void ACharacter::SimulatedRootMotionPositionFixup(float DeltaSeconds) { const FAnimMontageInstance* ClientMontageInstance = GetRootMotionAnimMontageInstance(); if( ClientMontageInstance && CharacterMovement && Mesh ) { // Find most recent buffered move that we can use. const int32 MoveIndex = FindRootMotionRepMove(*ClientMontageInstance); if( MoveIndex != INDEX_NONE ) { const FVector OldLocation = GetActorLocation(); const FQuat OldRotation = GetActorQuat(); // Move Actor back to position of that buffered move. (server replicated position). const FSimulatedRootMotionReplicatedMove& RootMotionRepMove = RootMotionRepMoves[MoveIndex]; if( RestoreReplicatedMove(RootMotionRepMove) ) { const float ServerPosition = RootMotionRepMove.RootMotion.Position; const float ClientPosition = ClientMontageInstance->GetPosition(); const float DeltaPosition = (ClientPosition - ServerPosition); if( FMath::Abs(DeltaPosition) > KINDA_SMALL_NUMBER ) { // Find Root Motion delta move to get back to where we were on the client. const FTransform LocalRootMotionTransform = ClientMontageInstance->Montage->ExtractRootMotionFromTrackRange(ServerPosition, ClientPosition); // Simulate Root Motion for delta move. if( CharacterMovement ) { const float MontagePlayRate = ClientMontageInstance->GetPlayRate(); // Guess time it takes for this delta track position, so we can get falling physics accurate. if (!FMath::IsNearlyZero(MontagePlayRate)) { const float DeltaTime = DeltaPosition / MontagePlayRate; // Even with negative playrate deltatime should be positive. check(DeltaTime > 0.f); CharacterMovement->SimulateRootMotion(DeltaTime, LocalRootMotionTransform); // After movement correction, smooth out error in position if any. INetworkPredictionInterface* PredictionInterface = Cast<INetworkPredictionInterface>(GetMovementComponent()); if (PredictionInterface) { PredictionInterface->SmoothCorrection(OldLocation, OldRotation); } } } } } // Delete this move and any prior one, we don't need them anymore. UE_LOG(LogRootMotion, Log, TEXT("\tClearing old moves (%d)"), MoveIndex+1); RootMotionRepMoves.RemoveAt(0, MoveIndex+1); } } }
void ACharacter::PostNetReceiveLocationAndRotation() { if( Role == ROLE_SimulatedProxy ) { // Don't change transform if using relative position (it should be nearly the same anyway, or base may be slightly out of sync) if (!ReplicatedBasedMovement.HasRelativeLocation()) { const FVector OldLocation = GetActorLocation(); const FQuat OldRotation = GetActorQuat(); UpdateSimulatedPosition(ReplicatedMovement.Location, ReplicatedMovement.Rotation); INetworkPredictionInterface* PredictionInterface = Cast<INetworkPredictionInterface>(GetMovementComponent()); if (PredictionInterface) { PredictionInterface->SmoothCorrection(OldLocation, OldRotation); } } } }
void APawn::PostNetReceiveLocationAndRotation() { // always consider Location as changed if we were spawned this tick as in that case our replicated Location was set as part of spawning, before PreNetReceive() if( (ReplicatedMovement.Location == GetActorLocation() && ReplicatedMovement.Rotation == GetActorRotation()) && (CreationTime != GetWorld()->TimeSeconds) ) { return; } if( Role == ROLE_SimulatedProxy ) { // Correction to make sure pawn doesn't penetrate floor after replication rounding ReplicatedMovement.Location.Z += 0.01f; const FVector OldLocation = GetActorLocation(); const FQuat OldRotation = GetActorQuat(); SetActorLocationAndRotation(ReplicatedMovement.Location, ReplicatedMovement.Rotation, /*bSweep=*/ false); INetworkPredictionInterface* PredictionInterface = Cast<INetworkPredictionInterface>(GetMovementComponent()); if (PredictionInterface) { PredictionInterface->SmoothCorrection(OldLocation, OldRotation, ReplicatedMovement.Location, ReplicatedMovement.Rotation.Quaternion()); } } }