Switch Client between player and spectator?

I have 2 classes one is the default Character class and one is the default Spectator class. These are both setup in a Game Mode class. I want to be able to switch between a pawn being a player or a spectator at the press of a key. When a key is hit this function is called.

void AOnlineCharacter::SpectatorOn()
{
	for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
	{
		AOnlineController* TestPC = Cast<AOnlineController>(*It);
		if (TestPC && TestPC->IsLocalController())
		{
			TestPC->PlayerState->bIsSpectator = true;
			TestPC->ChangeState(NAME_Spectating);
		}
	}
}

This function is in my Character class and works fine on the Server side of things putting the player into a Spectator state using my custom spectator class, however on the client side it seems to break the clients controller so they are unable to move at all.

My knowledge on replication at the minute is slightly limited so I’m wondering if there is anything else I need to do in order for the client to switch between spectating and playing?

EDIT

My log shows that I get the warning ‘NULL GameState when trying to spawn spectator’ so I’m guessing only the server has access to the GameState so how do I access it from the Client?

UPDATE

Still seem to be getting this problem and can’t seem to find anything in the documentation to point me in the right direction.

I think the movement is handled on the server and the server never knows when you change the spectating mode on a client.

I think the most simple way to implement your desired behavior is: Annotate your SpectatorOn() method as server-side. Therefore add the following in the header:

UFUNCTION(Server, Reliable, WithValidation)
void AOnlineCharacter::SpectatorOn();

That means that an SpectorOn method is auto-generated and that you have to implement the methods:

void AOnlineCharacter::SpectatorOn_Implementation();
bool AOnlineCharacter::SpectatorOn_Validate();

which are called by the auto generated method. In Validate simply return true but in the Implementation method use the Controller that is an attribute of your Character class (is defined in the base class APawn):

auto CastController = Cast<AOnlineController>(Controller);
if(CastController) 
{
    // ....
}

I highly recommend that you watch those Videos although they are related to Blueprints: (they explain a lot about Network and replication) Blueprint Networking Tutorials - Unreal Engine

You find the same concepts in C++ when you browse the code of the Unreal-Engine, the classes ACharacter, ADefaultPawn, APawn have a lot of examples and also checkout the Shooter-Example.

Have a nice Day!

I’m having the same problem!

Hi fireapache,
did you tried to annonate the method as described in my answer?

Pots3 did my answer worked for you or did you run into further problems?

I have recently come back to this in the last couple of days after failing the first time around however I’m no longer trying to get the player as a spectator I’m simply trying to have the server set the clients position like so…

UFUNCTION(reliable, NetMulticast)
		void ClientSetCameraPosition(FVector Pos, FRotator rot);

This is called on the client…

 void AOnlineController::ClientSetCameraPosition_Implementation(FVector pos, FRotator rot)
{
	for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
	{
		AOnlineController* ThePC = Cast<AOnlineController>(*It);
		if (ThePC && ThePC->IsLocalController())
		{
			ThePC->GetPawn()->SetActorLocation(pos);
			ThePC->GetPawn()->SetActorRotation(rot);
		}
	}	
}

Again the client is however routed to (0, 0, 0) and never moves even though my clients implementation is constantly being hit with different positions from the server. So different method same problem.

DarthB, yes I did implement your suggestion, but the problem is that the client never properly possesses the spectator pawn, be cause in client side the key bindings doesn’t work… in server, everything ok.

I’ve not solved this problem, but I start to change state from playing to spectator only in client machines, the server don’t see these operations. When I want to go back to playing state, then I call a Reliable Server function to properly repossess the character again.

I think the main problem here is in spawning actors on server side and giving their control to client side controllers.

Posts3, as I’ve commented with DarthB, I’ve changing the controller state just in client machines… ok no other machines will see or interact with other spectators, but for my game this is not a problem.

When I want to repossess the original character, then I call a Reliable Server function in client side to properly possess and take control of this same character.

Hi Pots3,

Would you be able to clarify what you are trying to accomplish? It sounds like you want to be able to have the player controlling PawnA, then when you press a key PawnA becomes SpectatorA and when the key is pressed again it switches back. Is that correct?