I used to have the same problem and fixed it using
ChangeState(NAME_Spectating);
ClientGotoState(NAME_Spectating);
I’ve analyzed engine code and I don’t think bIsSpectator makes a difference. I moved on and started working on other features and at some point the problem came back. I must have changed something at some point that stopped it from working. When I try your solution of adding a delay, it works but as you’ve pointed out, it’s not ideal.
I’ve spent a few hours debugging and it seems like the function DestroySpectatorPawn() inside PlayerController is called AFTER changing state to spectator, so it creates (when changing states) and then destroys itself. Here’s the stack trace:
UE4Editor-Engine.dll!APlayerController::DestroySpectatorPawn() Line 4549 C++
UE4Editor-Engine.dll!APlayerController::ChangeState(FName NewState) Line 4591 C++
UE4Editor-Engine.dll!AController::PawnPendingDestroy(APawn * inPawn) Line 336 C++
UE4Editor-Engine.dll!APawn::DetachFromControllerPendingDestroy() Line 863 C++
UE4Editor-Engine.dll!APawn::Destroyed() Line 388 C++
UE4Editor-Engine.dll!UWorld::DestroyActor(AActor * ThisActor, bool bNetForce, bool bShouldModifyLevel) Line 586 C++
UE4Editor-Engine.dll!AActor::Destroy(bool bNetForce, bool bShouldModifyLevel) Line 3565 C++
UE4Editor-Engine.dll!UActorChannel::CleanUp(const bool bForDestroy) Line 1770 C++
UE4Editor-Engine.dll!UChannel::ConditionalCleanUp(const bool bForDestroy) Line 135 C++
UE4Editor-Engine.dll!UChannel::ReceivedSequencedBunch(FInBunch & Bunch) Line 313 C++
UE4Editor-Engine.dll!UChannel::ReceivedNextBunch(FInBunch & Bunch, bool & bOutSkipAck) Line 667 C++
UE4Editor-Engine.dll!UChannel::ReceivedRawBunch(FInBunch & Bunch, bool & bOutSkipAck) Line 388 C++
UE4Editor-Engine.dll!UNetConnection::ReceivedPacket(FBitReader & Reader) Line 1540 C++
UE4Editor-Engine.dll!UNetConnection::ReceivedRawPacket(void * InData, int Count) Line 933 C++
UE4Editor-OnlineSubsystemUtils.dll!UIpNetDriver::TickDispatch(float DeltaTime) Line 237 C++
UE4Editor-Engine.dll!TBaseUObjectMethodDelegateInstance<0,UNetDriver,void __cdecl(float)>::ExecuteIfSafe(float <Params_0>) Line 659 C++
UE4Editor-Engine.dll!TBaseMulticastDelegate<void,float>::Broadcast(float <Params_0>) Line 937 C++
UE4Editor-Engine.dll!UWorld::Tick(ELevelTick TickType, float DeltaSeconds) Line 1317 C++
UE4Editor-UnrealEd.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 1693 C++
UE4Editor-UnrealEd.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 401 C++
UE4Editor.exe!FEngineLoop::Tick() Line 3339 C++
UE4Editor.exe!GuardedMain(const wchar_t * CmdLine, HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, int nCmdShow) Line 166 C++
UE4Editor.exe!GuardedMainWrapper(const wchar_t * CmdLine, HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, int nCmdShow) Line 144 C++
UE4Editor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 223 C++
[External Code]
I’ve tried the solution posted above and unfortunately it doesn’t change anything for me as the spectator is not even spawning to begin with (or maybe it is but it’s being immediately destroyed for some reason)