How to start spectating from clients?

k, that was more painful than expected

First I tried to make a nice non intrusive utility function which just calls the correct functions on the playercontroller and be done with it, but ofc nothing is ever easy…

I ran full frontal into that problem [Spectator Pawn On Client Side][1], so long story short. As far as I can see there is no way to use spectating “correctly” without creating your own PlayerController class. To use my solution you will need to inherit your PlayerController from the class I added below, or you can also just add the code to your implementation of a PlayerController if you already have one. An example how to use it would be in my github test project [here][2] in the StartSpectating folder.

StartSpectatingPlayerController.h

#pragma once

#include "GameFramework/PlayerController.h"
#include "StartSpectatingPlayerController.generated.h"

UCLASS()
class AStartSpectatingPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	virtual void OnRep_Pawn() override;

	UFUNCTION(BlueprintCallable, Category = "Start Spectating Player Controller")
	void StartSpectating();

	UFUNCTION(Client, Reliable)
	void Client_StartSpectating();

	UFUNCTION(BlueprintCallable, Category = "Start Spectating Player Controller")
	void StartPlaying();
};

StartSpectatingPlayerController.cpp

#include "StartSpectatingPlayerController.h"
#include "GameFramework/SpectatorPawn.h"

void AStartSpectatingPlayerController::OnRep_Pawn()
{
	Super::OnRep_Pawn();

	if (GetStateName() == NAME_Spectating)
	{
		AutoManageActiveCameraTarget(GetSpectatorPawn());
	}
}

void AStartSpectatingPlayerController::StartSpectating()
{
	if (!HasAuthority())
		return;

	ChangeState(NAME_Spectating);
	Client_StartSpectating();
}

void AStartSpectatingPlayerController::StartPlaying()
{
	if (!HasAuthority())
		return;

	ChangeState(NAME_Playing); 
	ClientGotoState(NAME_Playing);
}

void AStartSpectatingPlayerController::Client_StartSpectating_Implementation()
{
	if (PlayerCameraManager)
		SetSpawnLocation(PlayerCameraManager->GetCameraLocation());

	ChangeState(NAME_Spectating);
}

and an example how to use it

more elaborate example with switching to spectator mode and going back