Code Third Person - Multiplayer

Hey Guys,

So I have started a new project with the Code Third Person startup kit, I was reading about replication and how the pawns are automatically synched if replication is enabled, so I start two clients on one client I can move with point and click fine, on the other client however no pawn is loaded and instead the camera just stays in the middle of the level, I know both clients are connected because when on the client which has the pawn loaded I move to a location in front of the camera on client B I can see that the pawn is being synched properly.

On another note disabling the playercontroller and defaultpawn override in C++ actually makes it work, both clients connect to eachother in first person.

So my question is, what am I doing wrong? And why isnt the same process that creates the pawn for the first client not creating the pawn on the second connect client?

I am fairly new to Unreal so this is probably something trivial I have missed out.

Thank you.

Elyanar - can you try this: move the first client away from the starting spawn point, then type ‘reconnect’ on the second client. I noticed a bug in the third person code template where respawning doesn’t retry if the initial attempts. This is a work around until that bug can be fixed.

I was having this problem too, this does indeed fix it. Is there a way to setup a different spawn point for each client that connects?

At a quick glance, just adding a new spawn point doesn’t fix the issue. The problem is in the actual spawning / player controller state machine code (The server is never trying extra spawn points, or trying to respawn when the client clicks). I will need to dig a little deeper. This is working in some of our other games (Shooter game for example).

That seems to be a problem, although I dont know how there must be a way to assign another spawnpoint or a spawn position. Thank you very much for the help!

What happens I believe is that the actor fails it’s Pre-spawn checks: What happens when an Actor is spawned - Unreal Wiki and since there is something there the actor will not spawn.

What I did do get this to work was to override ChoosePlayerStart() in the gamemode class and from there you can return an appropriate starting location. If you iterate over all SpawnPoints (this is an TArray where all the starting position are stored) and check if there is a collision, if not return that player start location else keep looking. There is an example of this in the Shooter game, check the functions ChoosePlayerStart(), IsSpawnpointAllowed() and IsSpawnpointPreferred() in ShooterGameMode.h.

Hope it helps.

#ShooterGame Spawn Code

The entire code you need to add to your Game Mode class is right here:

This is from the shootergame example!

I use this code in my own project and I know it works for real multiplayer open ip games

#ShooterGame Game Mode Class

#.h

/** select best spawn point for player */
	virtual AActor* ChoosePlayerStart(AController* Player) OVERRIDE;


/** check if player can use spawnpoint */
	virtual bool IsSpawnpointAllowed(APlayerStart* SpawnPoint, AController* Player) const;

	/** check if player should use spawnpoint */
	virtual bool IsSpawnpointPreferred(APlayerStart* SpawnPoint, AController* Player) const;

#.cpp
AActor* AShooterGameMode::ChoosePlayerStart(AController* Player)
{
TArray<APlayerStart*> PreferredSpawns;
TArray<APlayerStart*> FallbackSpawns;

	for (int32 i = 0; i < PlayerStarts.Num(); i++)
	{
		APlayerStart* TestSpawn = PlayerStarts[i];
		if (IsSpawnpointAllowed(TestSpawn, Player))
		{
			if (IsSpawnpointPreferred(TestSpawn, Player))
			{
				PreferredSpawns.Add(TestSpawn);
			}
			else
			{
				FallbackSpawns.Add(TestSpawn);
			}
		}
	}

	APlayerStart* BestStart = NULL;
	if (PreferredSpawns.Num() > 0)
	{
		BestStart = PreferredSpawns[FMath::RandHelper(PreferredSpawns.Num())];
	}
	else if (FallbackSpawns.Num() > 0)
	{
		BestStart = FallbackSpawns[FMath::RandHelper(FallbackSpawns.Num())];
	}

	return BestStart ? BestStart : Super::ChoosePlayerStart(Player);
}

bool AShooterGameMode::IsSpawnpointAllowed(APlayerStart* SpawnPoint, AController* Player) const
{
	AShooterTeamStart* ShooterSpawnPoint = Cast<AShooterTeamStart>(SpawnPoint);
	if (ShooterSpawnPoint)
	{
		AShooterAIController* AIController = Cast<AShooterAIController>(Player);
		if (ShooterSpawnPoint->bNotForBots && AIController)
		{
			return false;
		}

		if (ShooterSpawnPoint->bNotForPlayers && AIController == NULL)
		{
			return false;
		}
	}

	return true;
}

bool AShooterGameMode::IsSpawnpointPreferred(APlayerStart* SpawnPoint, AController* Player) const
{
	ACharacter* MyPawn = Player ? Cast<ACharacter>(Player->GetPawn()) : NULL;
	if (MyPawn)
	{
		const FVector SpawnLocation = SpawnPoint->GetActorLocation();
		for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
		{
			ACharacter* OtherPawn = Cast<ACharacter>(*It);
			if (OtherPawn && OtherPawn != MyPawn)
			{
				const float CombinedHeight = (MyPawn->CapsuleComponent->GetScaledCapsuleHalfHeight() + OtherPawn->CapsuleComponent->GetScaledCapsuleHalfHeight()) * 2.0f;
				const float CombinedRadius = MyPawn->CapsuleComponent->GetScaledCapsuleRadius() + OtherPawn->CapsuleComponent->GetScaledCapsuleRadius();
				const FVector OtherLocation = OtherPawn->GetActorLocation();

				// check if player start overlaps this pawn
				if (FMath::Abs(SpawnLocation.Z - OtherLocation.Z) < CombinedHeight && (SpawnLocation - OtherLocation).Size2D() < CombinedRadius)
				{
					return false;
				}
			}
		}
	}

	return true;
}

You can also include the ShouldSpawnAtStartSpot function override:

// ShooterGameMode.h

/** always pick new random spawn */
virtual bool ShouldSpawnAtStartSpot(AController* Player) OVERRIDE;

// ShooterGameMode.cpp

bool AShooterGameMode::ShouldSpawnAtStartSpot(AController* Player)
{
	return false;
}

There is no reason to include the function below as you also have to create a new class “AShooterTeamStart”, and all it does is check if AI or player can spawn.

And the spawn points are still bugged, it seems that unless you repeatedly try to respawn the player, you will still get players re spawning on the same spawn point, not sure how shooter game is doing it, need to investigate.

> bool
> AShooterGameMode::IsSpawnpointAllowed(APlayerStart*
> SpawnPoint, AController* Player) const
>     {
>     AShooterTeamStart* ShooterSpawnPoint =
> Cast(SpawnPoint);
>     if (ShooterSpawnPoint)
>     {
>     AShooterAIController* AIController = Cast(Player);
>     if (ShooterSpawnPoint->bNotForBots && AIController)
>     {
>     return false;
>     }
>      
>     if (ShooterSpawnPoint->bNotForPlayers &&
> AIController == NULL)
>     {
>     return false;
>     }
>     }
>      
>     return true;
>     }

You must still call restartplayer for the repspawns to work.

Was there any resolution to this problem?

This is very helpful and i have to ask… could you show how to use this code to actually spawn a player with a controller in the world??? i mean it gets you the spawnpoints - ok. but i’m having problems to spawn actors? i wanted to spawn a ‘local’ second player.
this would be very helpful :slight_smile: