How to destroy a PlayerController

I’m trying to implement a simple local multiplayer menu and game mode to test some game mechanics. Have a simple menu map that lets players join and select their character before the game starts. Creating the PlayerControllers was no problem, but I’m having trouble getting rid of them when players drop out. DestroyActor() was the closest thing I could find, but calling that on a PC doesn’t seem to do anything. I tried Unpossessing the PCs before destroying them, mostly for the hell of it, but it didn’t help. Is there another way of doing this that I’m just missing?

Thanks.

I was using blueprints before, but it seems like the C++ function APlayerController::Destroy() works. However, now I’m getting a different issue: When I load the game level Controllers are recreated for each one that ever lived. For example, if I make 4 Controllers and destroy 2 of them, 4 will spawn when the level is loaded.

Hi Andrew,

Sorry for the delay. What you might be seeing is when you call LoadMap, it will destroy the old map, and any actors in it. It will then re-create PlayerController’s for any local player still in the game.

If you are using seamless travel, this shouldn’t happen though, and the player controllers will transfer over. There are some details I might be leaving out, but this could be what is happening if you are not using seamless travel.

Hi,

We think this post contains useful information which we would like to share with our public UE4 community. With your approval, we would like to make a copy of this post on the public AnswerHub which includes the discussion but strips out your username and company name. Please let us know if you are okay with this.

Thanks!

I set the game mode to use seamless travel, but I was getting the same behavior when using the OpenLevel node. Then I made a BP node that calls UWorld::SeamlessTravel, but now the engine is crashing:

Unknown exception - code 00000001 (first/second chance not available)

Assertion failed: Vehicle != NULL [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.7\Engine\Source\Runtime\Engine\Private\Vehicles\PhysXVehicleManager.cpp] [Line: 221]

KERNELBASE + 35740 bytes
UE4Editor_Core!FOutputDeviceWindowsError::Serialize() + 292 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\core\private\windows\windowsplatformoutputdevices.cpp:95]
UE4Editor_Core!FOutputDevice::Logf__VA() + 248 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\core\private\misc\outputdevice.cpp:144]
UE4Editor_Core!FDebug::AssertFailed() + 1079 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\core\private\misc\outputdevice.cpp:224]
UE4Editor_Engine!FPhysXVehicleManager::RemoveVehicle() + 85 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\vehicles\physxvehiclemanager.cpp:222]
UE4Editor_Engine!UWheeledVehicleMovementComponent::DestroyPhysicsState() + 82 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\vehicles\wheeledvehiclemovementcomponent.cpp:647]
UE4Editor_Engine!UActorComponent::ExecuteUnregisterEvents() + 109 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\actorcomponent.cpp:968]
UE4Editor_Engine!UActorComponent::UnregisterComponent() + 404 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\actorcomponent.cpp:809]
UE4Editor_Engine!AActor::UnregisterAllComponents() + 253 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\actor.cpp:3191]
UE4Editor_Engine!ULevel::ClearLevelComponents() + 284 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\level.cpp:584]
UE4Editor_Engine!UWorld::ClearWorldComponents() + 149 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\world.cpp:1145]
UE4Editor_Engine!UWorld::CleanupWorld() + 532 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\world.cpp:2998]
UE4Editor_Engine!FSeamlessTravelHandler::Tick() + 3625 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\world.cpp:4605]
UE4Editor_Engine!UEngine::TickWorldTravel() + 65 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\engine\private\unrealengine.cpp:8264]
UE4Editor_UnrealEd!UEditorEngine::Tick() + 3829 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\editor\unrealed\private\editor.cpp:1267]
UE4Editor_UnrealEd!UUnrealEdEngine::Tick() + 22 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\editor\unrealed\private\unrealedengine.cpp:347]
UE4Editor!FEngineLoop::Tick() + 4179 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\launch\private\launchengineloop.cpp:2257]
UE4Editor!GuardedMain() + 1404 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\launch\private\launch.cpp:142]
UE4Editor!GuardedMainWrapper() + 26 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor!WinMain() + 249 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.7\engine\source\runtime\launch\private\windows\launchwindows.cpp:202]
UE4Editor!__tmainCRTStartup() + 329 bytes [f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c:618]

Also, what’s the difference calling SeamlessTravel() and ServerTravel() with the seamless flag set?

Looks like that bug has to do with VehiclePawns not being transitioned properly. Since I don’t really need the players to be driving in the menu, I skirted the issue by having them possess DefaultPawns instead. So now the SeamlessTravel works and I’m able to create and destroy the PlayerControllers, however for some reason I’m not able to recreate PCs that have already been created and destroyed once.

This is my Create/Destroy code:

void UKartGameInstance::AddLocalPlayer(uint8 ControllerId)
{
	UWorld* World = GetWorld();
	APlayerController* PC = UGameplayStatics::GetPlayerController(World, ControllerId);
	if (PC == NULL)
	{
		UGameplayStatics::CreatePlayer(World, ControllerId, true);
	}
}
void UKartGameInstance::DestroyLocalPlayer(uint8 ControllerId)
{
	UWorld* World = GetWorld();
	APlayerController* PC = UGameplayStatics::GetPlayerController(World, ControllerId);
	if (!!PC)
	{
		World->RemoveController(PC);
		PC->Destroy();
	}
}

Am I not properly cleaning up the Controllers? I feel like that’s the only reason I wouldn’t be able to remake them.

Hi Andrew,

If you’re trying to add/remove players to your game, you want to be adding/removing ULocalPlayers (which will have associated PlayerControllers), which can be done via UGameInstance::CreateLocalPlayer() and UGameInstance::RemoveLocalPlayer().

Have a look at how the debug execs DebugCreatePlayer and DebugRemovePlayer work for guidance.

Hope that helps!
Jeff

Thanks, Jeff. I was able to get it working with the following code:

void UKartGameInstance::AddLocalPlayer(uint8 ControllerId)
{
	FString Error;
	ULocalPlayer* player = this->CreateLocalPlayer(ControllerId, Error, true);
}

void UKartGameInstance::DestroyLocalPlayer(uint8 ControllerId)
{
	int32 Num = this->LocalPlayers.Num();
	for (int32 i = 0; i < Num; ++i)
	{
		if (this->LocalPlayers[i]->GetControllerId() == ControllerId)
		{
			this->RemoveLocalPlayer(this->LocalPlayers[i]);
			break;
		}
	}
}

Excellent, glad to help!

Sure, that’s fine with me.