Well three days with no response I finally solved it. Hopefully this will aid anyone else looking to figure out this same problem. The following is psudocode you will need to properly adapt it to C++ for it to work.
First up my setup:
class CustomCharacter
{
// some class stuff here really not entirely important
};
class CustomPlayerController
{
public:
TSubobjectPtr<USpringArm> CameraBoom;
TSubobjectPtr<CameraComponent> Camera;
public:
CustomPlayerController()
{
this->PlayerCameraManagerClass = CustomCameraManager::StaticClass()
}
void BeginPlay() override
{
if(CustomCharacter * character = Cast<CustomCharacter>(this->GetPawn())
{
this->CameraBoom->AttachTo(character->GetRootComponent())
}
}
};
class CustomCameraManager
{
void UpdateViewTarget(FTViewTarget & OutVT, float DeltaTime)
{
if ((PendingViewTarget.Target != NULL) && BlendParams.bLockOutgoing && OutVT.Equal(ViewTarget))
{
return;
}
// store previous POV, incase we need it later
FMinimalViewInfo OrigPOV = OutVT.POV;
OutVT.POV.FOV = DefaultFOV;
OutVT.POV.OrthoWidth = DefaultOrthoWidth;
OutVT.POV.bConstrainAspectRatio = false;
OutVT.POV.ProjectionMode = this->bIsOrthographic ? ECameraProjectionMode::Orthographic : ECameraProjectionMode::Perspective;
OutVT.POV.PostProcessBlendWeight = 1.0f;
bool bDoNotApplyModifiers = false;
CustomPlayerController * customController = Cast<CustomPlayerController>(this->GetOwningPlayerController());
if (customController != NULL)
{
CustomCharacter * customPawn = Cast<CustomCharacter>(customController->GetPawn());
if (aPawn)
{
const FRotator pawnViewRotation = customPawn->GetViewRotation();
if (!pawnViewRotation.Equals(customController->CameraBoom->GetComponentRotation()))
{
customController->CameraBoom->SetWorldRotation(pawnViewRotation);
}
}
customController->Camera->AttachTo(customController->CameraBoom, USpringArmComponent::SocketName);
OutVT.POV.Location = customController->Camera->GetComponentLocation();
OutVT.POV.Rotation = customController->Camera->GetComponentRotation();
OutVT.POV.FOV = customController->Camera->FieldOfView;
OutVT.POV.AspectRatio = customController->Camera->AspectRatio;
OutVT.POV.bConstrainAspectRatio = customController->Camera->bConstrainAspectRatio;
OutVT.POV.ProjectionMode = customController->Camera->ProjectionMode;
OutVT.POV.OrthoWidth = customController->Camera->OrthoWidth;
OutVT.POV.PostProcessBlendWeight = customController->Camera->PostProcessBlendWeight;
if (customController->Camera->PostProcessBlendWeight > 0.0f)
{
OutVT.POV.PostProcessSettings = customController->Camera->PostProcessSettings;
}
if (!bDoNotApplyModifiers || this->bAlwaysApplyModifiers)
{
this->ApplyCameraModifiers(DeltaTime, OutVT.POV);
}
this->SetActorLocationAndRotation(OutVT.POV.Location, OutVT.POV.Rotation, false);
this->UpdateCameraLensEffects(OutVT);
}
else
{
Super::UpdateViewTarget(OutVT, DeltaTime);
}
}
}
The rotate View function was pretty much swiped directly from the documentation (with a few alterations where needed) Camera Manager UpdateView
Now the problem I was having with the whole having a “Crotch” view ended up being due to the behavior of the spring arm itself. It performs a collision check and excludes it’s owner, which under normal circumstances is the pawn itself… To fix this I gave the spring arm component an offset but this is only a temporary fix. To truely fix this problem I will need to subclass the USpringArm component and completely override the behavior of the UpdateDesiredArmLocation function to ignore collision against a designated pawn rather than the owner