This page describes how go-dota2 keeps its Go API surface in sync with Valve's protobuf definitions automatically. It covers the full pipeline from the upstream .proto submodule through preprocessing, compilation, and API code generation to the final Go output files.
The generation process is coordinated by cmd/generate/main.go and produces two primary output files from Valve's .proto definitions. The pipeline is designed to be self-contained, using Go-based tools and WASI-compiled protoc to avoid external system dependencies.
Diagram: Code Generation Pipeline — File and Function Topology
Sources: cmd/generate/main.go51-106 apigen/api_generate.go18-78
The generator/Protobufs directory is a git submodule pointing to Valve's official protobuf repository. It is the sole external input to the pipeline.
The generation logic in cmd/generate/main.go ensures this submodule is initialized and updated to the latest commit defined in the parent repository unless the -skip-submodule flag is provided cmd/generate/main.go67-72 This is also automated via GitHub Actions every 3 days .github/workflows/update-protos.yml4-24
Sources: cmd/generate/main.go67-72 .github/workflows/update-protos.yml4-24
preprocessProtos in cmd/generate/main.go123-191 performs several operations to ensure the raw Valve protos are compatible with the Go protobuf compiler and the library's package structure:
| Operation | Detail |
|---|---|
| Glob source files | Matches files against sourceProtoGlobs (37 patterns) from generator/Protobufs/dota2/ cmd/generate/main.go22-38 |
| Prepend header | Adds syntax = "proto2"; package protocol; to every file cmd/generate/main.go227 |
| String patches | Removes leading . from type references (optional .Foo → optional Foo) cmd/generate/main.go228-231 |
| Path replacement | Rewrites google/protobuf/valve_extensions.proto to valveextensions.proto cmd/generate/main.go232 |
| Clean protocol dir | Removes old .proto files in protocol/ that are no longer in the source glob cmd/generate/main.go170-186 |
Sources: cmd/generate/main.go22-38 cmd/generate/main.go123-191 cmd/generate/main.go226-235
The library uses the aptre tool (part of github.com/aperturerobotics/common) to handle the actual protobuf compilation cmd/generate/main.go18
The generateProtos step executes aptre generate with specific flags:
--language go: Generates Go code.--rpc none: Disables standard gRPC generation as Dota 2 uses a custom GC protocol.--targets 'protocol/*.proto': Targets the preprocessed files.This process produces the *.pb.go files in the protocol/ directory which contain the message structs and EDOTAGCMsg enumerations used by the rest of the pipeline Makefile16-17
Sources: cmd/generate/main.go18 Makefile16-17
After protocol/*.pb.go is generated, runApigen at cmd/generate/main.go93-97 executes the API generator. The entry point for generation is GenerateAPI in apigen/api_generate.go18
apigen uses Go's go/types package to reflect over the compiled protocol package at runtime apigen/api_generate.go21-24 then classifies each EDOTAGCMsg enum value to emit appropriate Go code for the client and events.
GenerateAPI iterates through message IDs apigen/api_generate.go46-78:
MsgSenderClient via GetMessageSender(msgID), it builds a request function using buildGeneratedRequestFunc apigen/api_generate.go53-63MsgSenderGC, it builds an event handler struct and registration logic using buildGeneratedEventHandler apigen/api_generate.go64-77The generator automatically detects fields containing "steamid" (case-insensitive) with a "uint64" type apigen/api_generate.go159-161 It overrides these fields to use the steamid.SteamId type from the go-steam library apigen/api_generate.go162-171 It also generates the necessary conversion logic to transform these back to uint64 pointers for the underlying protobuf message apigen/api_generate.go206-210
Diagram: apigen Data Flow
Sources: apigen/api_generate.go18-78 apigen/api_generate.go159-179 apigen/api_generate.go206-210
The generator produces methods on the Dota2 client struct. It distinguishes between two patterns:
context.Context and returns (*ResponseProto, error). It internally calls d.MakeRequest apigen/api_generate.go232-239error. It internally calls d.write apigen/api_generate.go242-249For messages sent by the GC, apigen generates event structs in the events package. Each event implements a standard interface allowing the SOCache and event bus to dispatch them based on the EDOTAGCMsg ID apigen/api_generate.go64-77
Sources: apigen/api_generate.go232-250 cmd/generate/main.go99-102