This page describes the end-to-end flow of Game Coordinator (GC) packets through the go-dota2 library: how HandleGCPacket receives and routes packets via the handlerMap, how the pendReq map tracks in-flight request/response calls via MakeRequest, and how connectionCtx and validateConnectionContext gate API execution based on session state.
For the SOCache object subscription and update flow, see page 2.1. For event struct definitions and emission patterns, see page 2.2.
The Dota2 struct client.go32-49 is the central hub for all communication. Inbound packets arrive at HandleGCPacket client.go156-177 are dispatched through a static handlerMap client.go29 and optionally matched against pending response registrations in pendReq client.go48 Outbound calls use one of two patterns: fire-and-forget (write) client.go116-118 or context-aware request/response (MakeRequest) client_request.go17-90 All API operations require a valid connectionCtx client.go38 which only exists when the GC session is in GCConnectionStatus_GCConnectionStatus_HAVE_SESSION state client_session.go125-127
| Field | Type | Role |
|---|---|---|
handlers | handlerMap | Routes inbound packets by message type ID |
pendReq | map[uint32]map[uint32]responseHandler | Tracks in-flight MakeRequest calls by response message type |
pendReqID | uint32 | Monotonic counter for request correlation |
connectionCtx | context.Context | Non-nil only when GCConnectionStatus_HAVE_SESSION |
state | state.Dota2State | Mutex-guarded session state including ConnectionStatus |
cache | *socache.SOCache | Receives cache updates from GC subscription messages |
Sources: client.go32-49 client.go156-177 client_request.go17-90 client_session.go125-127
The session follows a fixed sequence before any API calls can succeed. New client.go52-66 builds the handlerMap and registers the Dota2 struct as a packet handler with go-steam. SetPlaying(true) client_session.go14-24 tells Steam that Dota 2 (AppID = 570) is active. SayHello client_session.go27-38 sends CMsgClientHello to the GC. The GC responds with CMsgClientWelcome, which causes handleClientWelcome client_session.go59-79 to set connectionCtx and transition the state machine to HAVE_SESSION via setConnectionStatus client_session.go98-131
Session Establishment Sequence
Sources: client.go52-66 client.go83-113 client_session.go14-24 client_session.go27-38 client_session.go59-79 client_session.go98-131
All inbound GC packets enter through HandleGCPacket client.go156-177 The function filters by AppId == AppID client.go157-159 looks up the message type in d.handlers, and then calls handleResponsePacket client_request.go93-106 to check for pending MakeRequest matches. A packet may be handled by both a named handler and a pending response handler, or by neither, in which case an UnhandledGCPacket event is emitted client.go173-175
HandleGCPacket Dispatch Logic
Sources: client.go156-177 client_request.go93-106
buildHandlerMap client.go83-113 populates the handler table at construction time with several categories of entries:
| Category | Message Type Constant | Handler |
|---|---|---|
| Session | k_EMsgGCClientWelcome | handleClientWelcome |
| Session | k_EMsgGCClientConnectionStatus | handleConnectionStatus |
| Cache | k_ESOMsg_CacheSubscribed | handleCacheSubscribed |
| Cache | k_ESOMsg_UpdateMultiple | handleCacheUpdateMultiple |
| Cache | k_ESOMsg_CacheUnsubscribed | handleCacheUnsubscribed |
| Cache | k_ESOMsg_Destroy | handleCacheDestroy |
| System | k_EMsgGCPingRequest | handlePingRequest |
| Chat | k_EMsgGCChatMessage | getEventEmitter(ChatMessage) |
| Chat | k_EMsgGCJoinChatChannelResponse | getEventEmitter(JoinedChatChannel) |
| Invite | k_EMsgGCInvitationCreated | getEventEmitter(InvitationCreated) |
| Generated | (various) | registerGeneratedHandlers() |
handlePingRequest client.go180-183 immediately responds with CMsgGCClientPing via write to keep the session alive.
getEventEmitter client.go186-196 is a factory that returns a handler function; the returned function unmarshals the packet body using unmarshalBody client.go145-153 and calls d.emit(obj) client.go121-123 — forwarding the event to application code via the go-steam event bus.
Sources: client.go83-113 client.go145-153 client.go180-183 client.go186-196
API methods use one of two outbound patterns depending on whether the GC sends a response.
write)Used for operations where no response is expected. The method constructs a protobuf message and calls d.write client.go116-118 directly. No entry is created in pendReq.
write calls d.client.GC.Write(gamecoordinator.NewGCMsgProtobuf(AppID, messageType, msg)) — serializing the proto and sending it over the go-steam GC transport client.go117
MakeRequest)Used for operations where the GC sends a typed response. The method constructs a request proto, registers a responseHandler client_request.go14 in pendReq keyed by the expected response message type, then blocks on a channel until the response arrives or the context is canceled client_request.go82-89
Outbound Call Patterns
Sources: client.go116-118 client_request.go17-90
pendReq)pendReq is map[uint32]map[uint32]responseHandler client.go48 The outer key is the response message type. The inner key is a monotonically incrementing pendReqID client.go47 used to correlate a specific call. pendReqMtx client.go46 guards access.
When handleResponsePacket client_request.go93-106 processes an inbound packet, it looks up pendReq[packet.MsgType]. If any registered handlers are found, it executes them. If a handler returns true (indicating it matched the expected response), it is removed from the map client_request.go102
pendReq lifecycle for a single MakeRequest call
Sources: client.go46-48 client_request.go17-90 client_request.go93-106
The four SOCache-related message types are routed through the handlerMap to methods like handleCacheSubscribed client.go90-93 These handlers delegate to socache.SOCache client.go55 which maintains typed object containers and notifies subscribers. The full details of how SOCache manages object state are in page 2.1.
For unsolicited GC-to-client event messages, the handlerMap stores closures returned by getEventEmitter client.go186-196 These closures unmarshal the packet body and call d.emit client.go121-123 which delegates to d.client.Emit on the go-steam event bus. Generated event handlers registered by registerGeneratedHandlers follow the same pattern.
Sources: client.go55 client.go90-93 client.go121-123 client.go186-196
The client maintains connection state through context-based readiness tracking and explicit connection status management.
When the connection status changes to GCConnectionStatus_GCConnectionStatus_HAVE_SESSION, setConnectionStatus client_session.go98-131 creates a new connectionCtx client_session.go126 and connectionCtxCancel client_session.go126 If the connection is lost or the session becomes invalid, the context is canceled client_session.go121 and subsequent API calls return ErrNotReady client_session.go47-48 via validateConnectionContext client_session.go41-56
Sources: client_session.go41-56 client_session.go98-131 client.go25-26
Refresh this wiki