code: func discoverTypes(protoPath string) {
  	fileset := token.NewFileSet()
  	packageMap, err := parser.ParseDir(fileset, protoPath, nil, 0)
  	if err != nil {
  		panic(err)
  	}
  
  	// Iterate over packages
  	for _, p := range packageMap {
  		// Iterate over files
  		for _, f := range p.Files {
  			// Iterate over declarations
  			for _, d := range f.Decls {
  				switch t := d.(type) {
  				case *ast.GenDecl:
  					// Iterate over specifications
  					for _, s := range t.Specs {
  						// Handle type and value specs
  						switch t := s.(type) {
  						case *ast.TypeSpec:
  							// Type specs contain types such as CDemoPacket. Extract the type
  							// name and mark it as found in the corresponding message type.
  							typeName := t.Name.String()
  							//if _, ok := findMessageByTypeName(typeName); ok {
  							messageTypeNames[typeName] = true
  							//}
  
  						case *ast.ValueSpec:
  							// Value specs contain enum values such as EDemoCommands_DEM_Packet.
  							// Extract the enum name (ex. EDemoCommands), value name
  							// (ex. EDemoCommands_DEM_Packet) and real value (ex. 7) and
  							// store them with the matching enum type.
  							valueName := nameOfValue(t)
  							if enumName := typeOfValue(t); enumName != "" {
  								if mt, ok := findMessageByEnumName(enumName); ok {
  									mt.enumValues[valueName] = valueOfValue(t)
  								}
  							}
  						}
  					}
  				}
  			}
  		}
  	}
  }
docs: // discoverTypes walks the go files in the dota directory and populates the data
  // in messageTypes and messageTypeNames.