How to start spectating from clients?

Hello, I have a blueprint-basded PlayerState, and I would like to set a player as spectator. The only way I found to achieve this would be to set bIsSpectator to true. The problem is that bIsSpectator is a blueprint read only variable, so my question is, is there a way to set that variable via blueprints? If not, is there a way to set a player as spectator without that variable?
Thank you

First things first,

the PlayerState is the wrong place to change spectating states,
this should be done on the PlayerController the PlayerState is mostly information about the player not control

second I looked into how to start spectating but as far as I can see it’s not possible to change to spectating state from blueprints, what you would need to do is call

void APlayerController::ChangeState(FName NewState)

from somewhere but there is no access through blueprint to that function,
if you are able to create and compile a C++ project I can write you a small function that is callable from blueprint which starts spectating, but without that I would say you are out of luck

Thank you so much for your reply!

Okay so I should get the reference to the PlayerState from the inherited variable that is in the PlayerController, cast to that and than do stuff?

if you are able to create and compile a C++ project I can write you a small function that is callable from blueprint which starts spectating

My project is actually based off of the Third Person C++ Example, so I believe I can.
If you can do that for me, it would really help, thank you so much!

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

Wow, thank you so much!
So, basically, If i already have a blueprints-based player controller, I simply swap that with this one, and add back the blueprint code by creating an inherited version of your cpp player controller?
Again thank you so much, you quite literally saved my life!

if you already have a blueprint-based player controller you just need to reparent it to the cpp player controller, ofc after compiling :stuck_out_tongue:

then you can use the start spectating functions similar to how I do it in the example.

Would be cool if you could change the question to something like:
How to start spectating on clients

to make it easier for other people to find the answer

Oh yeahh I forgot about the possibility to reparent stuff lol
Just changed it, I want people to see this, because your answer was very helpful!

Hello, sorry to bother you again, but I’m having some problems with the player controller that you made… when i compile it, it fails and it gives this error:

D:/UnrealProjects/cest workspace/Source/cest/Public/MyPlayerController.h(25) : Error: Expected an include at the top of the header: ‘#include “MyPlayerController.generated.h”’

I tried to add that, but then it started to give other errors that I couldnt fix, also cuz i know almost nothing about C++ ahah
Thanks in advance

no worries,

include “MyPlayerController.generated.h”, is used by unreal code generation magic, and you will always need to have it as the last include in your header file,

can you add the rest of your code with the code formatting option

plus the new error messages,
think you will need some formatting of the code I posted
smallest change that has to happen every mention of
StartSpectatingPlayerController needs to be replaced with MyPlayerController

I managed to make it work, as you said I replaced all the player controller references and it compiledd!!:slight_smile: Thank you!!
One thing I noticed tho is that the number of spectators and number of players in the gameMode don’t get updated by these changes for some reasons

I mean, togheter with what you made, I wanted to set bisspectator to true like this:

PlayerState->bIsSpectator = true;

Problem is that I have no idea how to add this in your code. Because I dont know how to get the access to the variable player state that is in the player controller

extended the code that I wrote to also set the bIsSpectator flag

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

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

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

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

	PlayerState->bIsSpectator = true;
	ChangeState(NAME_Spectating);
	Client_StartSpectating();
}

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

	PlayerState->bIsSpectator = false;
	ChangeState(NAME_Playing); 
	ClientGotoState(NAME_Playing);
}

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

	ChangeState(NAME_Spectating);
}

just a question maybe I never really understood what you want to do, do you want player joining as spectator or do you want to be able to switch between playing and spectating mode?

Thank you so much again, you’re reaally helping me out!
I have one last question tho, everything works fine, and now is spectator is set to true when the function is called; but for some reasons in the game mode, the number of spectators doesn’t get updated, is it related to replication or is it a complete different thing that I am missing?
Thank you again!

This goes back to my question do you want to be able to switch between spectating and playing or do you just want a player to be a spectator forever?

Because the

GetNumSpectators()

function of the game mode just takes players into consideration which have the bOnlySpectator flag set, so only players that are always and ever spectators, and not players that can switch in and out of being a spectator.

which leaves you with two options either also set bOnlySpectator which as long as you are not allowing for switching of spectating state is fine, or create a new Current Spectator Counter function.

Depending what you want to do with your spectators switching to spectator mode might also not be the way to go, I would only suggest to switch if for example you allow spectating after dying or something like that, if you want to create a game and have let’s say 5 players and 3 spectators, your session data which allows people to join will probably not be updated correctly if you switch to spectating mode after having joined.

Okay, I think I’ll stick with what I have right now… thank you so much again!

if you want to count the current spectators, this will work:

[Blueprint on Paste in][1]

Yess, I had something like that in mind aswell, thank you!!

StartAsSpectator in GameModeBase doesn’t activate bIsSpectate in PlayerState. Is something counting login controllers which with flag StartAsSpectator? Or it must be done on custom functionality?