You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: client.go
    path of file: ./repos/rivet/sdks/full/go/matchmaker/players
    
    the code of the file until where you have to start completion: // This file was auto-generated by Fern from our API Definition.

package players

import (
	bytes "bytes"
	context "context"
	json "encoding/json"
	errors "errors"
	io "io"
	http "net/http"
	sdk "sdk"
	core "sdk/core"
	matchmaker "sdk/matchmaker"
)

type Client struct {
	baseURL string
	caller  *core.Caller
	header  http.Header
}

func NewClient(opts ...core.ClientOption) *Client {
	options := core.NewClientOptions()
	for _, opt := range opts {
		opt(options)
	}
	return &Client{
		baseURL: options.BaseURL,
		caller:  core.NewCaller(options.HTTPClient),
		header:  options.ToHeader(),
	}
}

// Validates the player token is valid and has not already been consumed then
// marks the player as connected.
//
// # Player Tokens and Reserved Slots
//
// Player tokens reserve a spot in the lobby until they expire. This allows for
// precise matchmaking up to exactly the lobby's player limit, which is
// important for games with small lobbies and a high influx of players.
// By calling this endpoint with the player token, the player's spot is marked
// as connected and will not expire. If this endpoint is never called, the
// player's token will expire and this spot will be filled by another player.
//
// # Anti-Botting
//
// Player tokens are only issued by caling `lobbies.join`, calling `lobbies.find`, or
// from the `GlobalEventMatchmakerLobbyJoin` event.
// These endpoints have anti-botting measures (i.e. enforcing max player
// limits, captchas, and detecting bots), so valid player tokens provide some
// confidence that the p
    
func (c *Client) Connected(ctx context.Context, request *matchmaker.PlayerConnectedRequest) error {
	baseURL := "https://api.rivet.gg"
	if c.baseURL != "" {
		baseURL = c.baseURL
	}
	endpointURL := baseURL + "/" + "matchmaker/players/connected"

	errorDecoder := func(statusCode int, body io.Reader) error {
		raw, err := io.ReadAll(body)
		if err != nil {
			return err
		}
		apiError := core.NewAPIError(statusCode, errors.New(string(raw)))
		decoder := json.NewDecoder(bytes.NewReader(raw))
		switch statusCode {
		case 500:
			value := new(sdk.InternalError)
			value.APIError = apiError
			if err := decoder.Decode(value); err != nil {
				return apiError
			}
			return value
		case 429:
			value := new(sdk.RateLimitError)
			value.APIError = apiError
			if err := decoder.Decode(value); err != nil {
				return apiError
			}
			return value
		case 403:
			value := new(sdk.ForbiddenError)
			value.APIError = apiError
			if err := decoder.Decode(value); err != nil {
				return apiError
			}
			return value
		case 408:
			value := new(sdk.UnauthorizedError)
			value.APIError = apiError
			if err := decoder.Decode(value); err != nil {
				return apiError
			}
			return value
		case 404:
			value := new(sdk.NotFoundError)
			value.APIError = apiError
			if err := decoder.Decode(value); err != nil {
				return apiError
			}
			return value
		case 400:
			value := new(sdk.BadRequestError)
			value.APIError = apiError
			if err := decoder.Decode(value); err != nil {
				return apiError
			}
			return value
		}
		return apiError
	}

	if err := c.caller.Call(
		ctx,
		&core.CallParams{
			URL:          endpointURL,
			Method:       http.MethodPost,
			Headers:      c.header,
			Request:      request,
			ErrorDecoder: errorDecoder,
		},
	); err != nil {
		return err
	}
	return nil
}