TeamSpawnAssigner.cs
using Sandbox;
using System.Linq;

public sealed class TeamSpawnAssigner : Sandbox.Component, Sandbox.Component.INetworkListener
{
	private int _nextTeamIndex;

	public void OnActive( Connection connection )
	{
		if ( !Networking.IsHost )
			return;

		var config = GameObject.Scene.GetAllComponents<TeamSpawnConfig>().FirstOrDefault();
		if ( config is null )
		{
			Log.Warning( "No TeamSpawnConfig found in scene." );
			return;
		}

		var playerController = GameObject.Scene.GetAllComponents<ButtonMasherPlayerController>()
			.FirstOrDefault( c => c.GameObject.Network.Owner == connection );
		if ( playerController is null )
		{
			Log.Warning( $"No ButtonMasherPlayerController found for connection {connection.DisplayName}." );
			return;
		}

		var team = (_nextTeamIndex++ % 2 == 0)
			? ButtonMasherPlayerController.TeamType.Player1
			: ButtonMasherPlayerController.TeamType.Player2;

		playerController.Team = team;
		playerController.Name = connection.DisplayName;
		playerController.Health = playerController.MaxHealth;
		playerController.IsDead = false;

		var spawn = config.GetSpawnForTeam( team );
		if ( spawn is not null && spawn.IsValid() )
		{
			playerController.OriginalSpawn = spawn;

			Log.Info( $"[Assign] {playerController.Name} team {team} original spawn = {spawn.Name} at {spawn.WorldPosition}" );

			playerController.GameObject.WorldPosition = spawn.WorldPosition;
			playerController.GameObject.WorldRotation = spawn.WorldRotation;
		}
		else
		{
			Log.Warning( $"No spawn found for team {team}." );
		}

		Log.Info( $"Spawned {playerController.Name} on {team} at {spawn?.Name ?? "default"}." );
	}
}