/** Change the Pawn's base. */ void ACharacter::SetBase( UPrimitiveComponent* NewBaseComponent, bool bNotifyPawn ) { if (NewBaseComponent != MovementBase) { // Verify no recursion. APawn* Loop = (NewBaseComponent ? Cast<APawn>(NewBaseComponent->GetOwner()) : NULL); for( ; Loop!=NULL; Loop=Cast<APawn>(Loop->GetMovementBase()) ) { if( Loop == this ) { UE_LOG(LogCharacter, Warning, TEXT(" SetBase failed! Recursion detected. Pawn %s already based on %s."), *GetName(), *NewBaseComponent->GetName()); return; } } // Set base. MovementBase = NewBaseComponent; if (Role == ROLE_Authority) { // Update replicated value UE_LOG(LogCharacter, Verbose, TEXT("Setting base on server for '%s' to '%s'"), *GetName(), *GetFullNameSafe(NewBaseComponent)); RelativeMovement.MovementBase = NewBaseComponent; RelativeMovement.bServerHasBaseComponent = (NewBaseComponent != NULL); // Flag whether the server had a non-null base. } else { UE_LOG(LogCharacter, Verbose, TEXT("Setting base on CLIENT for '%s' to '%s'"), *GetName(), *GetFullNameSafe(NewBaseComponent)); } // Update relative location/rotation if ( Role == ROLE_Authority || Role == ROLE_AutonomousProxy ) { if (MovementBaseUtility::UseRelativePosition(MovementBase)) { RelativeMovement.Location = GetActorLocation() - MovementBase->GetComponentLocation(); RelativeMovement.Rotation = (FRotationMatrix(GetActorRotation()) * FRotationMatrix(MovementBase->GetComponentRotation()).GetTransposed()).Rotator(); } } // Notify this actor of his new floor. if ( bNotifyPawn ) { BaseChange(); } if (MovementBase && CharacterMovement) { // Update OldBaseLocation/Rotation as those were referring to a different base CharacterMovement->OldBaseLocation = MovementBase->GetComponentLocation(); CharacterMovement->OldBaseRotation = MovementBase->GetComponentRotation(); } } }
/** Change the Pawn's base. */ void ACharacter::SetBase( UPrimitiveComponent* NewBaseComponent, const FName InBoneName, bool bNotifyPawn ) { // If NewBaseComponent is null, ignore bone name. const FName BoneName = (NewBaseComponent ? InBoneName : NAME_None); // See what changed. const bool bBaseChanged = (NewBaseComponent != BasedMovement.MovementBase); const bool bBoneChanged = (BoneName != BasedMovement.BoneName); if (bBaseChanged || bBoneChanged) { // Verify no recursion. APawn* Loop = (NewBaseComponent ? Cast<APawn>(NewBaseComponent->GetOwner()) : NULL); for( ; Loop!=NULL; Loop=Cast<APawn>(Loop->GetMovementBase()) ) { if( Loop == this ) { UE_LOG(LogCharacter, Warning, TEXT(" SetBase failed! Recursion detected. Pawn %s already based on %s."), *GetName(), *NewBaseComponent->GetName()); return; } } // Set base. UPrimitiveComponent* OldBase = BasedMovement.MovementBase; BasedMovement.MovementBase = NewBaseComponent; BasedMovement.BoneName = BoneName; if (CharacterMovement) { if (bBaseChanged) { MovementBaseUtility::RemoveTickDependency(CharacterMovement->PrimaryComponentTick, OldBase); MovementBaseUtility::AddTickDependency(CharacterMovement->PrimaryComponentTick, NewBaseComponent); } if (NewBaseComponent) { // Update OldBaseLocation/Rotation as those were referring to a different base // ... but not when handling replication for proxies (since they are going to copy this data from the replicated values anyway) if (!bInBaseReplication) { CharacterMovement->SaveBaseLocation(); } // Enable pre-cloth tick if we are standing on a physics object, as we need to to use post-physics transforms CharacterMovement->PreClothComponentTick.SetTickFunctionEnable(NewBaseComponent->IsSimulatingPhysics()); } else { BasedMovement.BoneName = NAME_None; // None, regardless of whether user tried to set a bone name, since we have no base component. BasedMovement.bRelativeRotation = false; CharacterMovement->CurrentFloor.Clear(); CharacterMovement->PreClothComponentTick.SetTickFunctionEnable(false); } if (Role == ROLE_Authority || Role == ROLE_AutonomousProxy) { BasedMovement.bServerHasBaseComponent = (BasedMovement.MovementBase != NULL); // Also set on proxies for nicer debugging. UE_LOG(LogCharacter, Verbose, TEXT("Setting base on %s for '%s' to '%s'"), Role == ROLE_Authority ? TEXT("Server") : TEXT("AutoProxy"), *GetName(), *GetFullNameSafe(NewBaseComponent)); } else { UE_LOG(LogCharacter, Verbose, TEXT("Setting base on Client for '%s' to '%s'"), *GetName(), *GetFullNameSafe(NewBaseComponent)); } } // Notify this actor of his new floor. if ( bNotifyPawn ) { BaseChange(); } } }