├── .coveragerc
├── .gitignore
├── Makefile
├── README.rst
├── docs
├── .gitignore
├── Makefile
├── conf.py
├── dota2.client.rst
├── dota2.enums.rst
├── dota2.features.chat.rst
├── dota2.features.lobby.rst
├── dota2.features.match.rst
├── dota2.features.party.rst
├── dota2.features.player.rst
├── dota2.features.rst
├── dota2.features.sharedobjects.rst
├── dota2.msg.rst
├── dota2.rst
├── dota2.utils.rst
├── index.rst
└── user_guide.rst
├── dota2
├── __init__.py
├── client.py
├── common_enums.py
├── enums.py
├── features
│ ├── __init__.py
│ ├── chat.py
│ ├── lobby.py
│ ├── match.py
│ ├── party.py
│ ├── player.py
│ └── sharedobjects.py
├── msg.py
├── proto_enums.py
├── protobufs
│ ├── __init__.py
│ ├── base_gcmessages_pb2.py
│ ├── dota_client_enums_pb2.py
│ ├── dota_gcmessages_client_chat_pb2.py
│ ├── dota_gcmessages_client_fantasy_pb2.py
│ ├── dota_gcmessages_client_guild_pb2.py
│ ├── dota_gcmessages_client_match_management_pb2.py
│ ├── dota_gcmessages_client_pb2.py
│ ├── dota_gcmessages_client_team_pb2.py
│ ├── dota_gcmessages_client_tournament_pb2.py
│ ├── dota_gcmessages_client_watch_pb2.py
│ ├── dota_gcmessages_common_match_management_pb2.py
│ ├── dota_gcmessages_common_pb2.py
│ ├── dota_gcmessages_msgid_pb2.py
│ ├── dota_match_metadata_pb2.py
│ ├── dota_shared_enums_pb2.py
│ ├── econ_gcmessages_pb2.py
│ ├── econ_shared_enums_pb2.py
│ ├── gcsdk_gcmessages_pb2.py
│ ├── gcsystemmsgs_pb2.py
│ └── steammessages_pb2.py
└── utils
│ └── __init__.py
├── gen_enum_from_protos.py
├── protobuf_list.txt
├── protobufs
├── base_gcmessages.proto
├── dota_client_enums.proto
├── dota_gcmessages_client.proto
├── dota_gcmessages_client_chat.proto
├── dota_gcmessages_client_fantasy.proto
├── dota_gcmessages_client_guild.proto
├── dota_gcmessages_client_match_management.proto
├── dota_gcmessages_client_team.proto
├── dota_gcmessages_client_tournament.proto
├── dota_gcmessages_client_watch.proto
├── dota_gcmessages_common.proto
├── dota_gcmessages_common_match_management.proto
├── dota_gcmessages_msgid.proto
├── dota_match_metadata.proto
├── dota_shared_enums.proto
├── econ_gcmessages.proto
├── econ_shared_enums.proto
├── gcsdk_gcmessages.proto
├── gcsystemmsgs.proto
├── google
│ └── protobuf
│ │ └── descriptor.proto
└── steammessages.proto
├── requirements.txt
└── setup.py
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | concurrency = gevent
3 | omit =
4 | dota2/protobufs/*
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | *.egg-info
3 | *.pyc
4 | .coverage
5 | *.swp
6 |
7 | dota2/protobufs/*.proto
8 | build
9 | venv
10 | *.log
11 | .idea
12 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | define HELPBODY
2 | Available commands:
3 |
4 | make help - this thing.
5 |
6 | make init - install python dependancies
7 | make test - run tests and coverage
8 | make pylint - code analysis
9 | make build - pylint + test
10 | make docs - generate html docs using sphinx
11 |
12 | make dist - build source distribution
13 | mage register - register in pypi
14 | make upload - upload to pypi
15 |
16 | make pb_fetch - fetch protobufs from SteamRE
17 | make pb_compile - compile with protoc
18 | make pb_clear - removes *.proto
19 | make pb_update - pb_fetch + pb_compile
20 |
21 | endef
22 |
23 | export HELPBODY
24 | help:
25 | @echo "$$HELPBODY"
26 |
27 | init:
28 | pip install -r requirements.txt
29 |
30 | test:
31 | coverage erase
32 | PYTHONHASHSEED=0 nosetests --verbosity 1 --with-coverage --cover-package=dota2
33 |
34 | pylint:
35 | pylint -r n -f colorized dota2 || true
36 |
37 | build: pylint test docs
38 |
39 | .FORCE:
40 | docs: .FORCE
41 | $(MAKE) -C docs html
42 |
43 | clean:
44 | rm -rf dist dota2.egg-info dota2/*.pyc
45 |
46 | dist: clean
47 | python setup.py sdist
48 |
49 | register:
50 | python setup.py register -r pypi
51 |
52 | upload: dist register
53 | twine upload -r pypi dist/*
54 |
55 | pb_fetch:
56 | wget -nv --backups=1 --show-progress -P ./protobufs/ -i protobuf_list.txt
57 | rm -f ./protobufs/*.1
58 | sed -i '1s/^/syntax = "proto2"\;\npackage dota\;\n/' protobufs/*.proto
59 | sed -i 's/\(optional\|repeated\) \.\([A-Z]\)/\1 dota.\2/' protobufs/*.proto
60 | sed -i 's/cc_generic_services/py_generic_services/' protobufs/*.proto
61 | sed -i 's/ = 6000/ = 7000/' protobufs/steammessages.proto # extentions hack
62 |
63 | pb_compile:
64 | for filepath in `ls ./protobufs/*.proto`; do \
65 | protoc3 --python_out ./dota2/protobufs/ --proto_path=./protobufs "$$filepath"; \
66 | done;
67 | sed -i '/^import sys/! s/^import /import dota2.protobufs./' dota2/protobufs/*_pb2.py
68 |
69 | pb_clear:
70 | rm -f ./protobufs/*.proto ./dota2/protobufs/*_pb2.py
71 |
72 | gen_enums:
73 | python gen_enum_from_protos.py > dota2/proto_enums.py
74 |
75 | pb_update: pb_fetch pb_compile gen_enums
76 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | | |pypi| |license| |docs|
2 | | |sonar_maintainability| |sonar_reliability| |sonar_security|
3 |
4 | Supports Python ``2.7+`` and ``3.4+``.
5 |
6 | Module based on `steam `_
7 | for interacting with Dota2's Game Coordinator. If you've used
8 | `node-dota2 `_ then
9 | this module should feel right at home. Check out the documentation
10 | to get started.
11 |
12 | **Documentation**: http://dota2.readthedocs.io
13 |
14 | Contributions and suggestion are always welcome.
15 |
16 |
17 | Installation
18 | ------------
19 |
20 | Install latest version from PYPI::
21 |
22 | pip install dota2
23 |
24 | Install the current dev version from ``github``::
25 |
26 | pip install git+https://github.com/ValvePython/dota2
27 |
28 | # if you are installing over existing install
29 | # note: "only-if-needed" will only update dependecies if needed
30 | pip install -U --upgrade-strategy only-if-needed git+https://github.com/ValvePython/dota2
31 |
32 |
33 |
34 | .. |pypi| image:: https://img.shields.io/pypi/v/dota2.svg?style=flat&label=latest%20version
35 | :target: https://pypi.python.org/pypi/dota2
36 | :alt: Latest version released on PyPi
37 |
38 | .. |license| image:: https://img.shields.io/pypi/l/dota2.svg?style=flat&label=license
39 | :target: https://pypi.python.org/pypi/dota2
40 | :alt: MIT License
41 |
42 | .. |docs| image:: https://readthedocs.org/projects/dota2/badge/?version=latest
43 | :target: http://dota2.readthedocs.io/en/latest/?badge=latest
44 | :alt: Documentation status
45 |
46 | .. |sonar_maintainability| image:: https://sonarcloud.io/api/project_badges/measure?project=ValvePython_dota2&metric=sqale_rating
47 | :target: https://sonarcloud.io/dashboard?id=ValvePython_dota2
48 | :alt: SonarCloud Rating
49 |
50 | .. |sonar_reliability| image:: https://sonarcloud.io/api/project_badges/measure?project=ValvePython_dota2&metric=reliability_rating
51 | :target: https://sonarcloud.io/dashboard?id=ValvePython_dota2
52 | :alt: SonarCloud Rating
53 |
54 | .. |sonar_security| image:: https://sonarcloud.io/api/project_badges/measure?project=ValvePython_dota2&metric=security_rating
55 | :target: https://sonarcloud.io/dashboard?id=ValvePython_dota2
56 | :alt: SonarCloud Rating
57 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _doc
2 | _build
3 | _static
4 | _templates
5 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help
23 | help:
24 | @echo "Please use \`make ' where is one of"
25 | @echo " html to make standalone HTML files"
26 | @echo " dirhtml to make HTML files named index.html in directories"
27 | @echo " singlehtml to make a single large HTML file"
28 | @echo " pickle to make pickle files"
29 | @echo " json to make JSON files"
30 | @echo " htmlhelp to make HTML files and a HTML help project"
31 | @echo " qthelp to make HTML files and a qthelp project"
32 | @echo " applehelp to make an Apple Help Book"
33 | @echo " devhelp to make HTML files and a Devhelp project"
34 | @echo " epub to make an epub"
35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38 | @echo " text to make text files"
39 | @echo " man to make manual pages"
40 | @echo " texinfo to make Texinfo files"
41 | @echo " info to make Texinfo files and run them through makeinfo"
42 | @echo " gettext to make PO message catalogs"
43 | @echo " changes to make an overview of all changed/added/deprecated items"
44 | @echo " xml to make Docutils-native XML files"
45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46 | @echo " linkcheck to check all external links for integrity"
47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48 | @echo " coverage to run coverage check of the documentation (if enabled)"
49 |
50 | .PHONY: clean
51 | clean:
52 | rm -rf $(BUILDDIR)/*
53 |
54 | .PHONY: html
55 | html:
56 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
57 | @echo
58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
59 |
60 | .PHONY: dirhtml
61 | dirhtml:
62 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
63 | @echo
64 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
65 |
66 | .PHONY: singlehtml
67 | singlehtml:
68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
69 | @echo
70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
71 |
72 | .PHONY: pickle
73 | pickle:
74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
75 | @echo
76 | @echo "Build finished; now you can process the pickle files."
77 |
78 | .PHONY: json
79 | json:
80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
81 | @echo
82 | @echo "Build finished; now you can process the JSON files."
83 |
84 | .PHONY: htmlhelp
85 | htmlhelp:
86 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
87 | @echo
88 | @echo "Build finished; now you can run HTML Help Workshop with the" \
89 | ".hhp project file in $(BUILDDIR)/htmlhelp."
90 |
91 | .PHONY: qthelp
92 | qthelp:
93 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
94 | @echo
95 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
96 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
97 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/dota2.qhcp"
98 | @echo "To view the help file:"
99 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/dota2.qhc"
100 |
101 | .PHONY: applehelp
102 | applehelp:
103 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
104 | @echo
105 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
106 | @echo "N.B. You won't be able to view it unless you put it in" \
107 | "~/Library/Documentation/Help or install it in your application" \
108 | "bundle."
109 |
110 | .PHONY: devhelp
111 | devhelp:
112 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
113 | @echo
114 | @echo "Build finished."
115 | @echo "To view the help file:"
116 | @echo "# mkdir -p $$HOME/.local/share/devhelp/dota2"
117 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/dota2"
118 | @echo "# devhelp"
119 |
120 | .PHONY: epub
121 | epub:
122 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
123 | @echo
124 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
125 |
126 | .PHONY: latex
127 | latex:
128 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
129 | @echo
130 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
131 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
132 | "(use \`make latexpdf' here to do that automatically)."
133 |
134 | .PHONY: latexpdf
135 | latexpdf:
136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
137 | @echo "Running LaTeX files through pdflatex..."
138 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
139 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
140 |
141 | .PHONY: latexpdfja
142 | latexpdfja:
143 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
144 | @echo "Running LaTeX files through platex and dvipdfmx..."
145 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
146 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
147 |
148 | .PHONY: text
149 | text:
150 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
151 | @echo
152 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
153 |
154 | .PHONY: man
155 | man:
156 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
157 | @echo
158 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
159 |
160 | .PHONY: texinfo
161 | texinfo:
162 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
163 | @echo
164 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
165 | @echo "Run \`make' in that directory to run these through makeinfo" \
166 | "(use \`make info' here to do that automatically)."
167 |
168 | .PHONY: info
169 | info:
170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
171 | @echo "Running Texinfo files through makeinfo..."
172 | make -C $(BUILDDIR)/texinfo info
173 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
174 |
175 | .PHONY: gettext
176 | gettext:
177 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
178 | @echo
179 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
180 |
181 | .PHONY: changes
182 | changes:
183 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
184 | @echo
185 | @echo "The overview file is in $(BUILDDIR)/changes."
186 |
187 | .PHONY: linkcheck
188 | linkcheck:
189 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
190 | @echo
191 | @echo "Link check complete; look for any errors in the above output " \
192 | "or in $(BUILDDIR)/linkcheck/output.txt."
193 |
194 | .PHONY: doctest
195 | doctest:
196 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
197 | @echo "Testing of doctests in the sources finished, look at the " \
198 | "results in $(BUILDDIR)/doctest/output.txt."
199 |
200 | .PHONY: coverage
201 | coverage:
202 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
203 | @echo "Testing of coverage in the sources finished, look at the " \
204 | "results in $(BUILDDIR)/coverage/python.txt."
205 |
206 | .PHONY: xml
207 | xml:
208 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
209 | @echo
210 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
211 |
212 | .PHONY: pseudoxml
213 | pseudoxml:
214 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
215 | @echo
216 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
217 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # dota2 documentation build configuration file, created by
4 | # sphinx-quickstart on Mon Feb 15 03:43:47 2016.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import sys
16 | import os
17 |
18 | # If extensions (or modules to document with autodoc) are in another directory,
19 | # add these directories to sys.path here. If the directory is relative to the
20 | # documentation root, use os.path.abspath to make it absolute, like shown here.
21 | sys.path.insert(0, os.path.abspath('../'))
22 |
23 | # -- General configuration ------------------------------------------------
24 |
25 | # If your documentation needs a minimal Sphinx version, state it here.
26 | #needs_sphinx = '1.0'
27 |
28 | # Add any Sphinx extension module names here, as strings. They can be
29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30 | # ones.
31 | extensions = [
32 | 'sphinx.ext.autodoc',
33 | 'sphinx.ext.intersphinx',
34 | # 'sphinx.ext.githubpages',
35 | ]
36 |
37 | # Add any paths that contain templates here, relative to this directory.
38 | templates_path = ['_templates']
39 |
40 | # The suffix(es) of source filenames.
41 | # You can specify multiple suffix as a list of string:
42 | # source_suffix = ['.rst', '.md']
43 | source_suffix = '.rst'
44 |
45 | # The encoding of source files.
46 | #source_encoding = 'utf-8-sig'
47 |
48 | # The master toctree document.
49 | master_doc = 'index'
50 |
51 | # General information about the project.
52 | from dota2 import __version__, __author__
53 | project = u'dota2'
54 | copyright = u'2019, %s' % __author__
55 | author = __author__
56 |
57 | # The version info for the project you're documenting, acts as replacement for
58 | # |version| and |release|, also used in various other places throughout the
59 | # built documents.
60 | # The short X.Y version.
61 | version = __version__
62 | # The full version, including alpha/beta/rc tags.
63 | release = __version__
64 |
65 | # The language for content autogenerated by Sphinx. Refer to documentation
66 | # for a list of supported languages.
67 | #
68 | # This is also used if you do content translation via gettext catalogs.
69 | # Usually you set "language" from the command line for these cases.
70 | language = 'en'
71 |
72 | # There are two options for replacing |today|: either, you set today to some
73 | # non-false value, then it is used:
74 | #today = ''
75 | # Else, today_fmt is used as the format for a strftime call.
76 | #today_fmt = '%B %d, %Y'
77 |
78 | # List of patterns, relative to source directory, that match files and
79 | # directories to ignore when looking for source files.
80 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
81 |
82 | # The reST default role (used for this markup: `text`) to use for all
83 | # documents.
84 | #default_role = None
85 |
86 | # If true, '()' will be appended to :func: etc. cross-reference text.
87 | #add_function_parentheses = True
88 |
89 | # If true, the current module name will be prepended to all description
90 | # unit titles (such as .. function::).
91 | #add_module_names = True
92 |
93 | # If true, sectionauthor and moduleauthor directives will be shown in the
94 | # output. They are ignored by default.
95 | #show_authors = False
96 |
97 | # The name of the Pygments (syntax highlighting) style to use.
98 | pygments_style = 'sphinx'
99 |
100 | # A list of ignored prefixes for module index sorting.
101 | #modindex_common_prefix = []
102 |
103 | # If true, keep warnings as "system message" paragraphs in the built documents.
104 | #keep_warnings = False
105 |
106 | # If true, `todo` and `todoList` produce output, else they produce nothing.
107 | todo_include_todos = True
108 |
109 |
110 | # -- Options for HTML output ----------------------------------------------
111 |
112 | # The theme to use for HTML and HTML Help pages. See the documentation for
113 | # a list of builtin themes.
114 | html_theme = 'sphinx_rtd_theme'
115 |
116 | # Theme options are theme-specific and customize the look and feel of a theme
117 | # further. For a list of options available for each theme, see the
118 | # documentation.
119 | #html_theme_options = {}
120 |
121 | # Add any paths that contain custom themes here, relative to this directory.
122 | #html_theme_path = []
123 |
124 | # The name for this set of Sphinx documents.
125 | # " v documentation" by default.
126 | #html_title = u'dota2 v'
127 |
128 | # A shorter title for the navigation bar. Default is the same as html_title.
129 | #html_short_title = None
130 |
131 | # The name of an image file (relative to this directory) to place at the top
132 | # of the sidebar.
133 | #html_logo = None
134 |
135 | # The name of an image file (within the static path) to use as favicon of the
136 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
137 | # pixels large.
138 | #html_favicon = None
139 |
140 | # Add any paths that contain custom static files (such as style sheets) here,
141 | # relative to this directory. They are copied after the builtin static files,
142 | # so a file named "default.css" will overwrite the builtin "default.css".
143 | html_static_path = ['_static']
144 |
145 | # Add any extra paths that contain custom files (such as robots.txt or
146 | # .htaccess) here, relative to this directory. These files are copied
147 | # directly to the root of the documentation.
148 | #html_extra_path = []
149 |
150 | # If not None, a 'Last updated on:' timestamp is inserted at every page
151 | # bottom, using the given strftime format.
152 | # The empty string is equivalent to '%b %d, %Y'.
153 | #html_last_updated_fmt = None
154 |
155 | # If true, SmartyPants will be used to convert quotes and dashes to
156 | # typographically correct entities.
157 | #html_use_smartypants = True
158 |
159 | # Custom sidebar templates, maps document names to template names.
160 | #html_sidebars = {}
161 |
162 | # Additional templates that should be rendered to pages, maps page names to
163 | # template names.
164 | #html_additional_pages = {}
165 |
166 | # If false, no module index is generated.
167 | #html_domain_indices = True
168 |
169 | # If false, no index is generated.
170 | #html_use_index = True
171 |
172 | # If true, the index is split into individual pages for each letter.
173 | #html_split_index = False
174 |
175 | # If true, links to the reST sources are added to the pages.
176 | html_show_sourcelink = True
177 |
178 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
179 | html_show_sphinx = True
180 |
181 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
182 | #html_show_copyright = True
183 |
184 | # If true, an OpenSearch description file will be output, and all pages will
185 | # contain a tag referring to it. The value of this option must be the
186 | # base URL from which the finished HTML is served.
187 | #html_use_opensearch = ''
188 |
189 | # This is the file name suffix for HTML files (e.g. ".xhtml").
190 | #html_file_suffix = None
191 |
192 | # Language to be used for generating the HTML full-text search index.
193 | # Sphinx supports the following languages:
194 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
195 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
196 | #html_search_language = 'en'
197 |
198 | # A dictionary with options for the search language support, empty by default.
199 | # 'ja' uses this config value.
200 | # 'zh' user can custom change `jieba` dictionary path.
201 | #html_search_options = {'type': 'default'}
202 |
203 | # The name of a javascript file (relative to the configuration directory) that
204 | # implements a search results scorer. If empty, the default will be used.
205 | #html_search_scorer = 'scorer.js'
206 |
207 | # Output file base name for HTML help builder.
208 | htmlhelp_basename = 'dota2doc'
209 |
210 | # -- Options for LaTeX output ---------------------------------------------
211 |
212 | latex_elements = {
213 | # The paper size ('letterpaper' or 'a4paper').
214 | #'papersize': 'letterpaper',
215 |
216 | # The font size ('10pt', '11pt' or '12pt').
217 | #'pointsize': '10pt',
218 |
219 | # Additional stuff for the LaTeX preamble.
220 | #'preamble': '',
221 |
222 | # Latex figure (float) alignment
223 | #'figure_align': 'htbp',
224 | }
225 |
226 | # Grouping the document tree into LaTeX files. List of tuples
227 | # (source start file, target name, title,
228 | # author, documentclass [howto, manual, or own class]).
229 | latex_documents = [
230 | (master_doc, 'dota2.tex', u'dota2 Documentation',
231 | version, 'manual'),
232 | ]
233 |
234 | # The name of an image file (relative to this directory) to place at the top of
235 | # the title page.
236 | #latex_logo = None
237 |
238 | # For "manual" documents, if this is true, then toplevel headings are parts,
239 | # not chapters.
240 | #latex_use_parts = False
241 |
242 | # If true, show page references after internal links.
243 | #latex_show_pagerefs = False
244 |
245 | # If true, show URL addresses after external links.
246 | #latex_show_urls = False
247 |
248 | # Documents to append as an appendix to all manuals.
249 | #latex_appendices = []
250 |
251 | # If false, no module index is generated.
252 | #latex_domain_indices = True
253 |
254 |
255 | # -- Options for manual page output ---------------------------------------
256 |
257 | # One entry per manual page. List of tuples
258 | # (source start file, name, description, authors, manual section).
259 | man_pages = [
260 | (master_doc, 'dota2', u'dota2 Documentation',
261 | [author], 1)
262 | ]
263 |
264 | # If true, show URL addresses after external links.
265 | #man_show_urls = False
266 |
267 |
268 | # -- Options for Texinfo output -------------------------------------------
269 |
270 | # Grouping the document tree into Texinfo files. List of tuples
271 | # (source start file, target name, title, author,
272 | # dir menu entry, description, category)
273 | texinfo_documents = [
274 | (master_doc, 'dota2', u'dota2 Documentation',
275 | author, 'dota2', 'One line description of project.',
276 | 'Miscellaneous'),
277 | ]
278 |
279 | # Documents to append as an appendix to all manuals.
280 | #texinfo_appendices = []
281 |
282 | # If false, no module index is generated.
283 | #texinfo_domain_indices = True
284 |
285 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
286 | #texinfo_show_urls = 'footnote'
287 |
288 | # If true, do not generate a @detailmenu in the "Top" node's menu.
289 | #texinfo_no_detailmenu = False
290 |
291 |
292 | # -- Options for Epub output ----------------------------------------------
293 |
294 | # Bibliographic Dublin Core info.
295 | epub_title = project
296 | epub_author = author
297 | epub_publisher = author
298 | epub_copyright = copyright
299 |
300 | # The basename for the epub file. It defaults to the project name.
301 | #epub_basename = project
302 |
303 | # The HTML theme for the epub output. Since the default themes are not
304 | # optimized for small screen space, using the same theme for HTML and epub
305 | # output is usually not wise. This defaults to 'epub', a theme designed to save
306 | # visual space.
307 | #epub_theme = 'epub'
308 |
309 | # The language of the text. It defaults to the language option
310 | # or 'en' if the language is not set.
311 | #epub_language = ''
312 |
313 | # The scheme of the identifier. Typical schemes are ISBN or URL.
314 | #epub_scheme = ''
315 |
316 | # The unique identifier of the text. This can be a ISBN number
317 | # or the project homepage.
318 | #epub_identifier = ''
319 |
320 | # A unique identification for the text.
321 | #epub_uid = ''
322 |
323 | # A tuple containing the cover image and cover page html template filenames.
324 | #epub_cover = ()
325 |
326 | # A sequence of (type, uri, title) tuples for the guide element of content.opf.
327 | #epub_guide = ()
328 |
329 | # HTML files that should be inserted before the pages created by sphinx.
330 | # The format is a list of tuples containing the path and title.
331 | #epub_pre_files = []
332 |
333 | # HTML files shat should be inserted after the pages created by sphinx.
334 | # The format is a list of tuples containing the path and title.
335 | #epub_post_files = []
336 |
337 | # A list of files that should not be packed into the epub file.
338 | epub_exclude_files = ['search.html']
339 |
340 | # The depth of the table of contents in toc.ncx.
341 | #epub_tocdepth = 3
342 |
343 | # Allow duplicate toc entries.
344 | #epub_tocdup = True
345 |
346 | # Choose between 'default' and 'includehidden'.
347 | #epub_tocscope = 'default'
348 |
349 | # Fix unsupported image types using the Pillow.
350 | #epub_fix_images = False
351 |
352 | # Scale large images.
353 | #epub_max_image_width = 0
354 |
355 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
356 | #epub_show_urls = 'inline'
357 |
358 | # If false, no index is generated.
359 | #epub_use_index = True
360 |
361 | # LINK EXT DOCS
362 | intersphinx_mapping = {
363 | 'python': ('https://docs.python.org/3.6', None),
364 | 'gevent': ('http://www.gevent.org', None),
365 | 'requests': ('https://2.python-requests.org/en/master', None),
366 | 'steam': ('https://steam.readthedocs.io/en/stable/', None),
367 | }
368 |
369 | # AUTODOC
370 | autodoc_member_order = 'bysource'
371 |
--------------------------------------------------------------------------------
/docs/dota2.client.rst:
--------------------------------------------------------------------------------
1 | client
2 | ======
3 |
4 | .. automodule:: dota2.client
5 | :members:
6 | :show-inheritance:
7 |
--------------------------------------------------------------------------------
/docs/dota2.enums.rst:
--------------------------------------------------------------------------------
1 | enums
2 | =====
3 |
4 | .. automodule:: dota2.common_enums
5 | :members:
6 | :undoc-members:
7 | :inherited-members:
8 |
9 | .. automodule:: dota2.proto_enums
10 | :members:
11 | :undoc-members:
12 | :inherited-members:
13 |
--------------------------------------------------------------------------------
/docs/dota2.features.chat.rst:
--------------------------------------------------------------------------------
1 | chat
2 | ====
3 |
4 | Chat channel features
5 |
6 |
7 | .. automodule:: dota2.features.chat
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/docs/dota2.features.lobby.rst:
--------------------------------------------------------------------------------
1 | lobby
2 | =====
3 |
4 | Lobby related features
5 |
6 |
7 | .. automodule:: dota2.features.lobby
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/docs/dota2.features.match.rst:
--------------------------------------------------------------------------------
1 | match
2 | =====
3 |
4 | Features related to matches and matchmaking.
5 |
6 | .. automodule:: dota2.features.match
7 | :members:
8 | :undoc-members:
9 | :show-inheritance:
10 |
--------------------------------------------------------------------------------
/docs/dota2.features.party.rst:
--------------------------------------------------------------------------------
1 | party
2 | ======
3 |
4 | Features related to party invite and communication.
5 |
6 | .. automodule:: dota2.features.party
7 | :members:
8 | :undoc-members:
9 | :show-inheritance:
10 |
--------------------------------------------------------------------------------
/docs/dota2.features.player.rst:
--------------------------------------------------------------------------------
1 | player
2 | ======
3 |
4 | Features related to community, players and profiles.
5 |
6 | .. automodule:: dota2.features.player
7 | :members:
8 | :undoc-members:
9 | :show-inheritance:
10 |
--------------------------------------------------------------------------------
/docs/dota2.features.rst:
--------------------------------------------------------------------------------
1 | features
2 | ========
3 |
4 | This package contains all high level features of the :class:`dota2.client.Dota2Client`.
5 |
6 | .. toctree::
7 |
8 | dota2.features.player
9 | dota2.features.match
10 | dota2.features.party
11 | dota2.features.lobby
12 | dota2.features.chat
13 | dota2.features.sharedobjects
14 |
--------------------------------------------------------------------------------
/docs/dota2.features.sharedobjects.rst:
--------------------------------------------------------------------------------
1 | sharedobjects
2 | =============
3 |
4 | .. automodule:: dota2.features.sharedobjects
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/dota2.msg.rst:
--------------------------------------------------------------------------------
1 | msg
2 | ===
3 |
4 | .. automodule:: dota2.msg
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/dota2.rst:
--------------------------------------------------------------------------------
1 | dota2 API
2 | =========
3 |
4 | Documentation related to various APIs available in this package.
5 |
6 | .. toctree::
7 |
8 | dota2.features
9 | dota2.client
10 | dota2.enums
11 | dota2.msg
12 | dota2.utils
13 |
--------------------------------------------------------------------------------
/docs/dota2.utils.rst:
--------------------------------------------------------------------------------
1 | utils
2 | =====
3 |
4 | .. automodule:: dota2.utils
5 | :members:
6 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to dota2's documentation!
2 | =================================
3 |
4 | |pypi| |license|
5 |
6 | Supports Python ``2.7+`` and ``3.4+``.
7 |
8 | | Module based on `steam `_ for interacting with Dota 2's Game Coordinator.
9 | | If you've used `node-dota2 `_ this module should feel familiar.
10 |
11 | As always contributions and suggestions are welcome.
12 | Just visit the `repository on github `_.
13 |
14 | Getting started
15 | ---------------
16 |
17 | .. toctree::
18 | :maxdepth: 2
19 |
20 | user_guide
21 |
22 | API Documentation
23 | -----------------
24 |
25 | .. toctree::
26 | :maxdepth: 4
27 |
28 | dota2
29 |
30 |
31 | Indices and tables
32 | ==================
33 |
34 | * :ref:`genindex`
35 | * :ref:`modindex`
36 | * :ref:`search`
37 |
38 | .. |pypi| image:: https://img.shields.io/pypi/v/dota2.svg?style=flat&label=latest%20version
39 | :target: https://pypi.python.org/pypi/dota2
40 | :alt: Latest version released on PyPi
41 |
42 | .. |license| image:: https://img.shields.io/pypi/l/dota2.svg?style=flat&label=license
43 | :target: https://pypi.python.org/pypi/dota2
44 | :alt: MIT License
45 |
--------------------------------------------------------------------------------
/docs/user_guide.rst:
--------------------------------------------------------------------------------
1 | User Guide
2 | **********
3 |
4 | This part of the documentation is a quick start for writing applications that
5 | interact with the game coordinator for Dota 2.
6 |
7 |
8 | Initialization
9 | ==============
10 |
11 | Below is a example how to login and get a session with game coordinator.
12 | See `steam's docs `_
13 | for details about :class:`SteamClient `.
14 |
15 | .. note::
16 | You won't see any output running the code above.
17 | In order to peek inside we need to setup debug logging.
18 | See the :ref:`logging_config` section
19 |
20 |
21 | .. code:: python
22 |
23 | from steam.client import SteamClient
24 | from dota2.client import Dota2Client
25 |
26 | client = SteamClient()
27 | dota = Dota2Client(client)
28 |
29 | @client.on('logged_on')
30 | def start_dota():
31 | dota.launch()
32 |
33 | @dota.on('ready')
34 | def do_dota_stuff():
35 | # talk to GC
36 |
37 | client.cli_login()
38 | client.run_forever()
39 |
40 |
41 | Working with events
42 | ===================
43 |
44 | This module makes use of `gevent `_
45 | and `gevent-eventemitter `_.
46 | Working with events is similiar to ``EventEmitter`` in javascript.
47 | Nevertheless, here is quick rundown.
48 |
49 | To catch an event we need to register a callback
50 |
51 | .. code:: python
52 |
53 | @dota.on('my event')
54 | def do_stuff(a, b):
55 | print "Hey!"
56 |
57 | dota.on('my event', do_stuff)
58 | dota.once('my event', do_stuff) # call do_stuff just one time
59 | dota.wait_event('my event') # blocks and returns arguments, if any
60 |
61 | .. note::
62 | ``wait_event`` may block forever, so use the ``timeout`` parameter
63 |
64 | Emitting an event is simple
65 |
66 | .. code:: python
67 |
68 | dota.emit("my event")
69 | dota.emit("my event", 1, [3,4,5]) # optional arguments
70 |
71 |
72 | That's it. For more details see `gevent-eventemitter `_.
73 |
74 |
75 | Fetch player profile card
76 | =========================
77 |
78 | You've probably seen the profile cards in Dota 2.
79 | They contain player selected stats, such trophies, number of matches, or MMR.
80 |
81 | We can request that data using an API from the :doc:`dota2.features` module.
82 |
83 | Let's get Dendi's profile card. All we need is his account id, which is ``70388657``.
84 |
85 | .. code:: python
86 |
87 | @dota.on('ready')
88 | def fetch_profile_card():
89 | dota.request_profile_card(70388657)
90 |
91 | @dota.on('profile_card'):
92 | def print_profile_card(account_id, profile_card):
93 | if account_id == 70388657:
94 | print str(profile_card)
95 |
96 | The profile card request also happens to be a job.
97 | ``request_profile_card`` returns a ``job id`` and we can wait for it instead.
98 | However, we will not get the same parameters as from ``profile_card``
99 |
100 | .. note::
101 | Listening for the ``job id``` will only give you one arugment: the protobuf message
102 |
103 | .. code:: python
104 |
105 | @dota.on('ready')
106 | def fetch_profile_card():
107 | jobid = dota.request_profile_card(70388657)
108 | profile_card = dota.wait_msg(jobid, timeout=10)
109 |
110 | if profile_card:
111 | print str(profile_card)
112 |
113 | .. note::
114 | Not every request returns a ``job id``, see the API documentation for details
115 |
116 | Running the code above will output something like this:
117 |
118 | .. code::
119 |
120 | account_id: 70388657
121 | background_def_index: 0
122 | slots {
123 | slot_id: 0
124 | stat {
125 | stat_id: k_eStat_FirstMatchDate
126 | stat_score: 1314309005
127 | }
128 | }
129 | slots {
130 | slot_id: 1
131 | stat {
132 | stat_id: k_eStat_SoloRank
133 | stat_score: 6775
134 |
135 |
136 | .. _logging_config:
137 |
138 | Configure console logging
139 | =========================
140 |
141 | Here is a basic configuration to get debug messages in the console.
142 |
143 | .. code:: python
144 |
145 | import logging
146 |
147 | logging.basicConfig(format='[%(asctime)s] %(levelname)s %(name)s: %(message)s', level=logging.DEBUG)
148 |
149 | The we run the program and the console ouput should look something like this:
150 |
151 | .. code::
152 |
153 | [2016-01-01 12:34:56,000] DEBUG CMClient: Connect initiated.
154 | [2016-01-01 12:34:56,000] DEBUG Connection: Attempting connection to ('208.78.164.13', 27018)
155 | [2016-01-01 12:34:56,000] DEBUG Connection: Connected.
156 | [2016-01-01 12:34:56,000] DEBUG CMClient: Emit event: 'connected'
157 | [2016-01-01 12:34:56,000] DEBUG SteamClient: Emit event: 'connected'
158 | [2016-01-01 12:34:56,000] DEBUG SteamClient: Attempting login
159 | [2016-01-01 12:34:56,000] DEBUG CMClient: Incoming: >
160 | [2016-01-01 12:34:56,000] DEBUG CMClient: Emit event:
161 | ...
162 |
163 |
164 |
--------------------------------------------------------------------------------
/dota2/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = "1.1.0"
2 | __author__ = "Rossen Georgiev"
3 |
4 | version_info = (1, 1, 0)
5 |
--------------------------------------------------------------------------------
/dota2/client.py:
--------------------------------------------------------------------------------
1 | """
2 | Only the most essential features to :class:`dota2.client.Dota2Client` are found here. Every other feature is inherited from
3 | the :mod:`dota2.features` package and it's submodules.
4 | """
5 |
6 | import logging
7 | import gevent
8 | import google.protobuf
9 | from eventemitter import EventEmitter
10 | from steam.core.msg import GCMsgHdrProto
11 | from steam.client.gc import GameCoordinator
12 | from steam.enums.emsg import EMsg
13 | from steam.utils.proto import proto_fill_from_dict
14 | from dota2.features import FeatureBase
15 | from dota2.enums import EGCBaseClientMsg, EDOTAGCSessionNeed, GCConnectionStatus, ESourceEngine
16 | from dota2.msg import get_emsg_enum, find_proto
17 | from dota2.protobufs import gcsdk_gcmessages_pb2 as pb_gc
18 | from dota2.protobufs import dota_gcmessages_client_pb2 as pb_gclient
19 |
20 |
21 |
22 | class Dota2Client(GameCoordinator, FeatureBase):
23 | """
24 | :param steam_client: Instance of the steam client
25 | :type steam_client: :class:`steam.client.SteamClient`
26 | """
27 | _retry_welcome_loop = None
28 | verbose_debug = False #: enable pretty print of messages in debug logging
29 | app_id = 570 #: main client app id
30 | current_jobid = 0
31 | ready = False #: ``True`` when we have a session with GC
32 | connection_status = GCConnectionStatus.NO_SESSION #: :class:`dota2.enums.GCConnectionStatus`
33 |
34 | @property
35 | def account_id(self):
36 | """
37 | Account ID of the logged in user in the steam client
38 | """
39 | return self.steam.steam_id.id
40 |
41 | @property
42 | def steam_id(self):
43 | """
44 | :class:`steam.steamid.SteamID` of the logged-in user in the steam client
45 | """
46 | return self.steam.steam_id
47 |
48 | def __init__(self, steam_client):
49 | GameCoordinator.__init__(self, steam_client, self.app_id)
50 | self._LOG = logging.getLogger(self.__class__.__name__)
51 |
52 | FeatureBase.__init__(self)
53 |
54 | self.steam.on('disconnected', self._handle_disconnect)
55 | self.steam.on(EMsg.ClientPlayingSessionState, self._handle_play_sess_state)
56 |
57 | # register GC message handles
58 | self.on(EGCBaseClientMsg.EMsgGCClientConnectionStatus, self._handle_conn_status)
59 | self.on(EGCBaseClientMsg.EMsgGCClientWelcome, self._handle_client_welcome)
60 |
61 | def __repr__(self):
62 | return "<%s(%s) %s>" % (self.__class__.__name__,
63 | repr(self.steam),
64 | repr(self.connection_status),
65 | )
66 |
67 | def _handle_play_sess_state(self, message):
68 | if self.ready and message.body.playing_app != self.app_id:
69 | self._set_connection_status(GCConnectionStatus.NO_SESSION)
70 |
71 | def _handle_disconnect(self):
72 | if self._retry_welcome_loop:
73 | self._retry_welcome_loop.kill()
74 |
75 | self._set_connection_status(GCConnectionStatus.NO_SESSION)
76 |
77 | def _handle_client_welcome(self, message):
78 | self._set_connection_status(GCConnectionStatus.HAVE_SESSION)
79 |
80 | # handle DOTAWelcome
81 | submessage = pb_gclient.CMsgDOTAWelcome()
82 | submessage.ParseFromString(message.game_data)
83 |
84 | if self.verbose_debug:
85 | self._LOG.debug("Got DOTAWelcome:\n%s" % str(submessage))
86 | else:
87 | self._LOG.debug("Got DOTAWelcome")
88 |
89 | self.emit('dota_welcome', submessage)
90 |
91 | for extra in submessage.extra_messages:
92 | self._process_gc_message(extra.id, GCMsgHdrProto(extra.id), extra.contents)
93 |
94 |
95 | def _handle_conn_status(self, message):
96 | self._set_connection_status(message.status)
97 |
98 | def _process_gc_message(self, emsg, header, payload):
99 | emsg = get_emsg_enum(emsg)
100 | proto = find_proto(emsg)
101 |
102 | if proto is None:
103 | self._LOG.error("Failed to parse: %s" % repr(emsg))
104 | return
105 |
106 | message = proto()
107 | message.ParseFromString(payload)
108 |
109 | if self.verbose_debug:
110 | self._LOG.debug("Incoming: %s\n%s\n---------\n%s" % (repr(emsg),
111 | str(header),
112 | str(message),
113 | ))
114 | else:
115 | self._LOG.debug("Incoming: %s", repr(emsg))
116 |
117 | self.emit(emsg, message)
118 |
119 | if header.proto.job_id_target != 18446744073709551615:
120 | self.emit('job_%d' % header.proto.job_id_target, message)
121 |
122 | def _set_connection_status(self, status):
123 | prev_status = self.connection_status
124 | self.connection_status = GCConnectionStatus(status)
125 |
126 | if self.connection_status != prev_status:
127 | self.emit("connection_status", self.connection_status)
128 |
129 | if self.connection_status == GCConnectionStatus.HAVE_SESSION and not self.ready:
130 | self.ready = True
131 | self.emit('ready')
132 | elif self.connection_status != GCConnectionStatus.HAVE_SESSION and self.ready:
133 | self.ready = False
134 | self.emit('notready')
135 |
136 | def wait_msg(self, event, timeout=None, raises=None):
137 | """Wait for a message, similiar to :meth:`.wait_event`
138 |
139 | :param event: :class:`.EDOTAGCMsg` or job id
140 | :param timeout: seconds to wait before timeout
141 | :type timeout: :class:`int`
142 | :param raises: On timeout when ``False`` returns :class:`None`, else raise :class:`gevent.Timeout`
143 | :type raises: :class:`bool`
144 | :return: returns a message or :class:`None`
145 | :rtype: :class:`None`, or `proto message`
146 | :raises: ``gevent.Timeout`
147 | """
148 | resp = self.wait_event(event, timeout, raises)
149 |
150 | if resp is not None:
151 | return resp[0]
152 |
153 | def send_job(self, *args, **kwargs):
154 | """
155 | Send a message as a job
156 |
157 | Exactly the same as :meth:`send`
158 |
159 | :return: jobid event identifier
160 | :rtype: :class:`str`
161 |
162 | """
163 | jobid = self.current_jobid = ((self.current_jobid + 1) % 10000) or 1
164 | self.remove_all_listeners('job_%d' % jobid)
165 |
166 | self._send(*args, jobid=jobid, **kwargs)
167 |
168 | return "job_%d" % jobid
169 |
170 | def send_job_and_wait(self, emsg, data={}, proto=None, timeout=None, raises=False):
171 | """
172 | Send a message as a job and wait for the response.
173 |
174 | .. note::
175 | Not all messages are jobs, you'll have to find out which are which
176 |
177 | :param emsg: Enum for the message
178 | :param data: data for the proto message
179 | :type data: :class:`dict`
180 | :param proto: (optional) specify protobuf, otherwise it's detected based on ``emsg``
181 | :param timeout: (optional) seconds to wait
182 | :type timeout: :class:`int`
183 | :param raises: (optional) On timeout if this is ``False`` method will return ``None``, else raises ``gevent.Timeout``
184 | :type raises: :class:`bool`
185 | :return: response proto message
186 | :raises: :class:`gevent.Timeout``
187 | """
188 | job_id = self.send_job(emsg, data, proto)
189 | return self.wait_msg(job_id, timeout, raises=raises)
190 |
191 | def send(self, emsg, data={}, proto=None):
192 | """
193 | Send a message
194 |
195 | :param emsg: Enum for the message
196 | :param data: data for the proto message
197 | :type data: :class:`dict`
198 | :param proto: (optional) manually specify protobuf, other it's detected based on ``emsg``
199 | """
200 | self._send(emsg, data, proto)
201 |
202 | def _send(self, emsg, data={}, proto=None, jobid=None):
203 | if not isinstance(data, dict):
204 | raise ValueError("data kwarg can only be a dict")
205 |
206 | if proto is None:
207 | proto = find_proto(emsg)
208 |
209 | if not issubclass(proto, google.protobuf.message.Message):
210 | raise ValueError("Unable to find proto for emsg, or proto kwarg is invalid")
211 |
212 | message = proto()
213 | proto_fill_from_dict(message, data)
214 |
215 | header = GCMsgHdrProto(emsg)
216 |
217 | if jobid is not None:
218 | header.proto.job_id_source = jobid
219 |
220 | if self.verbose_debug:
221 | str_message = ''
222 | str_header = str(header)
223 | str_body = str(message)
224 |
225 | if str_header:
226 | str_message += "-- header ---------\n%s\n" % str_header
227 | if str_body:
228 | str_message += "-- message --------\n%s\n" % str_body
229 |
230 | self._LOG.debug("Outgoing: %s\n%s" % (repr(emsg), str_message))
231 | else:
232 | self._LOG.debug("Outgoing: %s", repr(emsg))
233 |
234 | GameCoordinator.send(self, header, message.SerializeToString())
235 |
236 | def _knock_on_gc(self):
237 | n = 1
238 |
239 | while True:
240 | if not self.ready:
241 | self.send(EGCBaseClientMsg.EMsgGCClientHello, {
242 | 'client_session_need': EDOTAGCSessionNeed.UserInUINeverConnected,
243 | 'engine': ESourceEngine.ESE_Source2,
244 | })
245 |
246 | self.wait_event('ready', timeout=3 + (2**n))
247 | n = min(n + 1, 4)
248 |
249 | else:
250 | self.wait_event('notready')
251 | n = 1
252 | gevent.sleep(1)
253 |
254 | def launch(self):
255 | """
256 | Launch Dota 2 and establish connection with the game coordinator
257 |
258 | ``ready`` event will fire when the session is ready.
259 | If the session is lost ``notready`` event will fire.
260 | Alternatively, ``connection_status`` event can be monitored for changes.
261 | """
262 | if not self.steam.logged_on:
263 | return
264 |
265 | if not self._retry_welcome_loop and self.app_id not in self.steam.current_games_played:
266 | self.steam.games_played(self.steam.current_games_played + [self.app_id])
267 | self._retry_welcome_loop = gevent.spawn(self._knock_on_gc)
268 |
269 | def exit(self):
270 | """
271 | Close connection to Dota 2's game coordinator
272 | """
273 | if self._retry_welcome_loop:
274 | self._retry_welcome_loop.kill()
275 |
276 | if self.app_id in self.steam.current_games_played:
277 | self.steam.current_games_played.remove(self.app_id)
278 | self.steam.games_played(self.steam.current_games_played)
279 |
280 | self._set_connection_status(GCConnectionStatus.NO_SESSION)
281 |
282 | def sleep(self, seconds):
283 | """Yeild and sleep N seconds. Allows other greenlets to run"""
284 | gevent.sleep(seconds)
285 |
286 | def idle(self):
287 | """Yeild in the current greenlet and let other greenlets run"""
288 | gevent.idle()
289 |
--------------------------------------------------------------------------------
/dota2/common_enums.py:
--------------------------------------------------------------------------------
1 |
2 | from enum import IntEnum
3 |
4 |
5 | class ESOType(IntEnum):
6 | CSOEconItem = 1
7 | CSOItemRecipe = 5
8 | CSOEconGameAccountClient = 7
9 | CSOSelectedItemPreset = 35 # no longer exists in game files
10 | CSOEconItemPresetInstance = 36 # no longer exists in game files
11 | CSOEconItemDropRateBonus = 38
12 | CSOEconItemLeagueViewPass = 39
13 | CSOEconItemEventTicket = 40
14 | CSOEconItemTournamentPassport = 42
15 | CSODOTAGameAccountClient = 2002
16 | CSODOTAParty = 2003
17 | CSODOTALobby = 2004
18 | CSODOTAPartyInvite = 2006
19 | CSODOTAGameHeroFavorites = 2007
20 | CSODOTAMapLocationState = 2008
21 | CMsgDOTATournament = 2009
22 | CSODOTAPlayerChallenge = 2010
23 | CSODOTALobbyInvite = 2011
24 | CSODOTAGameAccountPlus = 2012
25 |
26 |
27 | class EServerRegion(IntEnum):
28 | Unspecified = 0
29 | USWest = 1
30 | USEast = 2
31 | Europe = 3 # EU West
32 | Korea = 4
33 | Singapore = 5
34 | Dubai = 6
35 | PerfectWorldTelecom = 12 # china
36 | PerfectWorldTelecomGuangdong = 17 #
37 | PerfectWorldTelecomZhejiang = 18 #
38 | PerfectWorldTelecomWuhan = 20 #
39 | PerfectWorldUnicom = 13 #
40 | PerfectWorldUnicomTianjin = 25 #
41 | Stockholm = 8 # Russia
42 | Brazil = 10
43 | Austria = 9 # EU East
44 | Australia = 7
45 | SouthAfrica = 11
46 | Chile = 14
47 | Peru = 15
48 | India = 16
49 | Japan = 19
50 | Taiwan = 37
51 |
52 |
53 | # Do not remove
54 | from sys import modules
55 | from enum import EnumMeta
56 |
57 | __all__ = [obj.__name__
58 | for obj in modules[__name__].__dict__.values()
59 | if obj.__class__ is EnumMeta and obj.__name__ != 'IntEnum'
60 | ]
61 |
62 | del modules, EnumMeta
63 |
--------------------------------------------------------------------------------
/dota2/enums.py:
--------------------------------------------------------------------------------
1 |
2 | from dota2.common_enums import *
3 | from dota2.proto_enums import *
4 |
--------------------------------------------------------------------------------
/dota2/features/__init__.py:
--------------------------------------------------------------------------------
1 | from dota2.features.player import Player
2 | from dota2.features.match import Match
3 | from dota2.features.lobby import Lobby
4 | from dota2.features.chat import ChatBase
5 | from dota2.features.sharedobjects import SOBase
6 | from dota2.features.party import Party
7 |
8 |
9 | class FeatureBase(Player, Match, Lobby, Party, ChatBase, SOBase):
10 | """
11 | This object is used to all high level functionality to Dota2Client.
12 | The features are seperated into submodules with a single class.
13 | """
14 | pass
15 |
--------------------------------------------------------------------------------
/dota2/features/chat.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import six
3 | from eventemitter import EventEmitter
4 | from dota2.enums import EDOTAGCMsg, DOTAChatChannelType_t
5 | from dota2.protobufs.dota_gcmessages_client_chat_pb2 import CMsgDOTAJoinChatChannelResponse,\
6 | CMsgDOTAChatChannelFullUpdate,\
7 | CMsgDOTAOtherJoinedChatChannel,\
8 | CMsgDOTAOtherLeftChatChannel,\
9 | CMsgDOTAChatChannelMemberUpdate
10 |
11 |
12 | class ChatBase(object):
13 | def __init__(self):
14 | super(ChatBase, self).__init__()
15 | name = "%s.channels" % self.__class__.__name__
16 | self.channels = ChannelManager(self, name)
17 |
18 |
19 | class ChannelManager(EventEmitter):
20 | EVENT_JOINED_CHANNEL = 'channel_joined'
21 | """When the client join a channel.
22 |
23 | :param channel: channel instance
24 | :type channel: :class:`ChatChannel`
25 | """
26 | EVENT_LEFT_CHANNEL = 'channel_left'
27 | """When the client leaves a channel.
28 |
29 | :param channel: channel instance
30 | :type channel: :class:`ChatChannel`
31 | """
32 | EVENT_MESSAGE = 'message'
33 | """On a new channel message
34 |
35 | :param channel: channel instance
36 | :type channel: :class:`ChatChannel`
37 | :param message: message data
38 | :type message: `CMsgDOTAChatMessage `_
39 | """
40 | EVENT_CHANNEL_MEMBERS_UPDATE = 'members_update'
41 | """When users join/leave a channel
42 |
43 | :param channel: channel instance
44 | :type channel: :class:`ChatChannel`
45 | :param joined: list of members who joined
46 | :type joined: list
47 | :param left: list of members who left
48 | :type left: list
49 | """
50 |
51 | def emit(self, event, *args):
52 | if event is not None:
53 | self._LOG.debug("Emit event: %s" % repr(event))
54 | EventEmitter.emit(self, event, *args)
55 |
56 | def __init__(self, dota_client, logger_name):
57 | super(ChannelManager, self).__init__()
58 |
59 | self._LOG = logging.getLogger(logger_name if logger_name else self.__class__.__name__)
60 | self._dota = dota_client
61 | self._channels = {}
62 | self._channels_by_name = {}
63 |
64 | # register our handlers
65 | self._dota.on('notready', self._cleanup)
66 | self._dota.on(EDOTAGCMsg.EMsgGCJoinChatChannelResponse, self._handle_join_response)
67 | self._dota.on(EDOTAGCMsg.EMsgGCChatMessage, self._handle_message)
68 | self._dota.on(EDOTAGCMsg.EMsgGCOtherJoinedChannel, self._handle_members_update)
69 | self._dota.on(EDOTAGCMsg.EMsgGCOtherLeftChannel, self._handle_members_update)
70 | self._dota.on(EDOTAGCMsg.EMsgDOTAChatChannelMemberUpdate, self._handle_members_update)
71 |
72 | def __repr__(self):
73 | return "" % (
74 | len(self),
75 | )
76 |
77 | def _cleanup(self):
78 | self._channels.clear()
79 | self._channels_by_name.clear()
80 |
81 | def _remove_channel(self, channel_id):
82 | channel = self._channels.pop(channel_id, None)
83 | self._channels_by_name.pop((channel.name, channel.type), None)
84 |
85 | def __contains__(self, key):
86 | return (key in self._channels) or (key in self._channels_by_name)
87 |
88 | def __getitem__(self, key):
89 | if isinstance(key, tuple):
90 | return self._channels_by_name[key]
91 | else:
92 | return self._channels[key]
93 |
94 | def __len__(self):
95 | return len(self._channels)
96 |
97 | def __iter__(self):
98 | return six.itervalues(self._channels)
99 |
100 | def _handle_join_response(self, message):
101 | key = (message.channel_name, message.channel_type)
102 | self.emit(('join_result',) + key, message.result)
103 |
104 | if message.result == message.JOIN_SUCCESS:
105 | if message.channel_id in self:
106 | channel = self[message.channel_id]
107 | else:
108 | channel = ChatChannel(self, message)
109 |
110 | self._channels[channel.id] = channel
111 | self._channels_by_name[key] = channel
112 |
113 | self.emit(self.EVENT_JOINED_CHANNEL, channel)
114 |
115 | def _handle_message(self, message):
116 | if message.channel_id in self:
117 | self.emit(self.EVENT_MESSAGE, self[message.channel_id], message)
118 |
119 | def _handle_members_update(self, message):
120 | if message.channel_id in self:
121 | channel = self[message.channel_id]
122 | joined = []
123 | left = []
124 |
125 | if isinstance(message, CMsgDOTAOtherLeftChatChannel):
126 | left.append(message.steam_id or message.channel_user_id)
127 | elif isinstance(message, CMsgDOTAOtherJoinedChatChannel):
128 | joined.append(message.steam_id or message.channel_user_id)
129 | elif isinstance(message, CMsgDOTAChatChannelMemberUpdate):
130 | left = list(message.left_steam_ids)
131 | joined = list(map(lambda x: x.steam_id or x.channel_user_id, message.joined_members))
132 | elif isinstance(message, CMsgDOTAChatChannelFullUpdate):
133 | pass
134 |
135 | channel._process_members_from_proto(message)
136 |
137 | if joined or left:
138 | self.emit(self.EVENT_CHANNEL_MEMBERS_UPDATE, channel, joined, left)
139 |
140 | def join_channel(self, channel_name, channel_type=DOTAChatChannelType_t.DOTAChannelType_Custom):
141 | """Join a chat channel
142 |
143 | :param channel_name: channel name
144 | :type channel_name: str
145 | :param channel_type: channel type
146 | :type channel_type: :class:`.DOTAChatChannelType_t`
147 | :return: join result
148 | :rtype: int
149 |
150 | Response event: :attr:`EVENT_JOINED_CHANNEL`
151 | """
152 | if self._dota.verbose_debug:
153 | self._LOG.debug("Request to join chat channel: %s", channel_name)
154 |
155 | self._dota.send(EDOTAGCMsg.EMsgGCJoinChatChannel, {
156 | "channel_name": channel_name,
157 | "channel_type": channel_type
158 | })
159 |
160 | resp = self.wait_event(('join_result', channel_name, channel_type), timeout=25)
161 |
162 | if resp:
163 | return resp[0]
164 | else:
165 | return None
166 |
167 | def join_lobby_channel(self):
168 | """
169 | Join the lobby channel if the client is in a lobby.
170 |
171 | Response event: :attr:`EVENT_JOINED_CHANNEL`
172 | """
173 | if self._dota.lobby:
174 | key = "Lobby_%s" % self._dota.lobby.lobby_id, DOTAChatChannelType_t.DOTAChannelType_Lobby
175 | return self.join_channel(*key)
176 |
177 | @property
178 | def lobby(self):
179 | """References lobby channel if client has joined it
180 |
181 | :return: channel instance
182 | :rtype: :class:`.ChatChannel`
183 | """
184 | if self._dota.lobby:
185 | key = "Lobby_%s" % self._dota.lobby.lobby_id, DOTAChatChannelType_t.DOTAChannelType_Lobby
186 | return self._channels_by_name.get(key, None)
187 |
188 | def join_party_channel(self):
189 | """
190 | Join the lobby channel if the client is in a lobby.
191 |
192 | Response event: :attr:`EVENT_JOINED_CHANNEL`
193 | """
194 | if self._dota.party:
195 | key = "Party_%s" % self._dota.party.party_id, DOTAChatChannelType_t.DOTAChannelType_Party
196 | return self.join_channel(*key)
197 |
198 | @property
199 | def party(self):
200 | """References party channel if client has joined it
201 |
202 | :return: channel instance
203 | :rtype: :class:`.ChatChannel`
204 | """
205 | if self._dota.party:
206 | key = "Party_%s" % self._dota.party.party_id, DOTAChatChannelType_t.DOTAChannelType_Party
207 | return self._channels_by_name.get(key, None)
208 |
209 | def get_channel_list(self):
210 | """
211 | Requests a list of chat channels from the GC.
212 |
213 | :return: List of chat channels
214 | :rtype: `CMsgDOTAChatGetUserListResponse `_, ``None``
215 | """
216 | if self._dota.verbose_debug:
217 | self._LOG.debug("Requesting channel list from GC.")
218 |
219 | jobid = self._dota.send_job(EDOTAGCMsg.EMsgGCRequestChatChannelList, {})
220 | resp = self._dota.wait_msg(jobid, timeout=25)
221 |
222 | return resp
223 |
224 | def leave_channel(self, channel_id):
225 | if channel_id in self:
226 | channel = self[channel_id]
227 |
228 | if self._dota.verbose_debug:
229 | self._LOG.debug("Leaving chat channel: %s", repr(channel))
230 |
231 | self._dota.send(EDOTAGCMsg.EMsgGCLeaveChatChannel, {
232 | "channel_id": channel_id
233 | })
234 |
235 | self._remove_channel(channel_id)
236 | self.emit(self.EVENT_LEFT_CHANNEL, channel)
237 |
238 |
239 | class ChatChannel(object):
240 | def __init__(self, channel_manager, join_data):
241 | self._manager = channel_manager
242 | self._dota = self._manager._dota
243 | self._LOG = self._manager._LOG
244 |
245 | self.members = {}
246 | self.id = join_data.channel_id
247 | self.name = join_data.channel_name
248 | self.type = join_data.channel_type
249 | self.user_id = join_data.channel_user_id
250 | self.max_members = join_data.max_members
251 |
252 | self._process_members_from_proto(join_data)
253 |
254 | def __repr__(self):
255 | return "" % (
256 | self.id,
257 | repr(self.name),
258 | self.type,
259 | )
260 |
261 | def _process_members_from_proto(self, data):
262 | if isinstance(data, CMsgDOTAOtherLeftChatChannel):
263 | self.members.pop(data.steam_id or data.channel_user_id, None)
264 | return
265 | elif isinstance(data, CMsgDOTAOtherJoinedChatChannel):
266 | members = [data]
267 | elif isinstance(data, CMsgDOTAJoinChatChannelResponse):
268 | members = data.members
269 | elif isinstance(data, CMsgDOTAChatChannelMemberUpdate):
270 | for steam_id in data.left_steam_ids:
271 | self.members.pop(steam_id, None)
272 |
273 | members = data.joined_members
274 |
275 | for member in members:
276 | self.members[member.steam_id or member.channel_user_id] = (
277 | member.persona_name,
278 | member.status
279 | )
280 |
281 |
282 | def leave(self):
283 | """Leave channel"""
284 | self._manager.leave_channel(self.id)
285 |
286 | def send(self, message):
287 | """Send a message to the channel
288 |
289 | :param message: message text
290 | :type message: str
291 | """
292 | self._dota.send(EDOTAGCMsg.EMsgGCChatMessage, {
293 | "channel_id": self.id,
294 | "text": message
295 | })
296 |
297 | def share_lobby(self):
298 | """Share current lobby to the channel"""
299 | if self._dota.lobby:
300 | self._dota.send(EDOTAGCMsg.EMsgGCChatMessage, {
301 | "channel_id": self.id,
302 | "share_lobby_id": self._dota.lobby.lobby_id,
303 | "share_lobby_passkey": self._dota.lobby.pass_key
304 | })
305 |
306 | def flip_coin(self):
307 | """Flip a coin"""
308 | self._dota.send(EDOTAGCMsg.EMsgGCChatMessage, {
309 | "channel_id": self.id,
310 | "coin_flip": True
311 | })
312 |
313 | def roll_dice(self, rollmin=1, rollmax=100):
314 | """Roll a dice
315 |
316 | :param rollmin: dice min value
317 | :type rollmin: int
318 | :param rollmax: dice max value
319 | :type rollmax: int
320 | """
321 | self._dota.send(EDOTAGCMsg.EMsgGCChatMessage, {
322 | "channel_id": self.id,
323 | "dice_roll": {
324 | "roll_min": dmin,
325 | "roll_max": dmax
326 | }
327 | })
328 |
--------------------------------------------------------------------------------
/dota2/features/match.py:
--------------------------------------------------------------------------------
1 | from steam.enums import EResult
2 | from dota2.enums import EDOTAGCMsg
3 |
4 | class Match(object):
5 | def __init__(self):
6 | super(Match, self).__init__()
7 |
8 | # register our handlers
9 | self.on(EDOTAGCMsg.EMsgGCMatchmakingStatsResponse, self.__handle_mmstats)
10 | self.on(EDOTAGCMsg.EMsgGCToClientFindTopSourceTVGamesResponse, self.__handle_top_source_tv)
11 | self.on(EDOTAGCMsg.EMsgDOTAGetPlayerMatchHistoryResponse, self.__handle_player_match_history)
12 | self.on(EDOTAGCMsg.EMsgGCRequestMatches, self.__handle_matches)
13 | self.on(EDOTAGCMsg.EMsgClientToGCMatchesMinimalResponse, self.__handle_matches_minimal)
14 |
15 | def request_matchmaking_stats(self):
16 | """
17 | Request matchmaking statistics
18 |
19 | Response event: ``matchmaking_stats``
20 |
21 | :param message: `CMsgDOTAMatchmakingStatsResponse `_
22 | :type message: proto message
23 | """
24 | self.send(EDOTAGCMsg.EMsgGCMatchmakingStatsRequest)
25 |
26 | def __handle_mmstats(self, message):
27 | self.emit("matchmaking_stats", message)
28 |
29 | def request_match_details(self, match_id):
30 | """Request match details for a specific match
31 |
32 | .. note::
33 | Rate limited to 100 requests/day
34 |
35 | :param match_id: match id
36 | :type match_id: :class:`int`
37 | :return: job event id
38 | :rtype: :class:`str`
39 |
40 | Response event: ``match_details``
41 |
42 | :param match_id: match_id for response
43 | :type match_id: :class:`int`
44 | :param eresult: result enum
45 | :type eresult: :class:`steam.enums.common.EResult`
46 | :param match: `CMsgDOTAMatch `_
47 | :type match: proto message
48 | """
49 | jobid = self.send_job(EDOTAGCMsg.EMsgGCMatchDetailsRequest, {
50 | 'match_id': match_id,
51 | })
52 |
53 | def wrap_match_details(message):
54 | eresult = EResult(message.result)
55 | match = message.match if eresult == EResult.OK else None
56 | self.emit('match_details', match_id, eresult, match)
57 |
58 | self.once(jobid, wrap_match_details)
59 |
60 | return jobid
61 |
62 |
63 | def request_matches(self, **kwargs):
64 | """Request matches. For arguments see `CMsgDOTARequestMatches `_
65 |
66 | .. note::
67 | Rate limited to 50 requests/day
68 |
69 | .. warning::
70 | Some of the arguments don't work. Ask Valve
71 |
72 | :return: job event id
73 | :rtype: :class:`str`
74 |
75 | Response event: ``matches``
76 |
77 | :param message: `CMsgDOTARequestMatchesResponse `_
78 | :type message: proto message
79 | """
80 | return self.send_job(EDOTAGCMsg.EMsgGCRequestMatches, kwargs)
81 |
82 | def __handle_matches(self, message):
83 | self.emit('matches', message)
84 |
85 | def request_matches_minimal(self, match_ids):
86 | """
87 | Request matches with only minimal data.
88 |
89 | :param match_ids: match ids
90 | :type match_ids: :class:`list`
91 | :return: job event id
92 | :rtype: :class:`str`
93 |
94 | Response event: ``matches_minimal``
95 |
96 | :param matches: list of `CMsgDOTAMatchMinimal `_
97 | :type matches: :class:`list`
98 |
99 | """
100 | return self.send_job(EDOTAGCMsg.EMsgClientToGCMatchesMinimalRequest, {'match_ids': match_ids})
101 |
102 | def __handle_matches_minimal(self, message):
103 | self.emit('matches_minimal', message.matches)
104 |
105 | def request_top_source_tv_games(self, **kwargs):
106 | """
107 | Find top source TV games. For arguments see `CMsgClientToGCFindTopSourceTVGames `_
108 |
109 | Response event: ``top_source_tv_games``
110 |
111 | :param response: `CMsgGCToClientFindTopSourceTVGamesResponse `_
112 | :type response: proto message
113 | """
114 | self.send(EDOTAGCMsg.EMsgClientToGCFindTopSourceTVGames, kwargs)
115 |
116 | def __handle_top_source_tv(self, message):
117 | self.emit("top_source_tv_games", message)
118 |
119 | def request_player_match_history(self, **kwargs):
120 | """Request player match history
121 |
122 | :param account_id: account id
123 | :type account_id: :class:`int`
124 | :param start_at_match_id: matches from before this match id (``0`` for latest)
125 | :type start_at_match_id: :class:`int`
126 | :param matches_requested: number of matches to return
127 | :type matches_requested: :class:`int`
128 | :param hero_id: filter by hero id
129 | :type hero_id: :class:`int`
130 | :param request_id: request id to match with the response with the request
131 | :type request_id: :class:`int`
132 | :param include_practice_matches: whether to include practive matches
133 | :type include_practice_matches: :class:`bool`
134 | :param include_custom_games: whether to include custom matches
135 | :type include_custom_games: :class:`bool`
136 |
137 | Response event: ``player_match_history``
138 |
139 | :param request_id: request id from the reuqest
140 | :type request_id: :class:`int`
141 | :param matches: `CMsgDOTAGetPlayerMatchHistoryResponse.matches `_
142 | :type matches: :class:`list`
143 |
144 | """
145 | self.send(EDOTAGCMsg.EMsgDOTAGetPlayerMatchHistory, kwargs)
146 |
147 | def __handle_player_match_history(self, message):
148 | self.emit('player_match_history', message.request_id, message.matches)
149 |
150 |
--------------------------------------------------------------------------------
/dota2/features/party.py:
--------------------------------------------------------------------------------
1 | from dota2.enums import EGCBaseMsg, EDOTAGCMsg, ESOType
2 |
3 |
4 | class Party(object):
5 | EVENT_PARTY_INVITE = 'party_invite'
6 | """When a party invite is receieved
7 |
8 | :param message: `CSODOTAPartyInvite `_
9 | :type message: proto message
10 | """
11 | EVENT_NEW_PARTY = 'new_party'
12 | """Entered a party, either by inviting someone or accepting an invite
13 |
14 | :param message: `CSODOTAParty `_
15 | :type message: proto message
16 | """
17 | EVENT_PARTY_CHANGED = 'party_changed'
18 | """Anything changes to the party state, leaving/entering/invites etc
19 |
20 | :param message: `CSODOTAParty `_
21 | :type message: proto message
22 | """
23 | EVENT_PARTY_REMOVED = 'party_removed'
24 | """Left party, either left, kicked or disbanded
25 |
26 | :param message: `CSODOTAParty `_
27 | :type message: proto message
28 | """
29 | EVENT_INVITATION_CREATED = 'invitation_created'
30 | """After inviting another user
31 |
32 | :param message: `CMsgInvitationCreated `_
33 | :type message: proto message
34 | """
35 |
36 | party = None
37 |
38 | def __init__(self):
39 | super(Party, self).__init__()
40 | self.on('notready', self.__party_cleanup)
41 | self.socache.on(('new', ESOType.CSODOTAPartyInvite), self.__handle_party_invite)
42 | self.socache.on(('new', ESOType.CSODOTAParty), self.__handle_party_new)
43 | self.socache.on(('updated', ESOType.CSODOTAParty), self.__handle_party_changed)
44 | self.socache.on(('removed', ESOType.CSODOTAParty), self.__handle_party_removed)
45 |
46 | self.on(EGCBaseMsg.EMsgGCInvitationCreated, self.__handle_invitation_created)
47 |
48 | def __party_cleanup(self):
49 | self.party = None
50 |
51 | def __handle_party_invite(self, message):
52 | self.emit('party_invite', message)
53 |
54 | def __handle_party_new(self, message):
55 | self.party = message
56 | self.emit('new_party', message)
57 |
58 | def __handle_party_changed(self, message):
59 | self.party = message
60 | self.emit('party_changed', message)
61 |
62 | def __handle_party_removed(self, message):
63 | self.party = None
64 | self.emit('party_removed', message)
65 |
66 | def __handle_invitation_created(self, message):
67 | self.emit('invitation_created', message)
68 |
69 | def respond_to_party_invite(self, party_id, accept=False):
70 | """
71 | Respond to a party invite.
72 |
73 | :param party_id: party id
74 | :param accept: accept
75 | """
76 | if self.verbose_debug:
77 | self._LOG.debug("Responding to party invite %s, accept: %s" % (party_id, accept))
78 |
79 | self.send(EGCBaseMsg.EMsgGCPartyInviteResponse, {
80 | "party_id": party_id,
81 | "accept": accept
82 | })
83 |
84 | def leave_party(self):
85 | """
86 | Leaves the current party.
87 |
88 | :return: job event id
89 | :rtype: str
90 | """
91 | if self.verbose_debug:
92 | self._LOG.debug("Leaving party.")
93 |
94 | self.send(EGCBaseMsg.EMsgGCLeaveParty, {})
95 |
96 | def set_party_leader(self, steam_id):
97 | """
98 | Set the new party leader.
99 |
100 | :param steam_id: steam_id
101 | :return: job event id
102 | :rtype: str
103 | """
104 | if not self.party: return
105 |
106 | if self.verbose_debug:
107 | self._LOG.debug("Setting party leader: %s" % steam_id)
108 |
109 | self.send(EDOTAGCMsg.EMsgClientToGCSetPartyLeader, {
110 | "new_leader_steamid": steam_id
111 | })
112 |
113 | def set_party_coach_flag(self, coach):
114 | """
115 | Set the bot's status as a coach.
116 |
117 | :param coach: bool
118 | :return: job event id
119 | :rtype: str
120 |
121 | Response event: ``party_coach``
122 |
123 | :param steam_id: steam_id for response
124 | :type steam_id: :class:`int`
125 |
126 | :param message: `CMsgDOTAPartyMemberSetCoach `_ proto message
127 | """
128 | if not self.party or self.party.leader_id != self.steam.steam_id: return
129 |
130 | if self.verbose_debug:
131 | self._LOG.debug("Setting coach flag to: %s" % coach)
132 |
133 | self.send(EDOTAGCMsg.EMsgGCPartyMemberSetCoach, {
134 | "wants_coach": coach
135 | })
136 |
137 | def invite_to_party(self, steam_id):
138 | """
139 | Invites a player to a party. This will create a new party if you aren't in one.
140 |
141 | :param steam_id: steam_id
142 | :return: job event id
143 | :rtype: str
144 |
145 | Response event: ``invite_to_party``
146 |
147 | :param message: `CMsgInvitationCreated `_ proto message
148 | """
149 | if self.party and self.party.leader_id != self.steam.steam_id: return
150 |
151 | if self.verbose_debug:
152 | self._LOG.debug("Inviting %s to a party." % steam_id)
153 |
154 | jobid = self.send_job(EGCBaseMsg.EMsgGCInviteToParty, {
155 | "steam_id": steam_id
156 | })
157 |
158 | @self.once(jobid)
159 | def wrap_invite_to_party(message):
160 | self.emit('invitation_created', message)
161 |
162 | return jobid
163 |
164 | def kick_from_party(self, steam_id):
165 | """
166 | Kicks a player from the party. This will create a new party
167 | if you aren't in one.
168 |
169 | :param steam_id: steam_id
170 | :return: job event id
171 | :rtype: str
172 |
173 | Response event: ``kick_from_party``
174 |
175 | :param steam_id: steam_id for response
176 | :type steam_id: :class:`int`
177 |
178 | :param message: `CMsgKickFromParty `_ proto message
179 | """
180 | if (not self.party
181 | or self.party.leader_id != self.steam.steam_id
182 | or steam_id not in self.party.memeber_ids): return
183 |
184 | if self.verbose_debug:
185 | self._LOG.debug("Kicking %s from the party." % steam_id)
186 |
187 | self.send(EGCBaseMsg.EMsgGCKickFromParty, {
188 | "steam_id": steam_id
189 | })
190 |
--------------------------------------------------------------------------------
/dota2/features/player.py:
--------------------------------------------------------------------------------
1 | from steam.enums import EResult
2 | from dota2.enums import EDOTAGCMsg
3 |
4 | class Player(object):
5 | def __init__(self):
6 | super(Player, self).__init__()
7 |
8 | # register our handlers
9 | self.on(EDOTAGCMsg.EMsgGCPlayerInfo, self.__handle_player_info)
10 | self.on(EDOTAGCMsg.EMsgClientToGCLatestConductScorecard, self.__handle_conduct_scorecard)
11 | self.on(EDOTAGCMsg.EMsgGCGetHeroStandingsResponse, self.__handle_hero_standings)
12 |
13 | def request_profile(self, account_id):
14 | """
15 | Request profile details
16 |
17 | :param account_id: steam account_id
18 | :type account_id: :class:`int`
19 | :return: job id
20 | :rtype: :class:`str`
21 |
22 | Response event: ``profile_data``
23 |
24 | :param account_id: account_id from request
25 | :type account_id: :class:`int`
26 | :param message: `CMsgProfileResponse `_
27 | :type message: proto message
28 |
29 | """
30 | jobid = self.send_job(EDOTAGCMsg.EMsgProfileRequest, {
31 | 'account_id': account_id,
32 | })
33 |
34 | def wrap_profile_data(message):
35 | self.emit("profile_data", account_id, message)
36 |
37 | self.once(jobid, wrap_profile_data)
38 |
39 | return jobid
40 |
41 | def request_gc_profile(self, account_id, request_name=False):
42 | """
43 | Request profile details
44 |
45 | .. warning::
46 | Disabled by Valve
47 |
48 | :param account_id: steam account_id
49 | :type account_id: :class:`int`
50 | :param request_name: whether to return name
51 | :type request_name: :class:`bool`
52 | :return: job id
53 | :rtype: :class:`str`
54 |
55 | Response event: ``gc_profile_data``
56 |
57 | :param account_id: account_id from request
58 | :type account_id: :class:`int`
59 | :param eresult: result enum
60 | :type eresult: :class:`steam.enums.common.EResult`
61 | :param message: `CMsgDOTAProfileResponse `_
62 | :type message: proto message
63 |
64 | """
65 | jobid = self.send_job(EDOTAGCMsg.EMsgGCProfileRequest, {
66 | 'account_id': account_id,
67 | 'request_name': request_name,
68 | })
69 |
70 | def wrap_profile_data(message):
71 | eresult = EResult(message.result)
72 | message = message if eresult == EResult.OK else None
73 | self.emit("gc_profile_data", account_id, eresult, message)
74 |
75 | self.once(jobid, wrap_profile_data)
76 |
77 | return jobid
78 |
79 | def request_profile_card(self, account_id):
80 | """
81 | Request profile card
82 |
83 | :param account_id: steam account_id
84 | :type account_id: :class:`int`
85 | :return: job id
86 | :rtype: :class:`str`
87 |
88 | Response event: ``profile_card``
89 |
90 | :param account_id: account_id from request
91 | :type account_id: :class:`int`
92 | :param message: `CMsgDOTAProfileCard `_
93 | :type message: proto message
94 |
95 | """
96 | jobid = self.send_job(EDOTAGCMsg.EMsgClientToGCGetProfileCard, {
97 | 'account_id': account_id,
98 | })
99 |
100 | def wrap_profile_card(message):
101 | self.emit("profile_card", account_id, message)
102 |
103 | self.once(jobid, wrap_profile_card)
104 |
105 | return jobid
106 |
107 | def request_player_stats(self, account_id):
108 | """
109 | Request players stats. These are located in the ``play style`` box on a player profie.
110 |
111 | :param account_id: steam account_id
112 | :type account_id: :class:`int`
113 | :return: job id
114 | :rtype: :class:`str`
115 |
116 | Response event: ``player_stats``
117 |
118 | :param account_id: account_id from request
119 | :type account_id: :class:`int`
120 | :param message: `CMsgGCToClientPlayerStatsResponse `_
121 | :type message: proto message
122 |
123 | """
124 | jobid = self.send_job(EDOTAGCMsg.EMsgClientToGCPlayerStatsRequest, {
125 | 'account_id': account_id,
126 | })
127 |
128 | def wrap_player_stats(message):
129 | self.emit("player_stats", account_id, message)
130 |
131 | self.once(jobid, wrap_player_stats)
132 |
133 | return jobid
134 |
135 | def request_player_info(self, account_ids):
136 | """
137 | .. warning::
138 | Disabled by Valve
139 |
140 | Request official player information
141 |
142 | :param account_id: A list of account ids
143 | :type account_id: :class:`list`
144 |
145 | Response event: ``player_info``
146 |
147 | :param message: `CMsgGCPlayerInfo `_
148 | :type message: proto message
149 | """
150 | if not isinstance(account_ids, list):
151 | raise ValueError("Expected account_ids to be a list")
152 |
153 | self.send(EDOTAGCMsg.EMsgGCPlayerInfoRequest, {
154 | 'player_infos': map(lambda x: {'account_id': x}, account_ids),
155 | })
156 |
157 | def __handle_player_info(self, message):
158 | self.emit("player_info", message)
159 |
160 | def request_conduct_scorecard(self):
161 | """
162 | Request conduct scorecard, otherwise knows as conduct summary
163 |
164 | :return: job id
165 | :rtype: :class:`str`
166 |
167 | Response event: ``conduct_scorecard``
168 |
169 | :param message: `CMsgPlayerConductScorecard `_
170 | :type message: proto message
171 | """
172 | return self.send_job(EDOTAGCMsg.EMsgClientToGCLatestConductScorecardRequest)
173 |
174 | def __handle_conduct_scorecard(self, message):
175 | self.emit("conduct_scorecard", message)
176 |
177 | def request_hero_standings(self):
178 | """
179 | Request hero stands for the currently logged on account.
180 | This is the data from the ``stats`` tab on your profile.
181 |
182 | Response event: ``hero_standings``
183 |
184 | :param message: `CMsgGCGetHeroStandingsResponse `_
185 | :type message: proto message
186 | """
187 | return self.send_job(EDOTAGCMsg.EMsgGCGetHeroStandings)
188 |
189 | def __handle_hero_standings(self, message):
190 | self.emit("hero_standings", message)
191 |
--------------------------------------------------------------------------------
/dota2/features/sharedobjects.py:
--------------------------------------------------------------------------------
1 | """Essentially a :class:`dict` containing shared object caches.
2 | The objects are read-only, so don't change any values.
3 | The instance reference of individual objects will remain the same thought their lifetime.
4 | Individual objects can be accessed via their key, if they have one.
5 |
6 | .. note::
7 | Some cache types don't have a key and only hold one object instance.
8 | Then only the the cache type is needed to access it.
9 | (e.g. ``CSOEconGameAccountClient``)
10 |
11 | .. code:: python
12 |
13 | dota_client.socache[ESOType.CSOEconItem] # dict with item objects, key = item id
14 | dota_client.socache[ESOType.CSOEconItem][123456] # item object
15 |
16 | dota_client.socache[ESOType.CSOEconGameAccountClient] # returns a CSOEconGameAccountClient object
17 |
18 | Events will be fired when individual objects are updated.
19 | Event key is a :class:`tuple`` in the following format: ``(event, cache_type)``.
20 |
21 | The available events are ``new``, ``updated``, and ``removed``.
22 | Each event has a single parameter, which is the object instance.
23 | Even when removed, there is object instance returned, usually only with the key field filled.
24 |
25 | .. code:: python
26 |
27 | @dota_client.socache.on(('new', ESOType.CSOEconItem))
28 | def got_a_new_item(obj):
29 | print "Got a new item! Yay"
30 | print obj
31 |
32 | # access the item via socache at any time
33 | print dota_client.socache[ESOType.CSOEconItem][obj.id]
34 |
35 | """
36 | import logging
37 | from eventemitter import EventEmitter
38 | from dota2.enums import EGCBaseClientMsg, ESOMsg, ESOType
39 | from dota2.protobufs import base_gcmessages_pb2 as _gc_base
40 | from dota2.protobufs import dota_gcmessages_client_pb2 as _gc_client
41 | from dota2.protobufs import dota_gcmessages_common_pb2 as _gc_common
42 | from dota2.protobufs import dota_gcmessages_common_match_management_pb2 as _gc_cmm
43 |
44 |
45 | def find_so_proto(type_id):
46 | """Resolves proto massage for given type_id
47 |
48 | :param type_id: SO type
49 | :type type_id: :class:`dota2.enums.ESOType`
50 | :returns: proto message or `None`
51 | """
52 | if not isinstance(type_id, ESOType):
53 | return None
54 |
55 | proto = getattr(_gc_base, type_id.name, None)
56 | if proto is None:
57 | proto = getattr(_gc_client, type_id.name, None)
58 | if proto is None:
59 | proto = getattr(_gc_common, type_id.name, None)
60 | if proto is None:
61 | proto = getattr(_gc_cmm, type_id.name, None)
62 |
63 | return proto
64 |
65 | # hack to mark certain CSO as having no key
66 | class NO_KEY:
67 | pass
68 |
69 | so_key_fields = {
70 | _gc_base.CSOEconItem.DESCRIPTOR: ['id'],
71 | _gc_base.CSOEconGameAccountClient.DESCRIPTOR: NO_KEY,
72 | _gc_common.CSODOTAGameAccountClient.DESCRIPTOR: NO_KEY,
73 | }
74 |
75 | # key is either one or a number of fields marked with option 'key_field'=true in protos
76 | def get_so_key_fields(desc):
77 | if desc in so_key_fields:
78 | return so_key_fields[desc]
79 | else:
80 | fields = []
81 |
82 | for field in desc.fields:
83 | for odesc, value in field.GetOptions().ListFields():
84 | if odesc.name == 'key_field' and value == True:
85 | fields.append(field.name)
86 |
87 | so_key_fields[desc] = fields
88 | return fields
89 |
90 | def get_key_for_object(obj):
91 | key = get_so_key_fields(obj.DESCRIPTOR)
92 |
93 | if key is NO_KEY:
94 | return NO_KEY
95 | elif not key:
96 | return None
97 | elif len(key) == 1:
98 | return getattr(obj, key[0])
99 | else:
100 | return tuple(map(lambda x: getattr(obj, x), key))
101 |
102 |
103 | class SOBase(object):
104 | def __init__(self):
105 | super(SOBase, self).__init__()
106 |
107 | #: Shared Object Caches
108 | name = "%s.socache" % self.__class__.__name__
109 | self.socache = SOCache(self, name)
110 |
111 |
112 | class SOCache(EventEmitter, dict):
113 | ESOType = ESOType #: expose ESOType
114 |
115 | file_version = None #: so file version
116 |
117 | def __init__(self, dota_client, logger_name):
118 | self._LOG = logging.getLogger(logger_name if logger_name else self.__class__.__name__)
119 | self._caches = {}
120 | self._dota = dota_client
121 |
122 | # register our handlers
123 | dota_client.on(ESOMsg.Create, self._handle_create)
124 | dota_client.on(ESOMsg.Update, self._handle_update)
125 | dota_client.on(ESOMsg.Destroy, self._handle_destroy)
126 | dota_client.on(ESOMsg.UpdateMultiple, self._handle_update_multiple)
127 | dota_client.on(ESOMsg.CacheSubscribed, self._handle_cache_subscribed)
128 | dota_client.on(ESOMsg.CacheUnsubscribed, self._handle_cache_unsubscribed)
129 | dota_client.on(EGCBaseClientMsg.EMsgGCClientWelcome, self._handle_client_welcome)
130 | dota_client.on('notready', self._handle_cleanup)
131 |
132 | def __hash__(self):
133 | # pretend that we are a hashable dict, lol
134 | # don't attach more than one SOCache per DotaClient
135 | return hash((self._dota, 42))
136 |
137 | def __getitem__(self, key):
138 | try:
139 | key = ESOType(key)
140 | except ValueError:
141 | raise KeyError("%s" % key)
142 | if key not in self:
143 | self[key] = dict()
144 | return dict.__getitem__(self, key)
145 |
146 | def __repr__(self):
147 | return "" % repr(self._dota)
148 |
149 | def emit(self, event, *args):
150 | if event is not None:
151 | self._LOG.debug("Emit event: %s" % repr(event))
152 | super(SOCache, self).emit(event, *args)
153 |
154 | def _handle_cleanup(self):
155 | for v in self.values():
156 | if isinstance(v, dict):
157 | v.clear()
158 | self.clear()
159 | self._caches.clear()
160 |
161 | def _get_proto_for_type(self, type_id):
162 | try:
163 | type_id = ESOType(type_id)
164 | except ValueError:
165 | self._LOG.error("Unsupported type: %d" % type_id)
166 | return
167 |
168 | proto = find_so_proto(type_id)
169 |
170 | if proto is None:
171 | self._LOG.error("Unable to locate proto for: %s" % repr(type_id))
172 | return
173 |
174 | return proto
175 |
176 | def _parse_object_data(self, type_id, object_data):
177 | proto = self._get_proto_for_type(type_id)
178 |
179 | if proto is None:
180 | return
181 |
182 | if not get_so_key_fields(proto.DESCRIPTOR):
183 | self._LOG.error("Unable to find key for %s" % type_id)
184 | return
185 |
186 | obj = proto.FromString(object_data)
187 | key = get_key_for_object(obj)
188 |
189 | return key, obj
190 |
191 | def _update_object(self, type_id, object_data):
192 | result = self._parse_object_data(type_id, object_data)
193 |
194 | if result:
195 | key, obj = result
196 | type_id = ESOType(type_id)
197 |
198 | if key is NO_KEY:
199 | if not isinstance(self[type_id], dict):
200 | self[type_id].CopyFrom(obj)
201 | obj = self[type_id]
202 | else:
203 | self[type_id] = obj
204 | else:
205 | if key in self[type_id]:
206 | self[type_id][key].CopyFrom(obj)
207 | obj = self[type_id][key]
208 | else:
209 | self[type_id][key] = obj
210 |
211 | return type_id, obj
212 |
213 | def _handle_create(self, message):
214 | result = self._update_object(message.type_id, message.object_data)
215 | if result:
216 | type_id, obj = result
217 | self.emit(('new', type_id), obj)
218 |
219 | def _handle_update(self, message):
220 | result = self._update_object(message.type_id, message.object_data)
221 | if result:
222 | type_id, obj = result
223 |
224 | if self._dota.verbose_debug:
225 | self._LOG.debug("Incoming: %s\n%s", repr(type_id), obj)
226 |
227 | self.emit(('updated', type_id), obj)
228 |
229 | def _handle_destroy(self, so):
230 | result = self._parse_object_data(so.type_id, so.object_data)
231 | if result:
232 | key, obj = result
233 | type_id = ESOType(so.type_id)
234 | current = None
235 |
236 | if key is NO_KEY:
237 | current = self.pop(type_id, None)
238 | else:
239 | current = self[type_id].pop(key, None)
240 |
241 | if current: current.CopyFrom(obj)
242 |
243 | self.emit(('removed', type_id), current or obj)
244 |
245 | def _handle_update_multiple(self, message):
246 | for so_object in message.objects_modified:
247 | self._handle_update(so_object)
248 | for so_object in message.objects_added:
249 | self._handle_create(so_object)
250 | for so_object in message.objects_removed:
251 | self._handle_destroy(so_object)
252 |
253 | def _handle_client_welcome(self, message):
254 | self.file_version = message.gc_socache_file_version
255 |
256 | for one in message.outofdate_subscribed_caches:
257 | self._handle_cache_subscribed(one)
258 |
259 | def _handle_cache_subscribed(self, message):
260 | cache_key = message.owner_soid.type, message.owner_soid.id
261 | self._caches.setdefault(cache_key, dict())
262 |
263 | cache = self._caches[cache_key]
264 | cache['version'] = message.version
265 | cache.setdefault('type_ids', set()).update(map(lambda x: x.type_id, message.objects))
266 |
267 | for objects in message.objects:
268 | for object_bytes in objects.object_data:
269 | result = self._update_object(objects.type_id, object_bytes)
270 | if not result: break
271 |
272 | type_id, obj = result
273 |
274 | if self._dota.verbose_debug:
275 | self._LOG.debug("Incoming: %s\n%s", repr(type_id), obj)
276 |
277 | self.emit(('new', type_id), obj)
278 |
279 | def _handle_cache_unsubscribed(self, message):
280 | cache_key = message.owner_soid.type, message.owner_soid.id
281 |
282 | if cache_key not in self._caches: return
283 | cache = self._caches[cache_key]
284 |
285 | for type_id in cache['type_ids']:
286 | if type_id in self:
287 | type_id = ESOType(type_id)
288 |
289 | if isinstance(self[type_id], dict):
290 | for key in list(self[type_id].keys()):
291 | self.emit(('removed', type_id), self[type_id].pop(key))
292 | else:
293 | self.emit(('removed', type_id), self.pop(type_id))
294 |
295 | del self[type_id]
296 | del self._caches[cache_key]
297 |
298 |
299 |
--------------------------------------------------------------------------------
/dota2/msg.py:
--------------------------------------------------------------------------------
1 | """
2 | Various utility function for dealing with messages.
3 |
4 | """
5 |
6 | from dota2.enums import EGCBaseClientMsg, EDOTAGCMsg, ESOMsg, EGCItemMsg, EGCBaseMsg
7 | from dota2.protobufs import (
8 | base_gcmessages_pb2,
9 | gcsdk_gcmessages_pb2,
10 | dota_gcmessages_common_pb2,
11 | dota_gcmessages_client_pb2,
12 | dota_gcmessages_client_chat_pb2,
13 | dota_gcmessages_client_fantasy_pb2,
14 | dota_gcmessages_client_guild_pb2,
15 | dota_gcmessages_client_match_management_pb2,
16 | dota_gcmessages_client_team_pb2,
17 | dota_gcmessages_client_tournament_pb2,
18 | dota_gcmessages_client_watch_pb2,
19 | econ_gcmessages_pb2,
20 | )
21 |
22 |
23 | def get_emsg_enum(emsg):
24 | """
25 | Attempts to find the Enum for the given :class:`int`
26 |
27 | :param emsg: integer corresponding to a Enum
28 | :type emsg: :class:`int`
29 | :return: Enum if found, `emsg` if not
30 | :rtype: Enum, :class:`int`
31 | """
32 | for enum in (EGCBaseClientMsg,
33 | EDOTAGCMsg,
34 | ESOMsg,
35 | EGCBaseMsg,
36 | EGCItemMsg,
37 | ):
38 | try:
39 | return enum(emsg)
40 | except ValueError:
41 | pass
42 |
43 | return emsg
44 |
45 |
46 | def find_proto(emsg):
47 | """
48 | Attempts to find the protobuf message for a given Enum
49 |
50 | :param emsg: Enum corrensponding to a protobuf message
51 | :type emsg: `Enum`
52 | :return: protobuf message class
53 | """
54 |
55 | if type(emsg) is int:
56 | return None
57 |
58 | if emsg in _proto_lookup_map:
59 | return _proto_lookup_map.get(emsg)
60 |
61 | if isinstance(emsg, ESOMsg):
62 | proto = _proto_lookup_map[emsg] = getattr(gcsdk_gcmessages_pb2, "CMsgSO%s" % emsg.name, None)
63 | return proto
64 |
65 | for module in (base_gcmessages_pb2,
66 | gcsdk_gcmessages_pb2,
67 | dota_gcmessages_common_pb2,
68 | dota_gcmessages_client_pb2,
69 | dota_gcmessages_client_chat_pb2,
70 | dota_gcmessages_client_fantasy_pb2,
71 | dota_gcmessages_client_guild_pb2,
72 | dota_gcmessages_client_match_management_pb2,
73 | dota_gcmessages_client_team_pb2,
74 | dota_gcmessages_client_tournament_pb2,
75 | dota_gcmessages_client_watch_pb2,
76 | econ_gcmessages_pb2,
77 | ):
78 |
79 | proto = getattr(module, emsg.name.replace("EMsg", "CMsg"), None)
80 |
81 | if proto is None:
82 | proto = getattr(module, emsg.name.replace("EMsgGC", "CMsgDOTA"), None)
83 | if proto is None:
84 | proto = getattr(module, emsg.name.replace("EMsgGCToClient", "CMsgDOTA"), None)
85 | if proto is None:
86 | proto = getattr(module, emsg.name.replace("EMsgGCToClient", "CMsg"), None)
87 | if proto is None:
88 | proto = getattr(module, emsg.name.replace("EMsgGC", "CMsg"), None)
89 | if proto is None:
90 | proto = getattr(module, emsg.name.replace("EMsgDOTA", "CMsg"), None)
91 | if proto is None:
92 | proto = getattr(module, emsg.name.replace("EMsg", "CMsgDOTA"), None)
93 |
94 | if proto is not None:
95 | _proto_lookup_map[emsg] = proto
96 | break
97 |
98 | return proto
99 |
100 |
101 | _proto_lookup_map = {
102 | EGCBaseClientMsg.EMsgGCClientConnectionStatus: gcsdk_gcmessages_pb2.CMsgConnectionStatus,
103 | EDOTAGCMsg.EMsgClientToGCGetProfileCardResponse: dota_gcmessages_common_pb2.CMsgDOTAProfileCard,
104 | EDOTAGCMsg.EMsgClientToGCLatestConductScorecardRequest: dota_gcmessages_client_pb2.CMsgPlayerConductScorecardRequest,
105 | EDOTAGCMsg.EMsgClientToGCLatestConductScorecard: dota_gcmessages_client_pb2.CMsgPlayerConductScorecard,
106 | ESOMsg.Create: gcsdk_gcmessages_pb2.CMsgSOSingleObject,
107 | ESOMsg.Update: gcsdk_gcmessages_pb2.CMsgSOSingleObject,
108 | ESOMsg.Destroy: gcsdk_gcmessages_pb2.CMsgSOSingleObject,
109 | ESOMsg.UpdateMultiple: gcsdk_gcmessages_pb2.CMsgSOMultipleObjects,
110 | EDOTAGCMsg.EMsgClientToGCEventGoalsRequest: dota_gcmessages_client_pb2.CMsgClientToGCGetEventGoals,
111 | EDOTAGCMsg.EMsgClientToGCEventGoalsResponse: dota_gcmessages_client_pb2.CMsgEventGoals,
112 | EDOTAGCMsg.EMsgClientToGCSetPartyLeader: dota_gcmessages_client_match_management_pb2.CMsgDOTASetGroupLeader,
113 | EDOTAGCMsg.EMsgGCOtherJoinedChannel: dota_gcmessages_client_chat_pb2.CMsgDOTAOtherJoinedChatChannel,
114 | EDOTAGCMsg.EMsgGCOtherLeftChannel: dota_gcmessages_client_chat_pb2.CMsgDOTAOtherLeftChatChannel,
115 | }
116 |
--------------------------------------------------------------------------------
/dota2/protobufs/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ValvePython/dota2/6ccebc3689e107746ec32ce07fc2f5cacecc0e18/dota2/protobufs/__init__.py
--------------------------------------------------------------------------------
/dota2/protobufs/econ_shared_enums_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: econ_shared_enums.proto
4 |
5 | import sys
6 | _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
7 | from google.protobuf.internal import enum_type_wrapper
8 | from google.protobuf import descriptor as _descriptor
9 | from google.protobuf import message as _message
10 | from google.protobuf import reflection as _reflection
11 | from google.protobuf import symbol_database as _symbol_database
12 | # @@protoc_insertion_point(imports)
13 |
14 | _sym_db = _symbol_database.Default()
15 |
16 |
17 |
18 |
19 | DESCRIPTOR = _descriptor.FileDescriptor(
20 | name='econ_shared_enums.proto',
21 | package='dota',
22 | syntax='proto2',
23 | serialized_options=_b('H\001\220\001\000'),
24 | serialized_pb=_b('\n\x17\x65\x63on_shared_enums.proto\x12\x04\x64ota\">\n\x11\x43MsgGenericResult\x12\x12\n\x07\x65result\x18\x01 \x01(\r:\x01\x32\x12\x15\n\rdebug_message\x18\x02 \x01(\t*,\n\x0e\x45GCEconBaseMsg\x12\x1a\n\x15k_EMsgGCGenericResult\x10\x93\x14*\x9b\x02\n\x0e\x45GCMsgResponse\x12\x16\n\x12k_EGCMsgResponseOK\x10\x00\x12\x1a\n\x16k_EGCMsgResponseDenied\x10\x01\x12\x1f\n\x1bk_EGCMsgResponseServerError\x10\x02\x12\x1b\n\x17k_EGCMsgResponseTimeout\x10\x03\x12\x1b\n\x17k_EGCMsgResponseInvalid\x10\x04\x12\x1b\n\x17k_EGCMsgResponseNoMatch\x10\x05\x12 \n\x1ck_EGCMsgResponseUnknownError\x10\x06\x12\x1f\n\x1bk_EGCMsgResponseNotLoggedOn\x10\x07\x12\x1a\n\x16k_EGCMsgFailedToCreate\x10\x08*\xa2\x01\n\x19\x45GCPartnerRequestResponse\x12\x17\n\x13k_EPartnerRequestOK\x10\x01\x12\x1f\n\x1bk_EPartnerRequestBadAccount\x10\x02\x12\x1e\n\x1ak_EPartnerRequestNotLinked\x10\x03\x12+\n\'k_EPartnerRequestUnsupportedPartnerType\x10\x04*\xc5\x05\n\x15\x45GCMsgUseItemResponse\x12$\n k_EGCMsgUseItemResponse_ItemUsed\x10\x00\x12.\n*k_EGCMsgUseItemResponse_GiftNoOtherPlayers\x10\x01\x12\'\n#k_EGCMsgUseItemResponse_ServerError\x10\x02\x12\x32\n.k_EGCMsgUseItemResponse_MiniGameAlreadyStarted\x10\x03\x12\x31\n-k_EGCMsgUseItemResponse_ItemUsed_ItemsGranted\x10\x04\x12\x37\n3k_EGCMsgUseItemResponse_DropRateBonusAlreadyGranted\x10\x05\x12\x30\n,k_EGCMsgUseItemResponse_NotInLowPriorityPool\x10\x06\x12.\n*k_EGCMsgUseItemResponse_NotHighEnoughLevel\x10\x07\x12*\n&k_EGCMsgUseItemResponse_EventNotActive\x10\x08\x12\x37\n3k_EGCMsgUseItemResponse_ItemUsed_EventPointsGranted\x10\t\x12.\n*k_EGCMsgUseItemResponse_MissingRequirement\x10\n\x12\x30\n,k_EGCMsgUseItemResponse_EmoticonUnlock_NoNew\x10\x0b\x12\x33\n/k_EGCMsgUseItemResponse_EmoticonUnlock_Complete\x10\x0c\x12/\n+k_EGCMsgUseItemResponse_ItemUsed_Compendium\x10\rB\x05H\x01\x90\x01\x00')
25 | )
26 |
27 | _EGCECONBASEMSG = _descriptor.EnumDescriptor(
28 | name='EGCEconBaseMsg',
29 | full_name='dota.EGCEconBaseMsg',
30 | filename=None,
31 | file=DESCRIPTOR,
32 | values=[
33 | _descriptor.EnumValueDescriptor(
34 | name='k_EMsgGCGenericResult', index=0, number=2579,
35 | serialized_options=None,
36 | type=None),
37 | ],
38 | containing_type=None,
39 | serialized_options=None,
40 | serialized_start=97,
41 | serialized_end=141,
42 | )
43 | _sym_db.RegisterEnumDescriptor(_EGCECONBASEMSG)
44 |
45 | EGCEconBaseMsg = enum_type_wrapper.EnumTypeWrapper(_EGCECONBASEMSG)
46 | _EGCMSGRESPONSE = _descriptor.EnumDescriptor(
47 | name='EGCMsgResponse',
48 | full_name='dota.EGCMsgResponse',
49 | filename=None,
50 | file=DESCRIPTOR,
51 | values=[
52 | _descriptor.EnumValueDescriptor(
53 | name='k_EGCMsgResponseOK', index=0, number=0,
54 | serialized_options=None,
55 | type=None),
56 | _descriptor.EnumValueDescriptor(
57 | name='k_EGCMsgResponseDenied', index=1, number=1,
58 | serialized_options=None,
59 | type=None),
60 | _descriptor.EnumValueDescriptor(
61 | name='k_EGCMsgResponseServerError', index=2, number=2,
62 | serialized_options=None,
63 | type=None),
64 | _descriptor.EnumValueDescriptor(
65 | name='k_EGCMsgResponseTimeout', index=3, number=3,
66 | serialized_options=None,
67 | type=None),
68 | _descriptor.EnumValueDescriptor(
69 | name='k_EGCMsgResponseInvalid', index=4, number=4,
70 | serialized_options=None,
71 | type=None),
72 | _descriptor.EnumValueDescriptor(
73 | name='k_EGCMsgResponseNoMatch', index=5, number=5,
74 | serialized_options=None,
75 | type=None),
76 | _descriptor.EnumValueDescriptor(
77 | name='k_EGCMsgResponseUnknownError', index=6, number=6,
78 | serialized_options=None,
79 | type=None),
80 | _descriptor.EnumValueDescriptor(
81 | name='k_EGCMsgResponseNotLoggedOn', index=7, number=7,
82 | serialized_options=None,
83 | type=None),
84 | _descriptor.EnumValueDescriptor(
85 | name='k_EGCMsgFailedToCreate', index=8, number=8,
86 | serialized_options=None,
87 | type=None),
88 | ],
89 | containing_type=None,
90 | serialized_options=None,
91 | serialized_start=144,
92 | serialized_end=427,
93 | )
94 | _sym_db.RegisterEnumDescriptor(_EGCMSGRESPONSE)
95 |
96 | EGCMsgResponse = enum_type_wrapper.EnumTypeWrapper(_EGCMSGRESPONSE)
97 | _EGCPARTNERREQUESTRESPONSE = _descriptor.EnumDescriptor(
98 | name='EGCPartnerRequestResponse',
99 | full_name='dota.EGCPartnerRequestResponse',
100 | filename=None,
101 | file=DESCRIPTOR,
102 | values=[
103 | _descriptor.EnumValueDescriptor(
104 | name='k_EPartnerRequestOK', index=0, number=1,
105 | serialized_options=None,
106 | type=None),
107 | _descriptor.EnumValueDescriptor(
108 | name='k_EPartnerRequestBadAccount', index=1, number=2,
109 | serialized_options=None,
110 | type=None),
111 | _descriptor.EnumValueDescriptor(
112 | name='k_EPartnerRequestNotLinked', index=2, number=3,
113 | serialized_options=None,
114 | type=None),
115 | _descriptor.EnumValueDescriptor(
116 | name='k_EPartnerRequestUnsupportedPartnerType', index=3, number=4,
117 | serialized_options=None,
118 | type=None),
119 | ],
120 | containing_type=None,
121 | serialized_options=None,
122 | serialized_start=430,
123 | serialized_end=592,
124 | )
125 | _sym_db.RegisterEnumDescriptor(_EGCPARTNERREQUESTRESPONSE)
126 |
127 | EGCPartnerRequestResponse = enum_type_wrapper.EnumTypeWrapper(_EGCPARTNERREQUESTRESPONSE)
128 | _EGCMSGUSEITEMRESPONSE = _descriptor.EnumDescriptor(
129 | name='EGCMsgUseItemResponse',
130 | full_name='dota.EGCMsgUseItemResponse',
131 | filename=None,
132 | file=DESCRIPTOR,
133 | values=[
134 | _descriptor.EnumValueDescriptor(
135 | name='k_EGCMsgUseItemResponse_ItemUsed', index=0, number=0,
136 | serialized_options=None,
137 | type=None),
138 | _descriptor.EnumValueDescriptor(
139 | name='k_EGCMsgUseItemResponse_GiftNoOtherPlayers', index=1, number=1,
140 | serialized_options=None,
141 | type=None),
142 | _descriptor.EnumValueDescriptor(
143 | name='k_EGCMsgUseItemResponse_ServerError', index=2, number=2,
144 | serialized_options=None,
145 | type=None),
146 | _descriptor.EnumValueDescriptor(
147 | name='k_EGCMsgUseItemResponse_MiniGameAlreadyStarted', index=3, number=3,
148 | serialized_options=None,
149 | type=None),
150 | _descriptor.EnumValueDescriptor(
151 | name='k_EGCMsgUseItemResponse_ItemUsed_ItemsGranted', index=4, number=4,
152 | serialized_options=None,
153 | type=None),
154 | _descriptor.EnumValueDescriptor(
155 | name='k_EGCMsgUseItemResponse_DropRateBonusAlreadyGranted', index=5, number=5,
156 | serialized_options=None,
157 | type=None),
158 | _descriptor.EnumValueDescriptor(
159 | name='k_EGCMsgUseItemResponse_NotInLowPriorityPool', index=6, number=6,
160 | serialized_options=None,
161 | type=None),
162 | _descriptor.EnumValueDescriptor(
163 | name='k_EGCMsgUseItemResponse_NotHighEnoughLevel', index=7, number=7,
164 | serialized_options=None,
165 | type=None),
166 | _descriptor.EnumValueDescriptor(
167 | name='k_EGCMsgUseItemResponse_EventNotActive', index=8, number=8,
168 | serialized_options=None,
169 | type=None),
170 | _descriptor.EnumValueDescriptor(
171 | name='k_EGCMsgUseItemResponse_ItemUsed_EventPointsGranted', index=9, number=9,
172 | serialized_options=None,
173 | type=None),
174 | _descriptor.EnumValueDescriptor(
175 | name='k_EGCMsgUseItemResponse_MissingRequirement', index=10, number=10,
176 | serialized_options=None,
177 | type=None),
178 | _descriptor.EnumValueDescriptor(
179 | name='k_EGCMsgUseItemResponse_EmoticonUnlock_NoNew', index=11, number=11,
180 | serialized_options=None,
181 | type=None),
182 | _descriptor.EnumValueDescriptor(
183 | name='k_EGCMsgUseItemResponse_EmoticonUnlock_Complete', index=12, number=12,
184 | serialized_options=None,
185 | type=None),
186 | _descriptor.EnumValueDescriptor(
187 | name='k_EGCMsgUseItemResponse_ItemUsed_Compendium', index=13, number=13,
188 | serialized_options=None,
189 | type=None),
190 | ],
191 | containing_type=None,
192 | serialized_options=None,
193 | serialized_start=595,
194 | serialized_end=1304,
195 | )
196 | _sym_db.RegisterEnumDescriptor(_EGCMSGUSEITEMRESPONSE)
197 |
198 | EGCMsgUseItemResponse = enum_type_wrapper.EnumTypeWrapper(_EGCMSGUSEITEMRESPONSE)
199 | k_EMsgGCGenericResult = 2579
200 | k_EGCMsgResponseOK = 0
201 | k_EGCMsgResponseDenied = 1
202 | k_EGCMsgResponseServerError = 2
203 | k_EGCMsgResponseTimeout = 3
204 | k_EGCMsgResponseInvalid = 4
205 | k_EGCMsgResponseNoMatch = 5
206 | k_EGCMsgResponseUnknownError = 6
207 | k_EGCMsgResponseNotLoggedOn = 7
208 | k_EGCMsgFailedToCreate = 8
209 | k_EPartnerRequestOK = 1
210 | k_EPartnerRequestBadAccount = 2
211 | k_EPartnerRequestNotLinked = 3
212 | k_EPartnerRequestUnsupportedPartnerType = 4
213 | k_EGCMsgUseItemResponse_ItemUsed = 0
214 | k_EGCMsgUseItemResponse_GiftNoOtherPlayers = 1
215 | k_EGCMsgUseItemResponse_ServerError = 2
216 | k_EGCMsgUseItemResponse_MiniGameAlreadyStarted = 3
217 | k_EGCMsgUseItemResponse_ItemUsed_ItemsGranted = 4
218 | k_EGCMsgUseItemResponse_DropRateBonusAlreadyGranted = 5
219 | k_EGCMsgUseItemResponse_NotInLowPriorityPool = 6
220 | k_EGCMsgUseItemResponse_NotHighEnoughLevel = 7
221 | k_EGCMsgUseItemResponse_EventNotActive = 8
222 | k_EGCMsgUseItemResponse_ItemUsed_EventPointsGranted = 9
223 | k_EGCMsgUseItemResponse_MissingRequirement = 10
224 | k_EGCMsgUseItemResponse_EmoticonUnlock_NoNew = 11
225 | k_EGCMsgUseItemResponse_EmoticonUnlock_Complete = 12
226 | k_EGCMsgUseItemResponse_ItemUsed_Compendium = 13
227 |
228 |
229 |
230 | _CMSGGENERICRESULT = _descriptor.Descriptor(
231 | name='CMsgGenericResult',
232 | full_name='dota.CMsgGenericResult',
233 | filename=None,
234 | file=DESCRIPTOR,
235 | containing_type=None,
236 | fields=[
237 | _descriptor.FieldDescriptor(
238 | name='eresult', full_name='dota.CMsgGenericResult.eresult', index=0,
239 | number=1, type=13, cpp_type=3, label=1,
240 | has_default_value=True, default_value=2,
241 | message_type=None, enum_type=None, containing_type=None,
242 | is_extension=False, extension_scope=None,
243 | serialized_options=None, file=DESCRIPTOR),
244 | _descriptor.FieldDescriptor(
245 | name='debug_message', full_name='dota.CMsgGenericResult.debug_message', index=1,
246 | number=2, type=9, cpp_type=9, label=1,
247 | has_default_value=False, default_value=_b("").decode('utf-8'),
248 | message_type=None, enum_type=None, containing_type=None,
249 | is_extension=False, extension_scope=None,
250 | serialized_options=None, file=DESCRIPTOR),
251 | ],
252 | extensions=[
253 | ],
254 | nested_types=[],
255 | enum_types=[
256 | ],
257 | serialized_options=None,
258 | is_extendable=False,
259 | syntax='proto2',
260 | extension_ranges=[],
261 | oneofs=[
262 | ],
263 | serialized_start=33,
264 | serialized_end=95,
265 | )
266 |
267 | DESCRIPTOR.message_types_by_name['CMsgGenericResult'] = _CMSGGENERICRESULT
268 | DESCRIPTOR.enum_types_by_name['EGCEconBaseMsg'] = _EGCECONBASEMSG
269 | DESCRIPTOR.enum_types_by_name['EGCMsgResponse'] = _EGCMSGRESPONSE
270 | DESCRIPTOR.enum_types_by_name['EGCPartnerRequestResponse'] = _EGCPARTNERREQUESTRESPONSE
271 | DESCRIPTOR.enum_types_by_name['EGCMsgUseItemResponse'] = _EGCMSGUSEITEMRESPONSE
272 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
273 |
274 | CMsgGenericResult = _reflection.GeneratedProtocolMessageType('CMsgGenericResult', (_message.Message,), dict(
275 | DESCRIPTOR = _CMSGGENERICRESULT,
276 | __module__ = 'econ_shared_enums_pb2'
277 | # @@protoc_insertion_point(class_scope:dota.CMsgGenericResult)
278 | ))
279 | _sym_db.RegisterMessage(CMsgGenericResult)
280 |
281 |
282 | DESCRIPTOR._options = None
283 | # @@protoc_insertion_point(module_scope)
284 |
--------------------------------------------------------------------------------
/dota2/protobufs/gcsystemmsgs_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: gcsystemmsgs.proto
4 |
5 | import sys
6 | _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
7 | from google.protobuf.internal import enum_type_wrapper
8 | from google.protobuf import descriptor as _descriptor
9 | from google.protobuf import message as _message
10 | from google.protobuf import reflection as _reflection
11 | from google.protobuf import symbol_database as _symbol_database
12 | # @@protoc_insertion_point(imports)
13 |
14 | _sym_db = _symbol_database.Default()
15 |
16 |
17 |
18 |
19 | DESCRIPTOR = _descriptor.FileDescriptor(
20 | name='gcsystemmsgs.proto',
21 | package='dota',
22 | syntax='proto2',
23 | serialized_options=_b('H\001\220\001\000'),
24 | serialized_pb=_b('\n\x12gcsystemmsgs.proto\x12\x04\x64ota*\xf0\x01\n\x06\x45SOMsg\x12\x13\n\x0fk_ESOMsg_Create\x10\x15\x12\x13\n\x0fk_ESOMsg_Update\x10\x16\x12\x14\n\x10k_ESOMsg_Destroy\x10\x17\x12\x1c\n\x18k_ESOMsg_CacheSubscribed\x10\x18\x12\x1e\n\x1ak_ESOMsg_CacheUnsubscribed\x10\x19\x12\x1b\n\x17k_ESOMsg_UpdateMultiple\x10\x1a\x12%\n!k_ESOMsg_CacheSubscriptionRefresh\x10\x1c\x12$\n k_ESOMsg_CacheSubscribedUpToDate\x10\x1d*\xc2\x03\n\x10\x45GCBaseClientMsg\x12\x18\n\x13k_EMsgGCPingRequest\x10\xb9\x17\x12\x19\n\x14k_EMsgGCPingResponse\x10\xba\x17\x12&\n!k_EMsgGCToClientPollConvarRequest\x10\xbb\x17\x12\'\n\"k_EMsgGCToClientPollConvarResponse\x10\xbc\x17\x12\"\n\x1dk_EMsgGCCompressedMsgToClient\x10\xbd\x17\x12)\n$k_EMsgGCCompressedMsgToClient_Legacy\x10\x8b\x04\x12#\n\x1ek_EMsgGCToClientRequestDropped\x10\xbe\x17\x12\x1a\n\x15k_EMsgGCClientWelcome\x10\xa4\x1f\x12\x1a\n\x15k_EMsgGCServerWelcome\x10\xa5\x1f\x12\x18\n\x13k_EMsgGCClientHello\x10\xa6\x1f\x12\x18\n\x13k_EMsgGCServerHello\x10\xa7\x1f\x12#\n\x1ek_EMsgGCClientConnectionStatus\x10\xa9\x1f\x12#\n\x1ek_EMsgGCServerConnectionStatus\x10\xaa\x1f\x42\x05H\x01\x90\x01\x00')
25 | )
26 |
27 | _ESOMSG = _descriptor.EnumDescriptor(
28 | name='ESOMsg',
29 | full_name='dota.ESOMsg',
30 | filename=None,
31 | file=DESCRIPTOR,
32 | values=[
33 | _descriptor.EnumValueDescriptor(
34 | name='k_ESOMsg_Create', index=0, number=21,
35 | serialized_options=None,
36 | type=None),
37 | _descriptor.EnumValueDescriptor(
38 | name='k_ESOMsg_Update', index=1, number=22,
39 | serialized_options=None,
40 | type=None),
41 | _descriptor.EnumValueDescriptor(
42 | name='k_ESOMsg_Destroy', index=2, number=23,
43 | serialized_options=None,
44 | type=None),
45 | _descriptor.EnumValueDescriptor(
46 | name='k_ESOMsg_CacheSubscribed', index=3, number=24,
47 | serialized_options=None,
48 | type=None),
49 | _descriptor.EnumValueDescriptor(
50 | name='k_ESOMsg_CacheUnsubscribed', index=4, number=25,
51 | serialized_options=None,
52 | type=None),
53 | _descriptor.EnumValueDescriptor(
54 | name='k_ESOMsg_UpdateMultiple', index=5, number=26,
55 | serialized_options=None,
56 | type=None),
57 | _descriptor.EnumValueDescriptor(
58 | name='k_ESOMsg_CacheSubscriptionRefresh', index=6, number=28,
59 | serialized_options=None,
60 | type=None),
61 | _descriptor.EnumValueDescriptor(
62 | name='k_ESOMsg_CacheSubscribedUpToDate', index=7, number=29,
63 | serialized_options=None,
64 | type=None),
65 | ],
66 | containing_type=None,
67 | serialized_options=None,
68 | serialized_start=29,
69 | serialized_end=269,
70 | )
71 | _sym_db.RegisterEnumDescriptor(_ESOMSG)
72 |
73 | ESOMsg = enum_type_wrapper.EnumTypeWrapper(_ESOMSG)
74 | _EGCBASECLIENTMSG = _descriptor.EnumDescriptor(
75 | name='EGCBaseClientMsg',
76 | full_name='dota.EGCBaseClientMsg',
77 | filename=None,
78 | file=DESCRIPTOR,
79 | values=[
80 | _descriptor.EnumValueDescriptor(
81 | name='k_EMsgGCPingRequest', index=0, number=3001,
82 | serialized_options=None,
83 | type=None),
84 | _descriptor.EnumValueDescriptor(
85 | name='k_EMsgGCPingResponse', index=1, number=3002,
86 | serialized_options=None,
87 | type=None),
88 | _descriptor.EnumValueDescriptor(
89 | name='k_EMsgGCToClientPollConvarRequest', index=2, number=3003,
90 | serialized_options=None,
91 | type=None),
92 | _descriptor.EnumValueDescriptor(
93 | name='k_EMsgGCToClientPollConvarResponse', index=3, number=3004,
94 | serialized_options=None,
95 | type=None),
96 | _descriptor.EnumValueDescriptor(
97 | name='k_EMsgGCCompressedMsgToClient', index=4, number=3005,
98 | serialized_options=None,
99 | type=None),
100 | _descriptor.EnumValueDescriptor(
101 | name='k_EMsgGCCompressedMsgToClient_Legacy', index=5, number=523,
102 | serialized_options=None,
103 | type=None),
104 | _descriptor.EnumValueDescriptor(
105 | name='k_EMsgGCToClientRequestDropped', index=6, number=3006,
106 | serialized_options=None,
107 | type=None),
108 | _descriptor.EnumValueDescriptor(
109 | name='k_EMsgGCClientWelcome', index=7, number=4004,
110 | serialized_options=None,
111 | type=None),
112 | _descriptor.EnumValueDescriptor(
113 | name='k_EMsgGCServerWelcome', index=8, number=4005,
114 | serialized_options=None,
115 | type=None),
116 | _descriptor.EnumValueDescriptor(
117 | name='k_EMsgGCClientHello', index=9, number=4006,
118 | serialized_options=None,
119 | type=None),
120 | _descriptor.EnumValueDescriptor(
121 | name='k_EMsgGCServerHello', index=10, number=4007,
122 | serialized_options=None,
123 | type=None),
124 | _descriptor.EnumValueDescriptor(
125 | name='k_EMsgGCClientConnectionStatus', index=11, number=4009,
126 | serialized_options=None,
127 | type=None),
128 | _descriptor.EnumValueDescriptor(
129 | name='k_EMsgGCServerConnectionStatus', index=12, number=4010,
130 | serialized_options=None,
131 | type=None),
132 | ],
133 | containing_type=None,
134 | serialized_options=None,
135 | serialized_start=272,
136 | serialized_end=722,
137 | )
138 | _sym_db.RegisterEnumDescriptor(_EGCBASECLIENTMSG)
139 |
140 | EGCBaseClientMsg = enum_type_wrapper.EnumTypeWrapper(_EGCBASECLIENTMSG)
141 | k_ESOMsg_Create = 21
142 | k_ESOMsg_Update = 22
143 | k_ESOMsg_Destroy = 23
144 | k_ESOMsg_CacheSubscribed = 24
145 | k_ESOMsg_CacheUnsubscribed = 25
146 | k_ESOMsg_UpdateMultiple = 26
147 | k_ESOMsg_CacheSubscriptionRefresh = 28
148 | k_ESOMsg_CacheSubscribedUpToDate = 29
149 | k_EMsgGCPingRequest = 3001
150 | k_EMsgGCPingResponse = 3002
151 | k_EMsgGCToClientPollConvarRequest = 3003
152 | k_EMsgGCToClientPollConvarResponse = 3004
153 | k_EMsgGCCompressedMsgToClient = 3005
154 | k_EMsgGCCompressedMsgToClient_Legacy = 523
155 | k_EMsgGCToClientRequestDropped = 3006
156 | k_EMsgGCClientWelcome = 4004
157 | k_EMsgGCServerWelcome = 4005
158 | k_EMsgGCClientHello = 4006
159 | k_EMsgGCServerHello = 4007
160 | k_EMsgGCClientConnectionStatus = 4009
161 | k_EMsgGCServerConnectionStatus = 4010
162 |
163 |
164 | DESCRIPTOR.enum_types_by_name['ESOMsg'] = _ESOMSG
165 | DESCRIPTOR.enum_types_by_name['EGCBaseClientMsg'] = _EGCBASECLIENTMSG
166 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
167 |
168 |
169 | DESCRIPTOR._options = None
170 | # @@protoc_insertion_point(module_scope)
171 |
--------------------------------------------------------------------------------
/dota2/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | def replay_url(match_id, cluster, replay_salt, app_id=570):
3 | """Form url for match replay
4 |
5 | :param match_id: match id
6 | :type match_id: :class:`int`
7 | :param cluster: cluster the match is saved on
8 | :type cluster: :class:`int`
9 | :param replay_salt: salt linked to the replay
10 | :type replay_salt: :class:`int`
11 | :param app_id: (optional) app_id for dota
12 | :type app_id: :class:`int`
13 | :return: url to download the replay of a specific match
14 | :rtype: :class:`str`
15 | """
16 | return 'http://replay{0}.valve.net/{1}/{2}_{3}.dem.bz2'.format(cluster, app_id, match_id, replay_salt)
17 |
18 |
19 | def replay_url_from_match(match, app_id=570):
20 | """Form url for match replay
21 |
22 | :param match: `CMsgDOTAMatch `_
23 | :type match: proto message
24 | :param app_id: (optional) app_id for dota
25 | :type app_id: :class:`int`
26 | :return: url to download the replay of a specific match, None if match has not all the information
27 | :rtype: :class:`str`, :class:`None`
28 | """
29 | if match.HasField('match_id') and match.HasField('cluster') and match.HasField('replay_salt'):
30 | return replay_url(match.match_id, match.cluster, match.replay_salt, app_id)
31 |
32 |
33 | def metadata_url(match_id, cluster, replay_salt, app_id=570):
34 | """Form url for match metadata file
35 |
36 | :param match_id: match id
37 | :type match_id: :class:`int`
38 | :param cluster: cluster the match is saved on
39 | :type cluster: :class:`int`
40 | :param replay_salt: salt linked to the replay
41 | :type replay_salt: :class:`int`
42 | :param app_id: (optional) app_id for dota
43 | :type app_id: :class:`int`
44 | :return: url to download the metadata of a specific match
45 | :rtype: :class:`str`
46 | """
47 | return 'http://replay{0}.valve.net/{1}/{2}_{3}.meta.bz2'.format(cluster, app_id, match_id, replay_salt)
48 |
49 |
50 | def metadata_url_from_match(match, app_id=570):
51 | """Form url for match metadata file
52 |
53 | :param match: `CMsgDOTAMatch `_
54 | :type match: proto message
55 | :param app_id: (optional) app_id for dota
56 | :type app_id: :class:`int`
57 | :return: url to download the metadata of a specific match, None if match has not all the information
58 | :rtype: :class:`str`, :class:`None`
59 | """
60 | if match.HasField('match_id') and match.HasField('cluster') and match.HasField('replay_salt'):
61 | return metadata_url(match.match_id, match.cluster, match.replay_salt, app_id)
62 |
--------------------------------------------------------------------------------
/gen_enum_from_protos.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import re
4 | from keyword import kwlist
5 | from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
6 | from dota2 import common_enums
7 |
8 | kwlist = set(kwlist + ['None'])
9 |
10 | _proto_modules = [
11 | 'base_gcmessages_pb2',
12 | 'dota_client_enums_pb2',
13 | 'dota_gcmessages_client_pb2',
14 | 'dota_gcmessages_client_fantasy_pb2',
15 | 'dota_gcmessages_client_match_management_pb2',
16 | 'dota_gcmessages_client_team_pb2',
17 | 'dota_gcmessages_client_tournament_pb2',
18 | 'dota_gcmessages_common_pb2',
19 | 'dota_gcmessages_common_match_management_pb2',
20 | 'dota_gcmessages_msgid_pb2',
21 | 'dota_shared_enums_pb2',
22 | 'gcsdk_gcmessages_pb2',
23 | 'gcsystemmsgs_pb2',
24 | 'steammessages_pb2',
25 | 'econ_gcmessages_pb2',
26 | 'econ_shared_enums_pb2',
27 | ]
28 |
29 | _proto_module = __import__("dota2.protobufs", globals(), locals(), _proto_modules, 0)
30 |
31 | classes = {}
32 |
33 | for name in _proto_modules:
34 |
35 | proto = getattr(_proto_module, name)
36 | gvars = globals()
37 |
38 | for class_name, value in proto.__dict__.items():
39 | if not isinstance(value, EnumTypeWrapper) or hasattr(common_enums, class_name):
40 | continue
41 |
42 | attrs_starting_with_number = False
43 | attrs = {}
44 |
45 | for ikey, ivalue in value.items():
46 | ikey = re.sub(r'^(k_)?(%s_)?' % class_name, '', ikey)
47 | attrs[ikey] = ivalue
48 |
49 | if ikey[0:1].isdigit() or ikey in kwlist:
50 | attrs_starting_with_number = True
51 |
52 | classes[class_name] = attrs, attrs_starting_with_number
53 |
54 | # Generate print out
55 |
56 | print("from enum import IntEnum")
57 |
58 | for class_name, (attrs, attrs_starting_with_number) in sorted(classes.items(), key=lambda x: x[0].lower()):
59 | if attrs_starting_with_number:
60 | print("\n%s = IntEnum(%r, {" % (class_name, class_name))
61 | for ikey, ivalue in attrs.items():
62 | print(" %r: %r," % (ikey, ivalue))
63 | print(" })")
64 | else:
65 | print("\nclass {class_name}(IntEnum):".format(class_name=class_name))
66 | for ikey, ivalue in attrs.items():
67 | print(" {} = {}".format(ikey, ivalue))
68 |
69 | print("\n__all__ = [")
70 |
71 | for class_name in sorted(classes, key=lambda x: x.lower()):
72 | print(" %r," % class_name)
73 |
74 | print(" ]")
75 |
--------------------------------------------------------------------------------
/protobuf_list.txt:
--------------------------------------------------------------------------------
1 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/steammessages.proto
2 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/gcsystemmsgs.proto
3 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/base_gcmessages.proto
4 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/gcsdk_gcmessages.proto
5 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_client_enums.proto
6 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client.proto
7 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_chat.proto
8 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_fantasy.proto
9 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_guild.proto
10 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_match_management.proto
11 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_team.proto
12 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_tournament.proto
13 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_client_watch.proto
14 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_common.proto
15 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_common_match_management.proto
16 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_gcmessages_msgid.proto
17 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_shared_enums.proto
18 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/econ_gcmessages.proto
19 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/econ_shared_enums.proto
20 | https://github.com/SteamDatabase/GameTracking-Dota2/raw/master/Protobufs/dota_match_metadata.proto
21 |
--------------------------------------------------------------------------------
/protobufs/base_gcmessages.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "steammessages.proto";
4 | import "gcsdk_gcmessages.proto";
5 |
6 | option optimize_for = SPEED;
7 | option py_generic_services = false;
8 |
9 | enum EGCBaseMsg {
10 | k_EMsgGCSystemMessage = 4001;
11 | k_EMsgGCReplicateConVars = 4002;
12 | k_EMsgGCConVarUpdated = 4003;
13 | k_EMsgGCInviteToParty = 4501;
14 | k_EMsgGCInvitationCreated = 4502;
15 | k_EMsgGCPartyInviteResponse = 4503;
16 | k_EMsgGCKickFromParty = 4504;
17 | k_EMsgGCLeaveParty = 4505;
18 | k_EMsgGCServerAvailable = 4506;
19 | k_EMsgGCClientConnectToServer = 4507;
20 | k_EMsgGCGameServerInfo = 4508;
21 | k_EMsgGCError = 4509;
22 | k_EMsgGCLANServerAvailable = 4511;
23 | k_EMsgGCInviteToLobby = 4512;
24 | k_EMsgGCLobbyInviteResponse = 4513;
25 | k_EMsgGCToClientPollFileRequest = 4514;
26 | k_EMsgGCToClientPollFileResponse = 4515;
27 | k_EMsgGCToGCPerformManualOp = 4516;
28 | k_EMsgGCToGCPerformManualOpCompleted = 4517;
29 | k_EMsgGCToGCReloadServerRegionSettings = 4518;
30 | k_EMsgGCAdditionalWelcomeMsgList = 4519;
31 | }
32 |
33 | enum EGCBaseProtoObjectTypes {
34 | k_EProtoObjectPartyInvite = 1001;
35 | k_EProtoObjectLobbyInvite = 1002;
36 | }
37 |
38 | enum ECustomGameInstallStatus {
39 | k_ECustomGameInstallStatus_Unknown = 0;
40 | k_ECustomGameInstallStatus_Ready = 1;
41 | k_ECustomGameInstallStatus_Busy = 2;
42 | k_ECustomGameInstallStatus_FailedGeneric = 101;
43 | k_ECustomGameInstallStatus_FailedInternalError = 102;
44 | k_ECustomGameInstallStatus_RequestedTimestampTooOld = 103;
45 | k_ECustomGameInstallStatus_RequestedTimestampTooNew = 104;
46 | k_ECustomGameInstallStatus_CRCMismatch = 105;
47 | k_ECustomGameInstallStatus_FailedSteam = 106;
48 | k_ECustomGameInstallStatus_FailedCanceled = 107;
49 | }
50 |
51 | message CGCStorePurchaseInit_LineItem {
52 | optional uint32 item_def_id = 1;
53 | optional uint32 quantity = 2;
54 | optional uint32 cost_in_local_currency = 3;
55 | optional uint32 purchase_type = 4;
56 | optional uint64 source_reference_id = 5;
57 | }
58 |
59 | message CMsgGCStorePurchaseInit {
60 | optional string country = 1;
61 | optional int32 language = 2;
62 | optional int32 currency = 3;
63 | repeated dota.CGCStorePurchaseInit_LineItem line_items = 4;
64 | }
65 |
66 | message CMsgGCStorePurchaseInitResponse {
67 | optional int32 result = 1;
68 | optional uint64 txn_id = 2;
69 | }
70 |
71 | message CMsgSystemBroadcast {
72 | optional string message = 1;
73 | }
74 |
75 | message CMsgClientPingData {
76 | repeated fixed32 relay_codes = 4 [packed = true];
77 | repeated uint32 relay_pings = 5 [packed = true];
78 | repeated uint32 region_codes = 8 [packed = true];
79 | repeated uint32 region_pings = 9 [packed = true];
80 | optional uint32 region_ping_failed_bitmask = 10;
81 | }
82 |
83 | message CMsgInviteToParty {
84 | optional fixed64 steam_id = 1;
85 | optional uint32 client_version = 2;
86 | optional uint32 team_id = 3;
87 | optional bool as_coach = 4;
88 | optional dota.CMsgClientPingData ping_data = 5;
89 | }
90 |
91 | message CMsgInviteToLobby {
92 | optional fixed64 steam_id = 1;
93 | optional uint32 client_version = 2;
94 | }
95 |
96 | message CMsgInvitationCreated {
97 | optional uint64 group_id = 1;
98 | optional fixed64 steam_id = 2;
99 | optional bool user_offline = 3;
100 | }
101 |
102 | message CMsgPartyInviteResponse {
103 | optional uint64 party_id = 1;
104 | optional bool accept = 2;
105 | optional uint32 client_version = 3;
106 | optional dota.CMsgClientPingData ping_data = 8;
107 | }
108 |
109 | message CMsgLobbyInviteResponse {
110 | optional fixed64 lobby_id = 1;
111 | optional bool accept = 2;
112 | optional uint32 client_version = 3;
113 | optional fixed64 custom_game_crc = 6;
114 | optional fixed32 custom_game_timestamp = 7;
115 | }
116 |
117 | message CMsgKickFromParty {
118 | optional fixed64 steam_id = 1;
119 | }
120 |
121 | message CMsgLeaveParty {
122 | }
123 |
124 | message CMsgCustomGameInstallStatus {
125 | optional dota.ECustomGameInstallStatus status = 1 [default = k_ECustomGameInstallStatus_Unknown];
126 | optional string message = 2;
127 | optional fixed32 latest_timestamp_from_steam = 3;
128 | }
129 |
130 | message CMsgServerAvailable {
131 | optional dota.CMsgCustomGameInstallStatus custom_game_install_status = 1;
132 | }
133 |
134 | message CMsgLANServerAvailable {
135 | optional fixed64 lobby_id = 1;
136 | }
137 |
138 | message CSOEconGameAccountClient {
139 | optional uint32 additional_backpack_slots = 1 [default = 0];
140 | optional bool trial_account = 2 [default = false];
141 | optional bool eligible_for_online_play = 3 [default = true];
142 | optional bool need_to_choose_most_helpful_friend = 4;
143 | optional bool in_coaches_list = 5;
144 | optional fixed32 trade_ban_expiration = 6;
145 | optional fixed32 duel_ban_expiration = 7;
146 | optional bool made_first_purchase = 9 [default = false];
147 | }
148 |
149 | message CSOItemCriteriaCondition {
150 | optional int32 op = 1;
151 | optional string field = 2;
152 | optional bool required = 3;
153 | optional float float_value = 4;
154 | optional string string_value = 5;
155 | }
156 |
157 | message CSOItemCriteria {
158 | optional uint32 item_level = 1;
159 | optional int32 item_quality = 2;
160 | optional bool item_level_set = 3;
161 | optional bool item_quality_set = 4;
162 | optional uint32 initial_inventory = 5;
163 | optional uint32 initial_quantity = 6;
164 | optional bool ignore_enabled_flag = 8;
165 | repeated dota.CSOItemCriteriaCondition conditions = 9;
166 | optional bool recent_only = 10;
167 | }
168 |
169 | message CSOItemRecipe {
170 | optional uint32 def_index = 1;
171 | optional string name = 2;
172 | optional string n_a = 3;
173 | optional string desc_inputs = 4;
174 | optional string desc_outputs = 5;
175 | optional string di_a = 6;
176 | optional string di_b = 7;
177 | optional string di_c = 8;
178 | optional string do_a = 9;
179 | optional string do_b = 10;
180 | optional string do_c = 11;
181 | optional bool requires_all_same_class = 12;
182 | optional bool requires_all_same_slot = 13;
183 | optional int32 class_usage_for_output = 14;
184 | optional int32 slot_usage_for_output = 15;
185 | optional int32 set_for_output = 16;
186 | repeated dota.CSOItemCriteria input_items_criteria = 20;
187 | repeated dota.CSOItemCriteria output_items_criteria = 21;
188 | repeated uint32 input_item_dupe_counts = 22;
189 | }
190 |
191 | message CMsgApplyStrangePart {
192 | optional uint64 strange_part_item_id = 1;
193 | optional uint64 item_item_id = 2;
194 | }
195 |
196 | message CMsgApplyPennantUpgrade {
197 | optional uint64 upgrade_item_id = 1;
198 | optional uint64 pennant_item_id = 2;
199 | }
200 |
201 | message CMsgApplyEggEssence {
202 | optional uint64 essence_item_id = 1;
203 | optional uint64 egg_item_id = 2;
204 | }
205 |
206 | message CSOEconItemAttribute {
207 | optional uint32 def_index = 1;
208 | optional uint32 value = 2;
209 | optional bytes value_bytes = 3;
210 | }
211 |
212 | message CSOEconItemEquipped {
213 | optional uint32 new_class = 1;
214 | optional uint32 new_slot = 2;
215 | }
216 |
217 | message CSOEconItem {
218 | optional uint64 id = 1;
219 | optional uint32 account_id = 2;
220 | optional uint32 inventory = 3;
221 | optional uint32 def_index = 4;
222 | optional uint32 quantity = 5 [default = 1];
223 | optional uint32 level = 6 [default = 1];
224 | optional uint32 quality = 7 [default = 4];
225 | optional uint32 flags = 8 [default = 0];
226 | optional uint32 origin = 9 [default = 0];
227 | repeated dota.CSOEconItemAttribute attribute = 12;
228 | optional dota.CSOEconItem interior_item = 13;
229 | optional uint32 style = 15 [default = 0];
230 | optional uint64 original_id = 16 [default = 0];
231 | repeated dota.CSOEconItemEquipped equipped_state = 18;
232 | }
233 |
234 | message CMsgSortItems {
235 | optional uint32 sort_type = 1;
236 | }
237 |
238 | message CSOEconClaimCode {
239 | optional uint32 account_id = 1;
240 | optional uint32 code_type = 2;
241 | optional uint32 time_acquired = 3;
242 | optional string code = 4;
243 | }
244 |
245 | message CMsgUpdateItemSchema {
246 | optional bytes items_game = 1;
247 | optional fixed32 item_schema_version = 2;
248 | optional string items_game_url = 3;
249 | }
250 |
251 | message CMsgGCError {
252 | optional string error_text = 1;
253 | }
254 |
255 | message CMsgRequestInventoryRefresh {
256 | }
257 |
258 | message CMsgConVarValue {
259 | optional string name = 1;
260 | optional string value = 2;
261 | }
262 |
263 | message CMsgReplicateConVars {
264 | repeated dota.CMsgConVarValue convars = 1;
265 | }
266 |
267 | message CMsgItemAcknowledged {
268 | optional uint32 account_id = 1;
269 | optional uint32 inventory = 2;
270 | optional uint32 def_index = 3;
271 | optional uint32 quality = 4;
272 | optional uint32 rarity = 5;
273 | optional uint32 origin = 6;
274 | }
275 |
276 | message CMsgSetItemPositions {
277 | message ItemPosition {
278 | optional uint64 item_id = 1;
279 | optional uint32 position = 2;
280 | }
281 |
282 | repeated dota.CMsgSetItemPositions.ItemPosition item_positions = 1;
283 | }
284 |
285 | message CMsgGCNameItemNotification {
286 | optional fixed64 player_steamid = 1;
287 | optional uint32 item_def_index = 2;
288 | optional string item_name_custom = 3;
289 | }
290 |
291 | message CMsgGCClientDisplayNotification {
292 | optional string notification_title_localization_key = 1;
293 | optional string notification_body_localization_key = 2;
294 | repeated string body_substring_keys = 3;
295 | repeated string body_substring_values = 4;
296 | }
297 |
298 | message CMsgGCShowItemsPickedUp {
299 | optional fixed64 player_steamid = 1;
300 | }
301 |
302 | message CMsgGCIncrementKillCountResponse {
303 | optional uint32 killer_account_id = 1 [(key_field) = true];
304 | optional uint32 num_kills = 2;
305 | optional uint32 item_def = 3;
306 | optional uint32 level_type = 4;
307 | }
308 |
309 | message CSOEconItemDropRateBonus {
310 | optional uint32 account_id = 1 [(key_field) = true];
311 | optional fixed32 expiration_date = 2;
312 | optional float bonus = 3 [(key_field) = true];
313 | optional uint32 bonus_count = 4;
314 | optional uint64 item_id = 5;
315 | optional uint32 def_index = 6;
316 | optional uint32 seconds_left = 7;
317 | optional uint32 booster_type = 8 [(key_field) = true];
318 | }
319 |
320 | message CSOEconItemLeagueViewPass {
321 | optional uint32 account_id = 1 [(key_field) = true];
322 | optional uint32 league_id = 2 [(key_field) = true];
323 | optional uint32 itemindex = 4;
324 | optional uint32 grant_reason = 5;
325 | }
326 |
327 | message CSOEconItemEventTicket {
328 | optional uint32 account_id = 1;
329 | optional uint32 event_id = 2;
330 | optional uint64 item_id = 3;
331 | }
332 |
333 | message CSOEconItemTournamentPassport {
334 | optional uint32 account_id = 1;
335 | optional uint32 league_id = 2;
336 | optional uint64 item_id = 3;
337 | optional uint32 original_purchaser_id = 4;
338 | optional uint32 passports_bought = 5;
339 | optional uint32 version = 6;
340 | optional uint32 def_index = 7;
341 | optional uint32 reward_flags = 8;
342 | }
343 |
344 | message CMsgGCStorePurchaseCancel {
345 | optional uint64 txn_id = 1;
346 | }
347 |
348 | message CMsgGCStorePurchaseCancelResponse {
349 | optional uint32 result = 1;
350 | }
351 |
352 | message CMsgGCStorePurchaseFinalize {
353 | optional uint64 txn_id = 1;
354 | }
355 |
356 | message CMsgGCStorePurchaseFinalizeResponse {
357 | optional uint32 result = 1;
358 | repeated uint64 item_ids = 2;
359 | }
360 |
361 | message CMsgGCToGCBannedWordListUpdated {
362 | optional uint32 group_id = 1;
363 | }
364 |
365 | message CMsgGCToGCDirtySDOCache {
366 | optional uint32 sdo_type = 1;
367 | optional uint64 key_uint64 = 2;
368 | }
369 |
370 | message CMsgGCToGCDirtyMultipleSDOCache {
371 | optional uint32 sdo_type = 1;
372 | repeated uint64 key_uint64 = 2;
373 | }
374 |
375 | message CMsgGCToGCApplyLocalizationDiff {
376 | optional uint32 language = 1;
377 | optional string packed_diff = 2;
378 | }
379 |
380 | message CMsgGCToGCApplyLocalizationDiffResponse {
381 | optional bool success = 1;
382 | }
383 |
384 | message CMsgGCCollectItem {
385 | optional uint64 collection_item_id = 1;
386 | optional uint64 subject_item_id = 2;
387 | }
388 |
389 | message CMsgSDONoMemcached {
390 | }
391 |
392 | message CMsgGCToGCUpdateSQLKeyValue {
393 | optional string key_name = 1;
394 | }
395 |
396 | message CMsgGCServerVersionUpdated {
397 | optional uint32 server_version = 1;
398 | }
399 |
400 | message CMsgGCClientVersionUpdated {
401 | optional uint32 client_version = 1;
402 | }
403 |
404 | message CMsgGCToGCWebAPIAccountChanged {
405 | }
406 |
407 | message CMsgRecipeComponent {
408 | optional uint64 subject_item_id = 1;
409 | optional uint64 attribute_index = 2;
410 | }
411 |
412 | message CMsgFulfillDynamicRecipeComponent {
413 | optional uint64 tool_item_id = 1;
414 | repeated dota.CMsgRecipeComponent consumption_components = 2;
415 | }
416 |
417 | message CMsgGCClientMarketDataRequest {
418 | optional uint32 user_currency = 1;
419 | }
420 |
421 | message CMsgGCClientMarketDataEntry {
422 | optional uint32 item_def_index = 1;
423 | optional uint32 item_quality = 2;
424 | optional uint32 item_sell_listings = 3;
425 | optional uint32 price_in_local_currency = 4;
426 | }
427 |
428 | message CMsgGCClientMarketData {
429 | repeated dota.CMsgGCClientMarketDataEntry entries = 1;
430 | }
431 |
432 | message CMsgExtractGems {
433 | optional uint64 tool_item_id = 1;
434 | optional uint64 item_item_id = 2;
435 | optional uint32 item_socket_id = 3 [default = 65535];
436 | }
437 |
438 | message CMsgExtractGemsResponse {
439 | enum EExtractGems {
440 | k_ExtractGems_Succeeded = 0;
441 | k_ExtractGems_Failed_ToolIsInvalid = 1;
442 | k_ExtractGems_Failed_ItemIsInvalid = 2;
443 | k_ExtractGems_Failed_ToolCannotRemoveGem = 3;
444 | k_ExtractGems_Failed_FailedToRemoveGem = 4;
445 | }
446 |
447 | optional uint64 item_id = 1;
448 | optional dota.CMsgExtractGemsResponse.EExtractGems response = 2 [default = k_ExtractGems_Succeeded];
449 | }
450 |
451 | message CMsgAddSocket {
452 | optional uint64 tool_item_id = 1;
453 | optional uint64 item_item_id = 2;
454 | optional bool unusual = 3;
455 | }
456 |
457 | message CMsgAddSocketResponse {
458 | enum EAddSocket {
459 | k_AddSocket_Succeeded = 0;
460 | k_AddSocket_Failed_ToolIsInvalid = 1;
461 | k_AddSocket_Failed_ItemCannotBeSocketed = 2;
462 | k_AddSocket_Failed_FailedToAddSocket = 3;
463 | }
464 |
465 | optional uint64 item_id = 1;
466 | repeated uint32 updated_socket_index = 2;
467 | optional dota.CMsgAddSocketResponse.EAddSocket response = 3 [default = k_AddSocket_Succeeded];
468 | }
469 |
470 | message CMsgAddItemToSocketData {
471 | optional uint64 gem_item_id = 1;
472 | optional uint32 socket_index = 2;
473 | }
474 |
475 | message CMsgAddItemToSocket {
476 | optional uint64 item_item_id = 1;
477 | repeated dota.CMsgAddItemToSocketData gems_to_socket = 2;
478 | }
479 |
480 | message CMsgAddItemToSocketResponse {
481 | enum EAddGem {
482 | k_AddGem_Succeeded = 0;
483 | k_AddGem_Failed_GemIsInvalid = 1;
484 | k_AddGem_Failed_ItemIsInvalid = 2;
485 | k_AddGem_Failed_FailedToAddGem = 3;
486 | k_AddGem_Failed_InvalidGemTypeForSocket = 4;
487 | k_AddGem_Failed_InvalidGemTypeForHero = 5;
488 | k_AddGem_Failed_InvalidGemTypeForSlot = 6;
489 | k_AddGem_Failed_SocketContainsUnremovableGem = 7;
490 | }
491 |
492 | optional uint64 item_item_id = 1;
493 | repeated uint32 updated_socket_index = 2;
494 | optional dota.CMsgAddItemToSocketResponse.EAddGem response = 3 [default = k_AddGem_Succeeded];
495 | }
496 |
497 | message CMsgResetStrangeGemCount {
498 | optional uint64 item_item_id = 1;
499 | optional uint32 socket_index = 2;
500 | }
501 |
502 | message CMsgResetStrangeGemCountResponse {
503 | enum EResetGem {
504 | k_ResetGem_Succeeded = 0;
505 | k_ResetGem_Failed_FailedToResetGem = 1;
506 | k_ResetGem_Failed_ItemIsInvalid = 2;
507 | k_ResetGem_Failed_InvalidSocketId = 3;
508 | k_ResetGem_Failed_SocketCannotBeReset = 4;
509 | }
510 |
511 | optional dota.CMsgResetStrangeGemCountResponse.EResetGem response = 1 [default = k_ResetGem_Succeeded];
512 | }
513 |
514 | message CMsgGCToClientPollFileRequest {
515 | optional string file_name = 1;
516 | optional uint32 client_version = 2;
517 | optional uint32 poll_id = 3;
518 | }
519 |
520 | message CMsgGCToClientPollFileResponse {
521 | optional uint32 poll_id = 1;
522 | optional uint32 file_size = 2;
523 | }
524 |
525 | message CMsgGCToGCPerformManualOp {
526 | optional uint64 op_id = 1;
527 | optional uint32 group_code = 2;
528 | }
529 |
530 | message CMsgGCToGCPerformManualOpCompleted {
531 | optional bool success = 1;
532 | optional uint32 source_gc = 2;
533 | }
534 |
535 | message CMsgGCToGCReloadServerRegionSettings {
536 | }
537 |
538 | message CMsgGCAdditionalWelcomeMsgList {
539 | repeated dota.CExtraMsgBlock welcome_messages = 1;
540 | }
541 |
--------------------------------------------------------------------------------
/protobufs/dota_client_enums.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | option optimize_for = SPEED;
4 | option py_generic_services = false;
5 |
6 | enum ETournamentTemplate {
7 | k_ETournamentTemplate_None = 0;
8 | k_ETournamentTemplate_AutomatedWin3 = 1;
9 | }
10 |
11 | enum ETournamentGameState {
12 | k_ETournamentGameState_Unknown = 0;
13 | k_ETournamentGameState_Canceled = 1;
14 | k_ETournamentGameState_Scheduled = 2;
15 | k_ETournamentGameState_Active = 3;
16 | k_ETournamentGameState_RadVictory = 20;
17 | k_ETournamentGameState_DireVictory = 21;
18 | k_ETournamentGameState_RadVictoryByForfeit = 22;
19 | k_ETournamentGameState_DireVictoryByForfeit = 23;
20 | k_ETournamentGameState_ServerFailure = 40;
21 | k_ETournamentGameState_NotNeeded = 41;
22 | }
23 |
24 | enum ETournamentTeamState {
25 | k_ETournamentTeamState_Unknown = 0;
26 | k_ETournamentTeamState_Node1 = 1;
27 | k_ETournamentTeamState_NodeMax = 1024;
28 | k_ETournamentTeamState_Eliminated = 14003;
29 | k_ETournamentTeamState_Forfeited = 14004;
30 | k_ETournamentTeamState_Finished1st = 15001;
31 | k_ETournamentTeamState_Finished2nd = 15002;
32 | k_ETournamentTeamState_Finished3rd = 15003;
33 | k_ETournamentTeamState_Finished4th = 15004;
34 | k_ETournamentTeamState_Finished5th = 15005;
35 | k_ETournamentTeamState_Finished6th = 15006;
36 | k_ETournamentTeamState_Finished7th = 15007;
37 | k_ETournamentTeamState_Finished8th = 15008;
38 | k_ETournamentTeamState_Finished9th = 15009;
39 | k_ETournamentTeamState_Finished10th = 15010;
40 | k_ETournamentTeamState_Finished11th = 15011;
41 | k_ETournamentTeamState_Finished12th = 15012;
42 | k_ETournamentTeamState_Finished13th = 15013;
43 | k_ETournamentTeamState_Finished14th = 15014;
44 | k_ETournamentTeamState_Finished15th = 15015;
45 | k_ETournamentTeamState_Finished16th = 15016;
46 | }
47 |
48 | enum ETournamentState {
49 | k_ETournamentState_Unknown = 0;
50 | k_ETournamentState_CanceledByAdmin = 1;
51 | k_ETournamentState_Completed = 2;
52 | k_ETournamentState_Merged = 3;
53 | k_ETournamentState_ServerFailure = 4;
54 | k_ETournamentState_TeamAbandoned = 5;
55 | k_ETournamentState_TeamTimeoutForfeit = 6;
56 | k_ETournamentState_TeamTimeoutRefund = 7;
57 | k_ETournamentState_ServerFailureGrantedVictory = 8;
58 | k_ETournamentState_TeamTimeoutGrantedVictory = 9;
59 | k_ETournamentState_InProgress = 100;
60 | k_ETournamentState_WaitingToMerge = 101;
61 | }
62 |
63 | enum ETournamentNodeState {
64 | k_ETournamentNodeState_Unknown = 0;
65 | k_ETournamentNodeState_Canceled = 1;
66 | k_ETournamentNodeState_TeamsNotYetAssigned = 2;
67 | k_ETournamentNodeState_InBetweenGames = 3;
68 | k_ETournamentNodeState_GameInProgress = 4;
69 | k_ETournamentNodeState_A_Won = 5;
70 | k_ETournamentNodeState_B_Won = 6;
71 | k_ETournamentNodeState_A_WonByForfeit = 7;
72 | k_ETournamentNodeState_B_WonByForfeit = 8;
73 | k_ETournamentNodeState_A_Bye = 9;
74 | k_ETournamentNodeState_A_Abandoned = 10;
75 | k_ETournamentNodeState_ServerFailure = 11;
76 | k_ETournamentNodeState_A_TimeoutForfeit = 12;
77 | k_ETournamentNodeState_A_TimeoutRefund = 13;
78 | }
79 |
80 | enum EDOTAGroupMergeResult {
81 | k_EDOTAGroupMergeResult_OK = 0;
82 | k_EDOTAGroupMergeResult_FAILED_GENERIC = 1;
83 | k_EDOTAGroupMergeResult_NOT_LEADER = 2;
84 | k_EDOTAGroupMergeResult_TOO_MANY_PLAYERS = 3;
85 | k_EDOTAGroupMergeResult_TOO_MANY_COACHES = 4;
86 | k_EDOTAGroupMergeResult_ENGINE_MISMATCH = 5;
87 | k_EDOTAGroupMergeResult_NO_SUCH_GROUP = 6;
88 | k_EDOTAGroupMergeResult_OTHER_GROUP_NOT_OPEN = 7;
89 | k_EDOTAGroupMergeResult_ALREADY_INVITED = 8;
90 | k_EDOTAGroupMergeResult_NOT_INVITED = 9;
91 | }
92 |
93 | enum EPartyBeaconType {
94 | k_EPartyBeaconType_Available = 0;
95 | k_EPartyBeaconType_Joinable = 1;
96 | }
97 |
--------------------------------------------------------------------------------
/protobufs/dota_gcmessages_client_chat.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "dota_shared_enums.proto";
4 |
5 | option optimize_for = SPEED;
6 | option py_generic_services = false;
7 |
8 | message CMsgClientToGCPrivateChatInvite {
9 | optional string private_chat_channel_name = 1;
10 | optional uint32 invited_account_id = 2;
11 | }
12 |
13 | message CMsgClientToGCPrivateChatKick {
14 | optional string private_chat_channel_name = 1;
15 | optional uint32 kick_account_id = 2;
16 | }
17 |
18 | message CMsgClientToGCPrivateChatPromote {
19 | optional string private_chat_channel_name = 1;
20 | optional uint32 promote_account_id = 2;
21 | }
22 |
23 | message CMsgClientToGCPrivateChatDemote {
24 | optional string private_chat_channel_name = 1;
25 | optional uint32 demote_account_id = 2;
26 | }
27 |
28 | message CMsgGCToClientPrivateChatResponse {
29 | enum Result {
30 | SUCCESS = 0;
31 | FAILURE_CREATION_LOCK = 1;
32 | FAILURE_SQL_TRANSACTION = 2;
33 | FAILURE_SDO_LOAD = 3;
34 | FAILURE_NO_PERMISSION = 4;
35 | FAILURE_ALREADY_MEMBER = 5;
36 | FAILURE_NOT_A_MEMBER = 7;
37 | FAILURE_NO_REMAINING_ADMINS = 8;
38 | FAILURE_NO_ROOM = 9;
39 | FAILURE_CREATION_RATE_LIMITED = 10;
40 | FAILURE_UNKNOWN_CHANNEL_NAME = 11;
41 | FAILURE_UNKNOWN_USER = 12;
42 | FAILURE_UNKNOWN_ERROR = 13;
43 | FAILURE_CANNOT_KICK_ADMIN = 14;
44 | FAILURE_ALREADY_ADMIN = 15;
45 | }
46 |
47 | optional string private_chat_channel_name = 1;
48 | optional dota.CMsgGCToClientPrivateChatResponse.Result result = 2 [default = SUCCESS];
49 | optional string username = 3;
50 | }
51 |
52 | message CMsgClientToGCPrivateChatInfoRequest {
53 | optional string private_chat_channel_name = 1;
54 | }
55 |
56 | message CMsgGCToClientPrivateChatInfoResponse {
57 | message Member {
58 | optional uint32 account_id = 1;
59 | optional string name = 2;
60 | optional uint32 status = 3;
61 | }
62 |
63 | optional string private_chat_channel_name = 1;
64 | repeated dota.CMsgGCToClientPrivateChatInfoResponse.Member members = 2;
65 | optional uint32 creator = 3;
66 | optional uint32 creation_date = 4;
67 | }
68 |
69 | message CMsgDOTAJoinChatChannel {
70 | optional string channel_name = 2;
71 | optional dota.DOTAChatChannelType_t channel_type = 4 [default = DOTAChannelType_Regional];
72 | optional bool silent_rejection = 5;
73 | }
74 |
75 | message CMsgDOTALeaveChatChannel {
76 | optional uint64 channel_id = 1;
77 | }
78 |
79 | message CMsgGCChatReportPublicSpam {
80 | optional uint64 channel_id = 1;
81 | optional uint32 channel_user_id = 2;
82 | }
83 |
84 | message CMsgDOTAClientIgnoredUser {
85 | optional uint32 ignored_account_id = 1;
86 | }
87 |
88 | message CMsgDOTAChatModeratorBan {
89 | optional uint64 channel_id = 1;
90 | optional uint32 account_id = 2;
91 | optional uint32 duration = 3;
92 | }
93 |
94 | message CMsgDOTAChatMessage {
95 | message DiceRoll {
96 | optional int32 roll_min = 1;
97 | optional int32 roll_max = 2;
98 | optional int32 result = 3;
99 | }
100 |
101 | message TriviaAnswered {
102 | optional uint32 question_id = 1;
103 | optional uint32 answer_index = 2;
104 | optional uint32 party_questions_correct = 3;
105 | optional uint32 party_questions_viewed = 4;
106 | optional uint32 party_trivia_points = 5;
107 | }
108 |
109 | optional uint32 account_id = 1;
110 | optional uint64 channel_id = 2;
111 | optional string persona_name = 3;
112 | optional string text = 4;
113 | optional uint32 timestamp = 5;
114 | optional uint32 suggest_invite_account_id = 6;
115 | optional string suggest_invite_name = 7;
116 | optional uint32 fantasy_draft_owner_account_id = 8;
117 | optional uint32 fantasy_draft_player_account_id = 9;
118 | optional uint32 event_id = 10;
119 | optional bool suggest_invite_to_lobby = 11;
120 | optional uint32 event_points = 12;
121 | optional bool coin_flip = 13;
122 | optional int32 player_id = 14 [default = -1];
123 | optional uint32 share_profile_account_id = 15;
124 | optional uint32 channel_user_id = 16;
125 | optional dota.CMsgDOTAChatMessage.DiceRoll dice_roll = 17;
126 | optional uint64 share_party_id = 18;
127 | optional uint64 share_lobby_id = 19;
128 | optional uint64 share_lobby_custom_game_id = 20;
129 | optional string share_lobby_passkey = 21;
130 | optional uint32 private_chat_channel_id = 22;
131 | optional uint32 status = 23;
132 | optional bool legacy_battle_cup_victory = 24;
133 | optional uint32 battle_cup_streak = 29;
134 | optional uint32 badge_level = 25;
135 | optional uint32 suggest_pick_hero_id = 26;
136 | optional string suggest_pick_hero_role = 27;
137 | optional uint32 suggest_ban_hero_id = 30;
138 | optional dota.CMsgDOTAChatMessage.TriviaAnswered trivia_answer = 32;
139 | optional uint32 requested_ability_id = 33;
140 | optional uint32 chat_flags = 34;
141 | optional bool started_finding_match = 35;
142 | optional bool ctrl_is_down = 36;
143 | }
144 |
145 | message CMsgDOTAChatMember {
146 | optional fixed64 steam_id = 1;
147 | optional string persona_name = 2;
148 | optional uint32 channel_user_id = 3;
149 | optional uint32 status = 4;
150 | }
151 |
152 | message CMsgDOTAJoinChatChannelResponse {
153 | enum Result {
154 | JOIN_SUCCESS = 0;
155 | INVALID_CHANNEL_TYPE = 1;
156 | ACCOUNT_NOT_FOUND = 2;
157 | ACH_FAILED = 3;
158 | USER_IN_TOO_MANY_CHANNELS = 4;
159 | RATE_LIMIT_EXCEEDED = 5;
160 | CHANNEL_FULL = 6;
161 | CHANNEL_FULL_OVERFLOWED = 7;
162 | FAILED_TO_ADD_USER = 8;
163 | CHANNEL_TYPE_DISABLED = 9;
164 | PRIVATE_CHAT_CREATE_FAILED = 10;
165 | PRIVATE_CHAT_NO_PERMISSION = 11;
166 | PRIVATE_CHAT_CREATE_LOCK_FAILED = 12;
167 | PRIVATE_CHAT_KICKED = 13;
168 | USER_NOT_ALLOWED = 14;
169 | ENSURE_SPECIAL_PRIVILEGES_FAILED = 15;
170 | NEW_PLAYER_USER_NOT_ELIGIBLE = 16;
171 | SILENT_ERROR = 17;
172 | NEW_PLAYER_USER_BANNED = 18;
173 | }
174 |
175 | optional uint32 response = 1;
176 | optional string channel_name = 2;
177 | optional fixed64 channel_id = 3;
178 | optional uint32 max_members = 4;
179 | repeated dota.CMsgDOTAChatMember members = 5;
180 | optional dota.DOTAChatChannelType_t channel_type = 6 [default = DOTAChannelType_Regional];
181 | optional dota.CMsgDOTAJoinChatChannelResponse.Result result = 7 [default = JOIN_SUCCESS];
182 | optional bool gc_initiated_join = 8;
183 | optional uint32 channel_user_id = 9;
184 | optional string welcome_message = 10;
185 | optional dota.EChatSpecialPrivileges special_privileges = 11 [default = k_EChatSpecialPrivileges_None];
186 | }
187 |
188 | message CMsgDOTAChatChannelFullUpdate {
189 | optional fixed64 channel_id = 1;
190 | repeated dota.CMsgDOTAChatMember members = 2;
191 | }
192 |
193 | message CMsgDOTAOtherJoinedChatChannel {
194 | optional fixed64 channel_id = 1;
195 | optional string persona_name = 2;
196 | optional fixed64 steam_id = 3;
197 | optional uint32 channel_user_id = 4;
198 | optional uint32 status = 5;
199 | }
200 |
201 | message CMsgDOTAOtherLeftChatChannel {
202 | optional fixed64 channel_id = 1;
203 | optional fixed64 steam_id = 2;
204 | optional uint32 channel_user_id = 3;
205 | }
206 |
207 | message CMsgDOTAChatChannelMemberUpdate {
208 | message JoinedMember {
209 | optional fixed64 steam_id = 1;
210 | optional string persona_name = 2;
211 | optional uint32 channel_user_id = 3;
212 | optional uint32 status = 4;
213 | }
214 |
215 | optional fixed64 channel_id = 1;
216 | repeated fixed64 left_steam_ids = 2;
217 | repeated dota.CMsgDOTAChatChannelMemberUpdate.JoinedMember joined_members = 3;
218 | }
219 |
220 | message CMsgDOTARequestChatChannelList {
221 | }
222 |
223 | message CMsgDOTARequestChatChannelListResponse {
224 | message ChatChannel {
225 | optional string channel_name = 1;
226 | optional uint32 num_members = 2;
227 | optional dota.DOTAChatChannelType_t channel_type = 3 [default = DOTAChannelType_Regional];
228 | }
229 |
230 | repeated dota.CMsgDOTARequestChatChannelListResponse.ChatChannel channels = 1;
231 | }
232 |
233 | message CMsgDOTAChatGetUserList {
234 | optional fixed64 channel_id = 1;
235 | }
236 |
237 | message CMsgDOTAChatGetUserListResponse {
238 | message Member {
239 | optional fixed64 steam_id = 1;
240 | optional string persona_name = 2;
241 | optional uint32 channel_user_id = 3;
242 | optional uint32 status = 4;
243 | }
244 |
245 | optional fixed64 channel_id = 1;
246 | repeated dota.CMsgDOTAChatGetUserListResponse.Member members = 2;
247 | }
248 |
249 | message CMsgDOTAChatGetMemberCount {
250 | optional string channel_name = 1;
251 | optional dota.DOTAChatChannelType_t channel_type = 2 [default = DOTAChannelType_Regional];
252 | }
253 |
254 | message CMsgDOTAChatGetMemberCountResponse {
255 | optional string channel_name = 1;
256 | optional dota.DOTAChatChannelType_t channel_type = 2 [default = DOTAChannelType_Regional];
257 | optional uint32 member_count = 3;
258 | }
259 |
260 | message CMsgDOTAChatRegionsEnabled {
261 | message Region {
262 | optional float min_latitude = 1;
263 | optional float max_latitude = 2;
264 | optional float min_longitude = 3;
265 | optional float max_longitude = 4;
266 | }
267 |
268 | optional bool enable_all_regions = 1;
269 | repeated dota.CMsgDOTAChatRegionsEnabled.Region enabled_regions = 2;
270 | }
271 |
--------------------------------------------------------------------------------
/protobufs/dota_gcmessages_client_team.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "dota_shared_enums.proto";
4 |
5 | option optimize_for = SPEED;
6 | option py_generic_services = false;
7 |
8 | enum ETeamInviteResult {
9 | TEAM_INVITE_SUCCESS = 0;
10 | TEAM_INVITE_FAILURE_INVITE_REJECTED = 1;
11 | TEAM_INVITE_FAILURE_INVITE_TIMEOUT = 2;
12 | TEAM_INVITE_ERROR_TEAM_AT_MEMBER_LIMIT = 3;
13 | TEAM_INVITE_ERROR_TEAM_LOCKED = 4;
14 | TEAM_INVITE_ERROR_INVITEE_NOT_AVAILABLE = 5;
15 | TEAM_INVITE_ERROR_INVITEE_BUSY = 6;
16 | TEAM_INVITE_ERROR_INVITEE_ALREADY_MEMBER = 7;
17 | TEAM_INVITE_ERROR_INVITEE_AT_TEAM_LIMIT = 8;
18 | TEAM_INVITE_ERROR_INVITEE_INSUFFICIENT_PLAY_TIME = 9;
19 | TEAM_INVITE_ERROR_INVITER_INVALID_ACCOUNT_TYPE = 10;
20 | TEAM_INVITE_ERROR_INVITER_NOT_ADMIN = 11;
21 | TEAM_INVITE_ERROR_INCORRECT_USER_RESPONDED = 12;
22 | TEAM_INVITE_ERROR_UNSPECIFIED = 13;
23 | }
24 |
25 | message CMsgDOTATeamMemberSDO {
26 | optional uint32 account_id = 1;
27 | repeated uint32 team_ids = 2;
28 | optional uint32 profile_team_id = 3;
29 | }
30 |
31 | message CMsgDOTATeamAdminSDO {
32 | optional uint32 account_id = 1;
33 | repeated uint32 team_ids = 2;
34 | }
35 |
36 | message CMsgDOTATeamMember {
37 | optional uint32 account_id = 1;
38 | optional uint32 time_joined = 4;
39 | }
40 |
41 | message CMsgDOTATeam {
42 | repeated dota.CMsgDOTATeamMember members = 1;
43 | optional uint32 team_id = 2;
44 | optional string name = 3;
45 | optional string tag = 4;
46 | optional uint32 admin_id = 5;
47 | optional uint32 time_created = 6;
48 | optional bool disbanded = 7;
49 | optional uint32 wins = 8;
50 | optional uint32 losses = 9;
51 | optional uint32 rank = 10;
52 | optional uint32 calibration_games_remaining = 24;
53 | optional uint64 logo = 11;
54 | optional uint64 base_logo = 12;
55 | optional uint64 banner_logo = 13;
56 | optional uint64 sponsor_logo = 14;
57 | optional string country_code = 15;
58 | optional string url = 16;
59 | optional uint32 fullgamesplayed = 17;
60 | repeated uint32 leagues = 18;
61 | optional uint32 gamesplayed = 19;
62 | optional uint32 gamesplayedwithcurrentroster = 20;
63 | optional uint32 teammatchmakinggamesplayed = 21;
64 | optional uint32 lastplayedgametime = 22;
65 | optional uint32 lastrenametime = 23;
66 | repeated uint64 recent_match_ids = 25;
67 | repeated uint64 top_match_ids = 26;
68 | optional bool pickup_team = 27;
69 | }
70 |
71 | message CMsgDOTATeamInfo {
72 | message HeroStats {
73 | optional uint32 hero_id = 1;
74 | optional uint32 picks = 2;
75 | optional uint32 wins = 3;
76 | optional uint32 bans = 4;
77 | optional float avg_kills = 5;
78 | optional float avg_deaths = 6;
79 | optional float avg_assists = 7;
80 | optional float avg_gpm = 8;
81 | optional float avg_xpm = 9;
82 | }
83 |
84 | message MemberStats {
85 | optional uint32 account_id = 1;
86 | optional uint32 wins_with_team = 2;
87 | optional uint32 losses_with_team = 3;
88 | repeated dota.CMsgDOTATeamInfo.HeroStats top_heroes = 4;
89 | optional float avg_kills = 5;
90 | optional float avg_deaths = 6;
91 | optional float avg_assists = 7;
92 | }
93 |
94 | message TeamStats {
95 | repeated dota.CMsgDOTATeamInfo.HeroStats played_heroes = 1;
96 | optional float farming = 2;
97 | optional float fighting = 3;
98 | optional float versatility = 4;
99 | optional float avg_kills = 5;
100 | optional float avg_deaths = 6;
101 | optional float avg_duration = 7;
102 | }
103 |
104 | message DPCResult {
105 | optional uint32 league_id = 1;
106 | optional uint32 standing = 2;
107 | optional uint32 points = 3;
108 | optional uint32 earnings = 4;
109 | optional uint32 timestamp = 5;
110 | }
111 |
112 | message Member {
113 | optional uint32 account_id = 1;
114 | optional uint32 time_joined = 2;
115 | optional bool admin = 3;
116 | }
117 |
118 | message AuditEntry {
119 | optional uint32 audit_action = 1;
120 | optional uint32 timestamp = 2;
121 | optional uint32 account_id = 3;
122 | }
123 |
124 | repeated dota.CMsgDOTATeamInfo.Member members = 1;
125 | optional uint32 team_id = 2;
126 | optional string name = 3;
127 | optional string tag = 4;
128 | optional uint32 time_created = 5;
129 | optional bool pro = 6;
130 | optional bool pickup_team = 8;
131 | optional uint64 ugc_logo = 9;
132 | optional uint64 ugc_base_logo = 10;
133 | optional uint64 ugc_banner_logo = 11;
134 | optional uint64 ugc_sponsor_logo = 12;
135 | optional string country_code = 13;
136 | optional string url = 14;
137 | optional uint32 wins = 15;
138 | optional uint32 losses = 16;
139 | optional uint32 games_played_total = 19;
140 | optional uint32 games_played_matchmaking = 20;
141 | optional string url_logo = 24;
142 | repeated uint32 registered_member_account_ids = 30;
143 | optional uint32 coach_account_id = 36;
144 | repeated dota.CMsgDOTATeamInfo.AuditEntry audit_entries = 31;
145 | optional dota.ELeagueRegion region = 29 [default = LEAGUE_REGION_UNSET];
146 | optional string abbreviation = 32;
147 | repeated dota.CMsgDOTATeamInfo.MemberStats member_stats = 33;
148 | optional dota.CMsgDOTATeamInfo.TeamStats team_stats = 34;
149 | repeated dota.CMsgDOTATeamInfo.DPCResult dpc_results = 35;
150 | optional string color_primary = 37;
151 | optional string color_secondary = 38;
152 | optional uint32 team_captain = 39;
153 | }
154 |
155 | message CMsgDOTATeamInfoRequest {
156 | optional dota.CMsgDOTATeamInfo result = 1;
157 | }
158 |
159 | message CMsgDOTATeamsInfo {
160 | optional uint32 league_id = 1;
161 | repeated dota.CMsgDOTATeamInfo teams = 2;
162 | }
163 |
164 | message CMsgDOTATeamInfoList {
165 | repeated dota.CMsgDOTATeamInfo teams = 1;
166 | }
167 |
168 | message CMsgDOTAMyTeamInfoRequest {
169 | }
170 |
171 | message CMsgDOTACreateTeam {
172 | optional string name = 1;
173 | optional string tag = 2;
174 | optional uint64 logo = 3;
175 | optional uint64 base_logo = 4;
176 | optional uint64 banner_logo = 5;
177 | optional uint64 sponsor_logo = 6;
178 | optional string country_code = 7;
179 | optional string url = 8;
180 | optional bool pickup_team = 9;
181 | optional string abbreviation = 10;
182 | }
183 |
184 | message CMsgDOTACreateTeamResponse {
185 | enum Result {
186 | INVALID = -1;
187 | SUCCESS = 0;
188 | NAME_EMPTY = 1;
189 | NAME_BAD_CHARACTERS = 2;
190 | NAME_TAKEN = 3;
191 | NAME_TOO_LONG = 4;
192 | TAG_EMPTY = 5;
193 | TAG_BAD_CHARACTERS = 6;
194 | TAG_TAKEN = 7;
195 | TAG_TOO_LONG = 8;
196 | CREATOR_BUSY = 9;
197 | UNSPECIFIED_ERROR = 10;
198 | CREATOR_TEAM_LIMIT_REACHED = 11;
199 | NO_LOGO = 12;
200 | CREATOR_TEAM_CREATION_COOLDOWN = 13;
201 | LOGO_UPLOAD_FAILED = 14;
202 | NAME_CHANGED_TOO_RECENTLY = 15;
203 | CREATOR_INSUFFICIENT_LEVEL = 16;
204 | INVALID_ACCOUNT_TYPE = 17;
205 | }
206 |
207 | optional dota.CMsgDOTACreateTeamResponse.Result result = 1 [default = INVALID];
208 | optional uint32 team_id = 2;
209 | }
210 |
211 | message CMsgDOTAEditTeamDetails {
212 | optional uint32 team_id = 1;
213 | optional string name = 2;
214 | optional string tag = 3;
215 | optional uint64 logo = 4;
216 | optional uint64 base_logo = 5;
217 | optional uint64 banner_logo = 6;
218 | optional uint64 sponsor_logo = 7;
219 | optional string country_code = 8;
220 | optional string url = 9;
221 | optional bool in_use_by_party = 10;
222 | optional string abbreviation = 11;
223 | }
224 |
225 | message CMsgDOTAEditTeamDetailsResponse {
226 | enum Result {
227 | SUCCESS = 0;
228 | FAILURE_INVALID_ACCOUNT_TYPE = 1;
229 | FAILURE_NOT_MEMBER = 2;
230 | FAILURE_TEAM_LOCKED = 3;
231 | FAILURE_UNSPECIFIED_ERROR = 4;
232 | }
233 |
234 | optional dota.CMsgDOTAEditTeamDetailsResponse.Result result = 1 [default = SUCCESS];
235 | }
236 |
237 | message CMsgDOTATeamProfileResponse {
238 | optional uint32 eresult = 1;
239 | optional dota.CMsgDOTATeam team = 2;
240 | }
241 |
242 | message CMsgDOTAProTeamListRequest {
243 | }
244 |
245 | message CMsgDOTAProTeamListResponse {
246 | message TeamEntry {
247 | optional uint32 team_id = 1;
248 | optional string tag = 2;
249 | optional uint32 time_created = 3;
250 | optional uint64 logo = 4;
251 | optional string country_code = 5;
252 | optional uint32 member_count = 6;
253 | }
254 |
255 | repeated dota.CMsgDOTAProTeamListResponse.TeamEntry teams = 1;
256 | optional uint32 eresult = 2;
257 | }
258 |
259 | message CMsgDOTATeamInvite_InviterToGC {
260 | optional uint32 account_id = 1;
261 | optional uint32 team_id = 2;
262 | }
263 |
264 | message CMsgDOTATeamInvite_GCImmediateResponseToInviter {
265 | optional dota.ETeamInviteResult result = 1 [default = TEAM_INVITE_SUCCESS];
266 | optional string invitee_name = 2;
267 | optional uint32 required_play_time = 3;
268 | }
269 |
270 | message CMsgDOTATeamInvite_GCRequestToInvitee {
271 | optional uint32 inviter_account_id = 1;
272 | optional string team_name = 2;
273 | optional string team_tag = 3;
274 | optional uint64 logo = 4;
275 | }
276 |
277 | message CMsgDOTATeamInvite_InviteeResponseToGC {
278 | optional dota.ETeamInviteResult result = 1 [default = TEAM_INVITE_SUCCESS];
279 | }
280 |
281 | message CMsgDOTATeamInvite_GCResponseToInviter {
282 | optional dota.ETeamInviteResult result = 1 [default = TEAM_INVITE_SUCCESS];
283 | optional string invitee_name = 2;
284 | }
285 |
286 | message CMsgDOTATeamInvite_GCResponseToInvitee {
287 | optional dota.ETeamInviteResult result = 1 [default = TEAM_INVITE_SUCCESS];
288 | optional string team_name = 2;
289 | }
290 |
291 | message CMsgDOTAKickTeamMember {
292 | optional uint32 account_id = 1;
293 | optional uint32 team_id = 2;
294 | }
295 |
296 | message CMsgDOTAKickTeamMemberResponse {
297 | enum Result {
298 | SUCCESS = 0;
299 | FAILURE_INVALID_ACCOUNT_TYPE = 1;
300 | FAILURE_KICKER_NOT_ADMIN = 2;
301 | FAILURE_KICKEE_NOT_MEMBER = 3;
302 | FAILURE_TEAM_LOCKED = 4;
303 | FAILURE_UNSPECIFIED_ERROR = 5;
304 | }
305 |
306 | optional dota.CMsgDOTAKickTeamMemberResponse.Result result = 1 [default = SUCCESS];
307 | }
308 |
309 | message CMsgDOTATransferTeamAdmin {
310 | optional uint32 new_admin_account_id = 1;
311 | optional uint32 team_id = 2;
312 | }
313 |
314 | message CMsgDOTATransferTeamAdminResponse {
315 | enum Result {
316 | SUCCESS = 0;
317 | FAILURE_INVALID_ACCOUNT_TYPE = 1;
318 | FAILURE_NOT_ADMIN = 2;
319 | FAILURE_SAME_ACCOUNT = 3;
320 | FAILURE_NOT_MEMBER = 4;
321 | FAILURE_UNSPECIFIED_ERROR = 5;
322 | }
323 |
324 | optional dota.CMsgDOTATransferTeamAdminResponse.Result result = 1 [default = SUCCESS];
325 | }
326 |
327 | message CMsgDOTALeaveTeam {
328 | optional uint32 team_id = 1;
329 | }
330 |
331 | message CMsgDOTALeaveTeamResponse {
332 | enum Result {
333 | SUCCESS = 0;
334 | FAILURE_NOT_MEMBER = 1;
335 | FAILURE_TEAM_LOCKED = 2;
336 | FAILURE_UNSPECIFIED_ERROR = 3;
337 | }
338 |
339 | optional dota.CMsgDOTALeaveTeamResponse.Result result = 1 [default = SUCCESS];
340 | }
341 |
342 | message CMsgDOTABetaParticipation {
343 | optional uint32 access_rights = 1;
344 | }
345 |
--------------------------------------------------------------------------------
/protobufs/dota_gcmessages_client_tournament.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "dota_client_enums.proto";
4 |
5 | option optimize_for = SPEED;
6 | option py_generic_services = false;
7 |
8 | enum ETournamentEvent {
9 | k_ETournamentEvent_None = 0;
10 | k_ETournamentEvent_TournamentCreated = 1;
11 | k_ETournamentEvent_TournamentsMerged = 2;
12 | k_ETournamentEvent_GameOutcome = 3;
13 | k_ETournamentEvent_TeamGivenBye = 4;
14 | k_ETournamentEvent_TournamentCanceledByAdmin = 5;
15 | k_ETournamentEvent_TeamAbandoned = 6;
16 | k_ETournamentEvent_ScheduledGameStarted = 7;
17 | k_ETournamentEvent_Canceled = 8;
18 | k_ETournamentEvent_TeamParticipationTimedOut_EntryFeeRefund = 9;
19 | k_ETournamentEvent_TeamParticipationTimedOut_EntryFeeForfeit = 10;
20 | k_ETournamentEvent_TeamParticipationTimedOut_GrantedVictory = 11;
21 | }
22 |
23 | message CMsgDOTATournamentInfo {
24 | message PhaseGroup {
25 | optional uint32 group_id = 1;
26 | optional string group_name = 2;
27 | }
28 |
29 | message Phase {
30 | optional uint32 phase_id = 1;
31 | optional string phase_name = 2;
32 | optional uint32 type_id = 3;
33 | optional uint32 iterations = 4;
34 | optional uint32 min_start_time = 5;
35 | optional uint32 max_start_time = 6;
36 | repeated dota.CMsgDOTATournamentInfo.PhaseGroup group_list = 7;
37 | }
38 |
39 | message Team {
40 | optional uint32 team_id = 1;
41 | optional string name = 2;
42 | optional string tag = 3;
43 | optional uint64 team_logo = 4;
44 | optional bool eliminated = 5;
45 | }
46 |
47 | message UpcomingMatch {
48 | optional uint32 series_id = 1;
49 | optional uint32 team1_id = 2;
50 | optional uint32 team2_id = 3;
51 | optional uint32 bo = 4;
52 | optional string stage_name = 5;
53 | optional uint32 start_time = 6;
54 | optional string winner_stage = 7;
55 | optional string loser_stage = 8;
56 | optional string team1_tag = 9;
57 | optional string team2_tag = 10;
58 | optional string team1_prev_opponent_tag = 11;
59 | optional string team2_prev_opponent_tag = 12;
60 | optional uint64 team1_logo = 13;
61 | optional uint64 team2_logo = 14;
62 | optional uint64 team1_prev_opponent_logo = 15;
63 | optional uint64 team2_prev_opponent_logo = 16;
64 | optional uint32 team1_prev_opponent_id = 17;
65 | optional uint32 team2_prev_opponent_id = 18;
66 | optional uint32 team1_prev_match_score = 19;
67 | optional uint32 team1_prev_match_opponent_score = 20;
68 | optional uint32 team2_prev_match_score = 21;
69 | optional uint32 team2_prev_match_opponent_score = 22;
70 | optional uint32 phase_type = 23;
71 | optional uint32 team1_score = 24;
72 | optional uint32 team2_score = 25;
73 | optional uint32 phase_id = 26;
74 | }
75 |
76 | message News {
77 | optional string link = 1;
78 | optional string title = 2;
79 | optional string image = 3;
80 | optional uint32 timestamp = 4;
81 | }
82 |
83 | optional uint32 league_id = 1;
84 | repeated dota.CMsgDOTATournamentInfo.Phase phase_list = 2;
85 | repeated dota.CMsgDOTATournamentInfo.Team teams_list = 3;
86 | repeated dota.CMsgDOTATournamentInfo.UpcomingMatch upcoming_matches_list = 4;
87 | repeated dota.CMsgDOTATournamentInfo.News news_list = 5;
88 | }
89 |
90 | message CMsgRequestWeekendTourneySchedule {
91 | }
92 |
93 | message CMsgWeekendTourneySchedule {
94 | message Division {
95 | optional uint32 division_code = 1;
96 | optional uint32 time_window_open = 2;
97 | optional uint32 time_window_close = 3;
98 | optional uint32 time_window_open_next = 4;
99 | optional uint32 trophy_id = 5;
100 | optional bool free_weekend = 6;
101 | }
102 |
103 | repeated dota.CMsgWeekendTourneySchedule.Division divisions = 1;
104 | }
105 |
106 | message CMsgWeekendTourneyOpts {
107 | optional bool participating = 1;
108 | optional uint32 division_id = 2;
109 | optional uint32 buyin = 3;
110 | optional uint32 skill_level = 4;
111 | optional uint32 match_groups = 5;
112 | optional uint32 team_id = 6;
113 | optional string pickup_team_name = 7;
114 | optional uint64 pickup_team_logo = 8;
115 | }
116 |
117 | message CMsgWeekendTourneyLeave {
118 | }
119 |
120 | message CMsgDOTATournament {
121 | message Team {
122 | optional fixed64 team_gid = 1;
123 | optional uint32 node_or_state = 2;
124 | repeated uint32 players = 3 [packed = true];
125 | repeated uint32 player_buyin = 9 [packed = true];
126 | repeated uint32 player_skill_level = 10 [packed = true];
127 | optional uint32 match_group_mask = 12;
128 | optional uint32 team_id = 4;
129 | optional string team_name = 5;
130 | optional uint64 team_base_logo = 7;
131 | optional uint64 team_ui_logo = 8;
132 | }
133 |
134 | message Game {
135 | optional uint32 node_idx = 1;
136 | optional fixed64 lobby_id = 2;
137 | optional uint64 match_id = 3;
138 | optional bool team_a_good = 4;
139 | optional dota.ETournamentGameState state = 5 [default = k_ETournamentGameState_Unknown];
140 | optional uint32 start_time = 6;
141 | }
142 |
143 | message Node {
144 | optional uint32 node_id = 1;
145 | optional uint32 team_idx_a = 2;
146 | optional uint32 team_idx_b = 3;
147 | optional dota.ETournamentNodeState node_state = 4 [default = k_ETournamentNodeState_Unknown];
148 | }
149 |
150 | optional uint32 tournament_id = 1;
151 | optional uint32 division_id = 2;
152 | optional uint32 schedule_time = 3;
153 | optional uint32 skill_level = 4;
154 | optional dota.ETournamentTemplate tournament_template = 5 [default = k_ETournamentTemplate_None];
155 | optional dota.ETournamentState state = 6 [default = k_ETournamentState_Unknown];
156 | optional uint32 state_seq_num = 10;
157 | optional uint32 season_trophy_id = 11;
158 | repeated dota.CMsgDOTATournament.Team teams = 7;
159 | repeated dota.CMsgDOTATournament.Game games = 8;
160 | repeated dota.CMsgDOTATournament.Node nodes = 9;
161 | }
162 |
163 | message CMsgDOTATournamentStateChange {
164 | message GameChange {
165 | optional uint64 match_id = 1;
166 | optional dota.ETournamentGameState new_state = 2 [default = k_ETournamentGameState_Unknown];
167 | }
168 |
169 | message TeamChange {
170 | optional uint64 team_gid = 1;
171 | optional uint32 new_node_or_state = 2;
172 | optional uint32 old_node_or_state = 3;
173 | }
174 |
175 | optional uint32 new_tournament_id = 1;
176 | optional dota.ETournamentEvent event = 2 [default = k_ETournamentEvent_None];
177 | optional dota.ETournamentState new_tournament_state = 3 [default = k_ETournamentState_Unknown];
178 | repeated dota.CMsgDOTATournamentStateChange.GameChange game_changes = 4;
179 | repeated dota.CMsgDOTATournamentStateChange.TeamChange team_changes = 5;
180 | repeated uint32 merged_tournament_ids = 6 [packed = true];
181 | optional uint32 state_seq_num = 7;
182 | }
183 |
184 | message CMsgDOTATournamentRequest {
185 | optional uint32 tournament_id = 1;
186 | optional uint64 client_tournament_gid = 2;
187 | }
188 |
189 | message CMsgDOTATournamentResponse {
190 | optional uint32 result = 1 [default = 2];
191 | optional dota.CMsgDOTATournament tournament = 2;
192 | }
193 |
194 | message CMsgDOTAClearTournamentGame {
195 | optional uint32 tournament_id = 1;
196 | optional uint32 game_id = 2;
197 | }
198 |
199 | message CMsgDOTAWeekendTourneyPlayerSkillLevelStats {
200 | optional uint32 skill_level = 1;
201 | optional uint32 times_won_0 = 2;
202 | optional uint32 times_won_1 = 3;
203 | optional uint32 times_won_2 = 4;
204 | optional uint32 times_won_3 = 5;
205 | optional uint32 times_bye_and_lost = 6;
206 | optional uint32 times_bye_and_won = 7;
207 | optional uint32 times_unusual_champ = 10;
208 | optional uint32 total_games_won = 8;
209 | optional uint32 score = 9;
210 | }
211 |
212 | message CMsgDOTAWeekendTourneyPlayerStats {
213 | optional uint32 account_id = 1;
214 | optional uint32 season_trophy_id = 2;
215 | repeated dota.CMsgDOTAWeekendTourneyPlayerSkillLevelStats skill_levels = 3;
216 | optional uint32 current_tier = 4;
217 | }
218 |
219 | message CMsgDOTAWeekendTourneyPlayerStatsRequest {
220 | optional uint32 account_id = 1;
221 | optional uint32 season_trophy_id = 2;
222 | }
223 |
224 | message CMsgDOTAWeekendTourneyPlayerHistoryRequest {
225 | optional uint32 account_id = 1;
226 | optional uint32 season_trophy_id = 2;
227 | }
228 |
229 | message CMsgDOTAWeekendTourneyPlayerHistory {
230 | message Tournament {
231 | optional uint32 tournament_id = 1;
232 | optional uint32 start_time = 2;
233 | optional uint32 tournament_tier = 3;
234 | optional uint32 team_id = 4;
235 | optional uint32 team_date = 5;
236 | optional uint32 team_result = 6;
237 | repeated uint32 account_id = 7;
238 | optional string team_name = 8;
239 | optional uint32 season_trophy_id = 9;
240 | }
241 |
242 | optional uint32 account_id = 1;
243 | repeated dota.CMsgDOTAWeekendTourneyPlayerHistory.Tournament tournaments = 3;
244 | }
245 |
246 | message CMsgDOTAWeekendTourneyParticipationDetails {
247 | message Tier {
248 | optional uint32 tier = 1;
249 | optional uint32 players = 2;
250 | optional uint32 teams = 3;
251 | optional uint32 winning_teams = 4;
252 | optional uint32 players_streak_2 = 5;
253 | optional uint32 players_streak_3 = 6;
254 | optional uint32 players_streak_4 = 7;
255 | optional uint32 players_streak_5 = 8;
256 | }
257 |
258 | message Division {
259 | optional uint32 division_id = 1;
260 | optional uint32 schedule_time = 2;
261 | repeated dota.CMsgDOTAWeekendTourneyParticipationDetails.Tier tiers = 3;
262 | }
263 |
264 | repeated dota.CMsgDOTAWeekendTourneyParticipationDetails.Division divisions = 1;
265 | }
266 |
--------------------------------------------------------------------------------
/protobufs/dota_gcmessages_client_watch.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "dota_gcmessages_common.proto";
4 |
5 | option optimize_for = SPEED;
6 | option py_generic_services = false;
7 |
8 | message CSourceTVGameSmall {
9 | message Player {
10 | optional uint32 account_id = 1;
11 | optional uint32 hero_id = 2;
12 | }
13 |
14 | optional uint32 activate_time = 1;
15 | optional uint32 deactivate_time = 2;
16 | optional uint64 server_steam_id = 3;
17 | optional uint64 lobby_id = 4;
18 | optional uint32 league_id = 5;
19 | optional uint32 lobby_type = 6;
20 | optional int32 game_time = 7;
21 | optional uint32 delay = 8;
22 | optional uint32 spectators = 9;
23 | optional uint32 game_mode = 10;
24 | optional uint32 average_mmr = 11;
25 | optional uint64 match_id = 12;
26 | optional uint32 series_id = 13;
27 | optional string team_name_radiant = 15;
28 | optional string team_name_dire = 16;
29 | optional fixed64 team_logo_radiant = 24;
30 | optional fixed64 team_logo_dire = 25;
31 | optional uint32 team_id_radiant = 30;
32 | optional uint32 team_id_dire = 31;
33 | optional uint32 sort_score = 17;
34 | optional float last_update_time = 18;
35 | optional int32 radiant_lead = 19;
36 | optional uint32 radiant_score = 20;
37 | optional uint32 dire_score = 21;
38 | repeated dota.CSourceTVGameSmall.Player players = 22;
39 | optional fixed32 building_state = 23;
40 | optional uint32 weekend_tourney_tournament_id = 26;
41 | optional uint32 weekend_tourney_division = 27;
42 | optional uint32 weekend_tourney_skill_level = 28;
43 | optional uint32 weekend_tourney_bracket_round = 29;
44 | optional uint32 custom_game_difficulty = 32;
45 | }
46 |
47 | message CMsgClientToGCFindTopSourceTVGames {
48 | optional string search_key = 1;
49 | optional uint32 league_id = 2;
50 | optional uint32 hero_id = 3;
51 | optional uint32 start_game = 4;
52 | optional uint32 game_list_index = 5;
53 | repeated uint64 lobby_ids = 6;
54 | }
55 |
56 | message CMsgGCToClientFindTopSourceTVGamesResponse {
57 | optional string search_key = 1;
58 | optional uint32 league_id = 2;
59 | optional uint32 hero_id = 3;
60 | optional uint32 start_game = 4;
61 | optional uint32 num_games = 5;
62 | optional uint32 game_list_index = 6;
63 | repeated dota.CSourceTVGameSmall game_list = 7;
64 | optional bool specific_games = 8;
65 | optional dota.CSourceTVGameSmall bot_game = 9;
66 | }
67 |
68 | message CMsgGCToClientTopWeekendTourneyGames {
69 | repeated dota.CSourceTVGameSmall live_games = 1;
70 | }
71 |
72 | message CMsgClientToGCTopMatchesRequest {
73 | optional uint32 hero_id = 1;
74 | optional uint32 player_account_id = 2;
75 | optional uint32 team_id = 3;
76 | }
77 |
78 | message CMsgClientToGCTopLeagueMatchesRequest {
79 | }
80 |
81 | message CMsgClientToGCTopFriendMatchesRequest {
82 | }
83 |
84 | message CMsgClientToGCMatchesMinimalRequest {
85 | repeated uint64 match_ids = 1;
86 | }
87 |
88 | message CMsgClientToGCMatchesMinimalResponse {
89 | repeated dota.CMsgDOTAMatchMinimal matches = 1;
90 | optional bool last_match = 2;
91 | }
92 |
93 | message CMsgGCToClientTopLeagueMatchesResponse {
94 | repeated dota.CMsgDOTAMatchMinimal matches = 2;
95 | }
96 |
97 | message CMsgGCToClientTopFriendMatchesResponse {
98 | repeated dota.CMsgDOTAMatchMinimal matches = 1;
99 | }
100 |
101 | message CMsgClientToGCFindTopMatches {
102 | optional uint32 start_game = 1;
103 | optional uint32 league_id = 2;
104 | optional uint32 hero_id = 3;
105 | optional uint32 friend_id = 4;
106 | optional bool friend_list = 5;
107 | optional bool league_list = 6;
108 | }
109 |
110 | message CMsgGCToClientFindTopLeagueMatchesResponse {
111 | optional uint32 start_game = 1;
112 | optional uint32 league_id = 2;
113 | optional uint32 hero_id = 3;
114 | repeated uint32 match_ids = 4;
115 | repeated dota.CMsgDOTAMatch matches = 5;
116 | }
117 |
118 | message CMsgSpectateFriendGame {
119 | optional fixed64 steam_id = 1;
120 | optional bool live = 2;
121 | }
122 |
123 | message CMsgSpectateFriendGameResponse {
124 | enum EWatchLiveResult {
125 | SUCCESS = 0;
126 | ERROR_GENERIC = 1;
127 | ERROR_NO_PLUS = 2;
128 | ERROR_NOT_FRIENDS = 3;
129 | ERROR_LOBBY_NOT_FOUND = 4;
130 | ERROR_SPECTATOR_IN_A_LOBBY = 5;
131 | ERROR_LOBBY_IS_LAN = 6;
132 | ERROR_WRONG_LOBBY_TYPE = 7;
133 | ERROR_WRONG_LOBBY_STATE = 8;
134 | ERROR_PLAYER_NOT_PLAYER = 9;
135 | ERROR_TOO_MANY_SPECTATORS = 10;
136 | ERROR_SPECTATOR_SWITCHED_TEAMS = 11;
137 | ERROR_FRIENDS_ON_BOTH_SIDES = 12;
138 | ERROR_SPECTATOR_IN_THIS_LOBBY = 13;
139 | ERROR_LOBBY_IS_LEAGUE = 14;
140 | }
141 |
142 | optional fixed64 server_steamid = 4;
143 | optional dota.CMsgSpectateFriendGameResponse.EWatchLiveResult watch_live_result = 5 [default = SUCCESS];
144 | }
145 |
146 | message CDOTAReplayDownloadInfo {
147 | message Highlight {
148 | optional uint32 timestamp = 1;
149 | optional string description = 2;
150 | }
151 |
152 | optional dota.CMsgDOTAMatchMinimal match = 1;
153 | optional string title = 2;
154 | optional string description = 3;
155 | optional uint32 size = 4;
156 | repeated string tags = 5;
157 | optional bool exists_on_disk = 6;
158 | }
159 |
160 | message CMsgWatchGame {
161 | optional fixed64 server_steamid = 1;
162 | optional uint32 client_version = 2;
163 | optional fixed64 watch_server_steamid = 3;
164 | optional uint64 lobby_id = 4;
165 | repeated uint32 regions = 5;
166 | }
167 |
168 | message CMsgCancelWatchGame {
169 | }
170 |
171 | message CMsgWatchGameResponse {
172 | enum WatchGameResult {
173 | PENDING = 0;
174 | READY = 1;
175 | GAMESERVERNOTFOUND = 2;
176 | UNAVAILABLE = 3;
177 | CANCELLED = 4;
178 | INCOMPATIBLEVERSION = 5;
179 | MISSINGLEAGUESUBSCRIPTION = 6;
180 | LOBBYNOTFOUND = 7;
181 | }
182 |
183 | optional dota.CMsgWatchGameResponse.WatchGameResult watch_game_result = 1 [default = PENDING];
184 | optional uint32 source_tv_public_addr = 2;
185 | optional uint32 source_tv_private_addr = 3;
186 | optional uint32 source_tv_port = 4;
187 | optional fixed64 game_server_steamid = 5;
188 | optional fixed64 watch_server_steamid = 6;
189 | optional fixed64 watch_tv_unique_secret_code = 7;
190 | }
191 |
192 | message CMsgPartyLeaderWatchGamePrompt {
193 | optional fixed64 game_server_steamid = 5;
194 | }
195 |
196 | message CDOTABroadcasterInfo {
197 | optional uint32 account_id = 1;
198 | optional fixed64 server_steam_id = 2;
199 | optional bool live = 3;
200 | optional string team_name_radiant = 4;
201 | optional string team_name_dire = 5;
202 | optional uint32 series_game = 7;
203 | optional uint32 upcoming_broadcast_timestamp = 9;
204 | optional bool allow_live_video = 10;
205 | optional uint32 node_type = 11;
206 | optional string node_name = 12;
207 | }
208 |
209 | message CMsgDOTASeries {
210 | message TeamInfo {
211 | optional uint32 team_id = 1;
212 | optional string team_name = 2;
213 | optional string team_logo_url = 3;
214 | optional uint32 wager_count = 4;
215 | }
216 |
217 | message LiveGame {
218 | optional fixed64 server_steam_id = 1;
219 | optional dota.CMsgDOTASeries.TeamInfo team_radiant = 2;
220 | optional dota.CMsgDOTASeries.TeamInfo team_dire = 3;
221 | optional uint32 team_radiant_score = 4;
222 | optional uint32 team_dire_score = 5;
223 | }
224 |
225 | optional uint32 series_id = 1;
226 | optional uint32 series_type = 2;
227 | optional dota.CMsgDOTASeries.TeamInfo team_1 = 3;
228 | optional dota.CMsgDOTASeries.TeamInfo team_2 = 4;
229 | repeated dota.CMsgDOTAMatchMinimal match_minimal = 5;
230 | optional dota.CMsgDOTASeries.LiveGame live_game = 6;
231 | }
232 |
--------------------------------------------------------------------------------
/protobufs/dota_match_metadata.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "base_gcmessages.proto";
4 | import "dota_gcmessages_common_match_management.proto";
5 | import "dota_gcmessages_common.proto";
6 | import "dota_shared_enums.proto";
7 |
8 | option py_generic_services = false;
9 |
10 | message CDOTAMatchMetadataFile {
11 | required int32 version = 1;
12 | required uint64 match_id = 2;
13 | optional dota.CDOTAMatchMetadata metadata = 3;
14 | optional bytes private_metadata = 5;
15 | }
16 |
17 | message CDOTAMatchMetadata {
18 | message Team {
19 | message PlayerKill {
20 | optional uint32 victim_slot = 1;
21 | optional uint32 count = 2;
22 | }
23 |
24 | message ItemPurchase {
25 | optional uint32 item_id = 1;
26 | optional int32 purchase_time = 2;
27 | }
28 |
29 | message InventorySnapshot {
30 | repeated uint32 item_id = 1;
31 | optional int32 game_time = 2;
32 | optional uint32 kills = 3;
33 | optional uint32 deaths = 4;
34 | optional uint32 assists = 5;
35 | optional uint32 level = 6;
36 | }
37 |
38 | message AutoStyleCriteria {
39 | optional uint32 name_token = 1;
40 | optional float value = 2;
41 | }
42 |
43 | message StrangeGemProgress {
44 | optional uint32 kill_eater_type = 1;
45 | optional uint32 gem_item_def_index = 2;
46 | optional uint32 required_hero_id = 3;
47 | optional uint32 starting_value = 4;
48 | optional uint32 ending_value = 5;
49 | optional uint32 owner_item_def_index = 6;
50 | optional uint64 owner_item_id = 7;
51 | }
52 |
53 | message VictoryPrediction {
54 | optional uint64 item_id = 1;
55 | optional uint32 item_def_index = 2;
56 | optional uint32 starting_value = 3;
57 | optional bool is_victory = 4;
58 | }
59 |
60 | message SubChallenge {
61 | optional uint32 slot_id = 1;
62 | optional uint32 start_value = 2;
63 | optional uint32 end_value = 3;
64 | optional bool completed = 4;
65 | }
66 |
67 | message CavernChallengeResult {
68 | optional uint32 completed_path_id = 1;
69 | optional uint32 claimed_room_id = 2;
70 | }
71 |
72 | message ActionGrant {
73 | optional uint32 action_id = 1;
74 | optional uint32 quantity = 2;
75 | optional uint32 audit = 3;
76 | }
77 |
78 | message CandyGrant {
79 | optional uint32 points = 1;
80 | optional uint32 reason = 2;
81 | }
82 |
83 | message EventData {
84 | optional uint32 event_id = 1;
85 | optional uint32 event_points = 2;
86 | optional uint32 challenge_instance_id = 3;
87 | optional uint32 challenge_quest_id = 4;
88 | optional uint32 challenge_quest_challenge_id = 5;
89 | optional bool challenge_completed = 6;
90 | optional uint32 challenge_rank_completed = 7;
91 | optional uint32 challenge_rank_previously_completed = 8;
92 | optional bool event_owned = 9;
93 | repeated dota.CDOTAMatchMetadata.Team.SubChallenge sub_challenges_with_progress = 10;
94 | optional uint32 wager_winnings = 11;
95 | optional bool cavern_challenge_active = 12;
96 | optional uint32 cavern_challenge_winnings = 13;
97 | optional uint32 amount_wagered = 14;
98 | optional uint32 periodic_point_adjustments = 16;
99 | repeated dota.CDOTAMatchMetadata.Team.CavernChallengeResult cavern_challenge_map_results = 17;
100 | optional uint32 cavern_challenge_plus_shard_winnings = 18;
101 | repeated dota.CDOTAMatchMetadata.Team.ActionGrant actions_granted = 19;
102 | optional uint32 cavern_crawl_map_variant = 20;
103 | optional uint32 team_wager_bonus_pct = 21;
104 | optional uint32 wager_streak_pct = 22;
105 | repeated dota.CDOTAMatchMetadata.Team.CandyGrant candy_points_granted = 23;
106 | }
107 |
108 | message GauntletProgress {
109 | optional uint32 gauntlet_tier = 2;
110 | optional uint32 gauntlet_wins = 3;
111 | optional uint32 gauntlet_losses = 4;
112 | }
113 |
114 | message Player {
115 | message ContractProgress {
116 | optional uint32 guild_id = 1;
117 | optional uint32 event_id = 2;
118 | optional uint32 challenge_instance_id = 3;
119 | optional uint32 challenge_parameter = 4;
120 | optional uint32 contract_stars = 5;
121 | optional uint32 contract_slot = 6;
122 | optional bool completed = 7;
123 | }
124 |
125 | optional uint32 account_id = 1;
126 | repeated uint32 ability_upgrades = 2;
127 | optional uint32 player_slot = 3;
128 | repeated dota.CSOEconItem equipped_econ_items = 4;
129 | repeated dota.CDOTAMatchMetadata.Team.PlayerKill kills = 5;
130 | repeated dota.CDOTAMatchMetadata.Team.ItemPurchase items = 6;
131 | optional uint32 avg_kills_x16 = 7;
132 | optional uint32 avg_deaths_x16 = 8;
133 | optional uint32 avg_assists_x16 = 9;
134 | optional uint32 avg_gpm_x16 = 10;
135 | optional uint32 avg_xpm_x16 = 11;
136 | optional uint32 best_kills_x16 = 12;
137 | optional uint32 best_assists_x16 = 13;
138 | optional uint32 best_gpm_x16 = 14;
139 | optional uint32 best_xpm_x16 = 15;
140 | optional uint32 win_streak = 16;
141 | optional uint32 best_win_streak = 17;
142 | optional float fight_score = 18;
143 | optional float farm_score = 19;
144 | optional float support_score = 20;
145 | optional float push_score = 21;
146 | repeated uint32 level_up_times = 22;
147 | repeated float graph_net_worth = 23;
148 | repeated dota.CDOTAMatchMetadata.Team.InventorySnapshot inventory_snapshot = 24;
149 | optional bool avg_stats_calibrated = 25;
150 | repeated dota.CDOTAMatchMetadata.Team.AutoStyleCriteria auto_style_criteria = 26;
151 | repeated dota.CDOTAMatchMetadata.Team.EventData event_data = 29;
152 | repeated dota.CDOTAMatchMetadata.Team.StrangeGemProgress strange_gem_progress = 30;
153 | optional uint32 hero_xp = 31;
154 | optional uint32 camps_stacked = 32;
155 | repeated dota.CDOTAMatchMetadata.Team.VictoryPrediction victory_prediction = 33;
156 | optional uint32 lane_selection_flags = 34;
157 | optional uint32 rampages = 35;
158 | optional uint32 triple_kills = 36;
159 | optional uint32 aegis_snatched = 37;
160 | optional uint32 rapiers_purchased = 38;
161 | optional uint32 couriers_killed = 39;
162 | optional uint32 net_worth_rank = 40;
163 | optional uint32 support_gold_spent = 41;
164 | optional uint32 observer_wards_placed = 42;
165 | optional uint32 sentry_wards_placed = 43;
166 | optional uint32 wards_dewarded = 44;
167 | optional float stun_duration = 45;
168 | optional dota.EDOTAMMRBoostType rank_mmr_boost_type = 46 [default = k_EDOTAMMRBoostType_None];
169 | optional dota.CDOTAMatchMetadata.Team.GauntletProgress gauntlet_progress = 47;
170 | repeated dota.CDOTAMatchMetadata.Team.Player.ContractProgress contract_progress = 48;
171 | repeated uint32 guild_ids = 49;
172 | }
173 |
174 | optional uint32 dota_team = 1;
175 | repeated dota.CDOTAMatchMetadata.Team.Player players = 2;
176 | repeated float graph_experience = 3;
177 | repeated float graph_gold_earned = 4;
178 | repeated float graph_net_worth = 5;
179 | optional bool cm_first_pick = 6;
180 | optional uint32 cm_captain_player_id = 7;
181 | repeated uint32 cm_bans = 8;
182 | repeated uint32 cm_picks = 9;
183 | optional uint32 cm_penalty = 10;
184 | }
185 |
186 | message GuildChallengeProgress {
187 | message IndividualProgress {
188 | optional uint32 account_id = 1;
189 | optional uint32 progress = 2;
190 | }
191 |
192 | optional uint32 guild_id = 1;
193 | optional dota.EEvent event_id = 2 [default = EVENT_ID_NONE];
194 | optional uint32 challenge_instance_id = 3;
195 | optional uint32 challenge_parameter = 4;
196 | optional uint32 challenge_timestamp = 5;
197 | optional uint32 challenge_progress_at_start = 6;
198 | optional uint32 challenge_progress_accumulated = 7;
199 | repeated dota.CDOTAMatchMetadata.GuildChallengeProgress.IndividualProgress individual_progress = 8;
200 | }
201 |
202 | repeated dota.CDOTAMatchMetadata.Team teams = 1;
203 | repeated dota.CLobbyTimedRewardDetails item_rewards = 2;
204 | optional fixed64 lobby_id = 3;
205 | optional fixed64 report_until_time = 4;
206 | optional bytes event_game_custom_table = 5;
207 | optional uint32 primary_event_id = 6;
208 | repeated dota.CMsgMatchTips match_tips = 7;
209 | optional dota.CMsgMatchMatchmakingStats matchmaking_stats = 8;
210 | optional dota.CMvpData mvp_data = 9;
211 | repeated dota.CDOTAMatchMetadata.GuildChallengeProgress guild_challenge_progress = 10;
212 | }
213 |
214 | message CDOTAMatchPrivateMetadata {
215 | message StringName {
216 | optional uint32 id = 1;
217 | optional string name = 2;
218 | }
219 |
220 | message Team {
221 | message Player {
222 | message CombatSegment {
223 | message DamageByAbility {
224 | message ByHeroTarget {
225 | optional uint32 hero_id = 1;
226 | optional uint32 damage = 2;
227 | }
228 |
229 | optional uint32 source_unit_index = 3;
230 | optional uint32 ability_id = 1;
231 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.CombatSegment.DamageByAbility.ByHeroTarget by_hero_targets = 2;
232 | }
233 |
234 | message HealingByAbility {
235 | message ByHeroTarget {
236 | optional uint32 hero_id = 1;
237 | optional uint32 healing = 2;
238 | }
239 |
240 | optional uint32 source_unit_index = 3;
241 | optional uint32 ability_id = 1;
242 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.CombatSegment.HealingByAbility.ByHeroTarget by_hero_targets = 2;
243 | }
244 |
245 | optional int32 game_time = 1;
246 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.CombatSegment.DamageByAbility damage_by_ability = 2;
247 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.CombatSegment.HealingByAbility healing_by_ability = 3;
248 | }
249 |
250 | message BuffRecord {
251 | message ByHeroTarget {
252 | optional uint32 hero_id = 1;
253 | optional float elapsed_duration = 2;
254 | optional bool is_hidden = 3;
255 | }
256 |
257 | optional uint32 buff_ability_id = 1;
258 | optional string buff_modifier_name = 3;
259 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.BuffRecord.ByHeroTarget by_hero_targets = 2;
260 | }
261 |
262 | message GoldReceived {
263 | optional uint32 creep = 1;
264 | optional uint32 heroes = 2;
265 | optional uint32 bounty_runes = 3;
266 | optional uint32 passive = 4;
267 | optional uint32 buildings = 5;
268 | optional uint32 abilities = 6;
269 | optional uint32 wards = 7;
270 | optional uint32 other = 8;
271 | }
272 |
273 | message XPReceived {
274 | optional uint32 creep = 1;
275 | optional uint32 heroes = 2;
276 | optional uint32 roshan = 3;
277 | optional uint32 tome_of_knowledge = 4;
278 | optional uint32 outpost = 5;
279 | optional uint32 other = 6;
280 | }
281 |
282 | optional uint32 account_id = 1;
283 | optional uint32 player_slot = 2;
284 | optional bytes position_stream = 3;
285 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.CombatSegment combat_segments = 4;
286 | repeated string damage_unit_names = 5;
287 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player.BuffRecord buff_records = 6;
288 | repeated float graph_kills = 7;
289 | repeated float graph_deaths = 8;
290 | repeated float graph_assists = 9;
291 | repeated float graph_lasthits = 10;
292 | repeated float graph_denies = 11;
293 | optional dota.CDOTAMatchPrivateMetadata.Team.Player.GoldReceived gold_received = 12;
294 | optional dota.CDOTAMatchPrivateMetadata.Team.Player.XPReceived xp_received = 13;
295 | }
296 |
297 | message Building {
298 | optional string unit_name = 1;
299 | optional uint32 position_quant_x = 2;
300 | optional uint32 position_quant_y = 3;
301 | optional float death_time = 4;
302 | }
303 |
304 | optional uint32 dota_team = 1;
305 | repeated dota.CDOTAMatchPrivateMetadata.Team.Player players = 2;
306 | repeated dota.CDOTAMatchPrivateMetadata.Team.Building buildings = 3;
307 | }
308 |
309 | repeated dota.CDOTAMatchPrivateMetadata.Team teams = 1;
310 | repeated float graph_win_probability = 2;
311 | repeated dota.CDOTAMatchPrivateMetadata.StringName string_names = 3;
312 | }
313 |
314 | message CMsgDOTADPCMatch {
315 | optional dota.CMsgDOTAMatch match = 1;
316 | optional dota.CDOTAMatchMetadata metadata = 2;
317 | }
318 |
--------------------------------------------------------------------------------
/protobufs/econ_shared_enums.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | option optimize_for = SPEED;
4 | option py_generic_services = false;
5 |
6 | enum EGCEconBaseMsg {
7 | k_EMsgGCGenericResult = 2579;
8 | }
9 |
10 | enum EGCMsgResponse {
11 | k_EGCMsgResponseOK = 0;
12 | k_EGCMsgResponseDenied = 1;
13 | k_EGCMsgResponseServerError = 2;
14 | k_EGCMsgResponseTimeout = 3;
15 | k_EGCMsgResponseInvalid = 4;
16 | k_EGCMsgResponseNoMatch = 5;
17 | k_EGCMsgResponseUnknownError = 6;
18 | k_EGCMsgResponseNotLoggedOn = 7;
19 | k_EGCMsgFailedToCreate = 8;
20 | }
21 |
22 | enum EGCPartnerRequestResponse {
23 | k_EPartnerRequestOK = 1;
24 | k_EPartnerRequestBadAccount = 2;
25 | k_EPartnerRequestNotLinked = 3;
26 | k_EPartnerRequestUnsupportedPartnerType = 4;
27 | }
28 |
29 | enum EGCMsgUseItemResponse {
30 | k_EGCMsgUseItemResponse_ItemUsed = 0;
31 | k_EGCMsgUseItemResponse_GiftNoOtherPlayers = 1;
32 | k_EGCMsgUseItemResponse_ServerError = 2;
33 | k_EGCMsgUseItemResponse_MiniGameAlreadyStarted = 3;
34 | k_EGCMsgUseItemResponse_ItemUsed_ItemsGranted = 4;
35 | k_EGCMsgUseItemResponse_DropRateBonusAlreadyGranted = 5;
36 | k_EGCMsgUseItemResponse_NotInLowPriorityPool = 6;
37 | k_EGCMsgUseItemResponse_NotHighEnoughLevel = 7;
38 | k_EGCMsgUseItemResponse_EventNotActive = 8;
39 | k_EGCMsgUseItemResponse_ItemUsed_EventPointsGranted = 9;
40 | k_EGCMsgUseItemResponse_MissingRequirement = 10;
41 | k_EGCMsgUseItemResponse_EmoticonUnlock_NoNew = 11;
42 | k_EGCMsgUseItemResponse_EmoticonUnlock_Complete = 12;
43 | k_EGCMsgUseItemResponse_ItemUsed_Compendium = 13;
44 | }
45 |
46 | message CMsgGenericResult {
47 | optional uint32 eresult = 1 [default = 2];
48 | optional string debug_message = 2;
49 | }
50 |
--------------------------------------------------------------------------------
/protobufs/gcsdk_gcmessages.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | import "steammessages.proto";
4 |
5 | option optimize_for = SPEED;
6 | option py_generic_services = false;
7 |
8 | enum ESourceEngine {
9 | k_ESE_Source1 = 0;
10 | k_ESE_Source2 = 1;
11 | }
12 |
13 | enum PartnerAccountType {
14 | PARTNER_NONE = 0;
15 | PARTNER_PERFECT_WORLD = 1;
16 | PARTNER_INVALID = 3;
17 | }
18 |
19 | enum GCConnectionStatus {
20 | GCConnectionStatus_HAVE_SESSION = 0;
21 | GCConnectionStatus_GC_GOING_DOWN = 1;
22 | GCConnectionStatus_NO_SESSION = 2;
23 | GCConnectionStatus_NO_SESSION_IN_LOGON_QUEUE = 3;
24 | GCConnectionStatus_NO_STEAM = 4;
25 | GCConnectionStatus_SUSPENDED = 5;
26 | GCConnectionStatus_STEAM_GOING_DOWN = 6;
27 | }
28 |
29 | message CExtraMsgBlock {
30 | optional uint32 msg_type = 1;
31 | optional bytes contents = 2;
32 | optional uint64 msg_key = 3;
33 | optional bool is_compressed = 4;
34 | }
35 |
36 | message CMsgGCAssertJobData {
37 | optional string message_type = 1;
38 | optional bytes message_data = 2;
39 | }
40 |
41 | message CMsgGCConCommand {
42 | optional string command = 1;
43 | }
44 |
45 | message CMsgSDOAssert {
46 | message Request {
47 | repeated uint64 key = 1;
48 | optional string requesting_job = 2;
49 | }
50 |
51 | optional int32 sdo_type = 1;
52 | repeated dota.CMsgSDOAssert.Request requests = 2;
53 | }
54 |
55 | message CMsgSHA1Digest {
56 | required fixed64 block1 = 1;
57 | required fixed64 block2 = 2;
58 | required fixed32 block3 = 3;
59 | }
60 |
61 | message CMsgSOIDOwner {
62 | optional uint32 type = 1;
63 | optional uint64 id = 2;
64 | }
65 |
66 | message CMsgSOSingleObject {
67 | optional int32 type_id = 2;
68 | optional bytes object_data = 3;
69 | optional fixed64 version = 4;
70 | optional dota.CMsgSOIDOwner owner_soid = 5;
71 | optional uint32 service_id = 6;
72 | }
73 |
74 | message CMsgSOMultipleObjects {
75 | message SingleObject {
76 | option (msgpool_soft_limit) = 256;
77 | option (msgpool_hard_limit) = 1024;
78 |
79 | optional int32 type_id = 1;
80 | optional bytes object_data = 2;
81 | }
82 |
83 | repeated dota.CMsgSOMultipleObjects.SingleObject objects_modified = 2;
84 | optional fixed64 version = 3;
85 | repeated dota.CMsgSOMultipleObjects.SingleObject objects_added = 4;
86 | repeated dota.CMsgSOMultipleObjects.SingleObject objects_removed = 5;
87 | optional dota.CMsgSOIDOwner owner_soid = 6;
88 | optional uint32 service_id = 7;
89 | }
90 |
91 | message CMsgSOCacheSubscribed {
92 | message SubscribedType {
93 | optional int32 type_id = 1;
94 | repeated bytes object_data = 2;
95 | }
96 |
97 | repeated dota.CMsgSOCacheSubscribed.SubscribedType objects = 2;
98 | optional fixed64 version = 3;
99 | optional dota.CMsgSOIDOwner owner_soid = 4;
100 | optional uint32 service_id = 5;
101 | repeated uint32 service_list = 6;
102 | optional fixed64 sync_version = 7;
103 | }
104 |
105 | message CMsgSOCacheSubscribedUpToDate {
106 | optional fixed64 version = 1;
107 | optional dota.CMsgSOIDOwner owner_soid = 2;
108 | optional uint32 service_id = 3;
109 | repeated uint32 service_list = 4;
110 | optional fixed64 sync_version = 5;
111 | }
112 |
113 | message CMsgSOCacheUnsubscribed {
114 | optional dota.CMsgSOIDOwner owner_soid = 2;
115 | }
116 |
117 | message CMsgSOCacheSubscriptionCheck {
118 | optional fixed64 version = 2;
119 | optional dota.CMsgSOIDOwner owner_soid = 3;
120 | optional uint32 service_id = 4;
121 | repeated uint32 service_list = 5;
122 | optional fixed64 sync_version = 6;
123 | }
124 |
125 | message CMsgSOCacheSubscriptionRefresh {
126 | optional dota.CMsgSOIDOwner owner_soid = 2;
127 | }
128 |
129 | message CMsgSOCacheVersion {
130 | optional fixed64 version = 1;
131 | }
132 |
133 | message CMsgGCMultiplexMessage {
134 | optional uint32 msgtype = 1;
135 | optional bytes payload = 2;
136 | repeated fixed64 steamids = 3;
137 | }
138 |
139 | message CMsgGCToGCSubGCStarting {
140 | optional uint32 dir_index = 1;
141 | }
142 |
143 | message CGCToGCMsgMasterAck {
144 | message Process {
145 | optional uint32 dir_index = 1;
146 | repeated uint32 type_instances = 2;
147 | }
148 |
149 | optional uint32 dir_index = 1;
150 | optional string machine_name = 3;
151 | optional string process_name = 4;
152 | repeated dota.CGCToGCMsgMasterAck.Process directory = 6;
153 | }
154 |
155 | message CGCToGCMsgMasterAck_Response {
156 | optional int32 eresult = 1 [default = 2];
157 | }
158 |
159 | message CMsgGCToGCUniverseStartup {
160 | optional bool is_initial_startup = 1;
161 | }
162 |
163 | message CMsgGCToGCUniverseStartupResponse {
164 | optional int32 eresult = 1;
165 | }
166 |
167 | message CGCToGCMsgMasterStartupComplete {
168 | message GCInfo {
169 | optional uint32 dir_index = 1;
170 | optional string machine_name = 2;
171 | }
172 |
173 | repeated dota.CGCToGCMsgMasterStartupComplete.GCInfo gc_info = 1;
174 | }
175 |
176 | message CGCToGCMsgRouted {
177 | optional uint32 msg_type = 1;
178 | optional fixed64 sender_id = 2;
179 | optional bytes net_message = 3;
180 | }
181 |
182 | message CGCToGCMsgRoutedReply {
183 | optional uint32 msg_type = 1;
184 | optional bytes net_message = 2;
185 | }
186 |
187 | message CMsgGCUpdateSubGCSessionInfo {
188 | message CMsgUpdate {
189 | optional fixed64 steamid = 1;
190 | optional fixed32 ip = 2;
191 | optional bool trusted = 3;
192 | }
193 |
194 | repeated dota.CMsgGCUpdateSubGCSessionInfo.CMsgUpdate updates = 1;
195 | }
196 |
197 | message CMsgGCRequestSubGCSessionInfo {
198 | optional fixed64 steamid = 1;
199 | }
200 |
201 | message CMsgGCRequestSubGCSessionInfoResponse {
202 | optional fixed32 ip = 1;
203 | optional bool trusted = 2;
204 | optional uint32 port = 3;
205 | optional bool success = 4;
206 | }
207 |
208 | message CMsgSOCacheHaveVersion {
209 | optional dota.CMsgSOIDOwner soid = 1;
210 | optional fixed64 version = 2;
211 | optional uint32 service_id = 3;
212 | optional uint32 cached_file_version = 4;
213 | }
214 |
215 | message CMsgClientHello {
216 | optional uint32 version = 1;
217 | repeated dota.CMsgSOCacheHaveVersion socache_have_versions = 2;
218 | optional uint32 client_session_need = 3;
219 | optional dota.PartnerAccountType client_launcher = 4 [default = PARTNER_NONE];
220 | optional string secret_key = 5;
221 | optional uint32 client_language = 6;
222 | optional dota.ESourceEngine engine = 7 [default = k_ESE_Source1];
223 | optional bytes steamdatagram_login = 8;
224 | optional uint32 platform_id = 9;
225 | optional bytes game_msg = 10;
226 | optional int32 os_type = 11;
227 | optional uint32 render_system = 12;
228 | optional uint32 render_system_req = 13;
229 | optional uint32 screen_width = 14;
230 | optional uint32 screen_height = 15;
231 | optional uint32 screen_refresh = 16;
232 | optional uint32 render_width = 17;
233 | optional uint32 render_height = 18;
234 | optional uint32 swap_width = 19;
235 | optional uint32 swap_height = 20;
236 | optional bool is_steam_china = 22;
237 | optional string platform_name = 23;
238 | }
239 |
240 | message CMsgClientWelcome {
241 | message Location {
242 | optional float latitude = 1;
243 | optional float longitude = 2;
244 | optional string country = 3;
245 | }
246 |
247 | optional uint32 version = 1;
248 | optional bytes game_data = 2;
249 | repeated dota.CMsgSOCacheSubscribed outofdate_subscribed_caches = 3;
250 | repeated dota.CMsgSOCacheSubscriptionCheck uptodate_subscribed_caches = 4;
251 | optional dota.CMsgClientWelcome.Location location = 5;
252 | optional bytes save_game_key = 6;
253 | optional fixed32 item_schema_crc = 7;
254 | optional string items_game_url = 8;
255 | optional uint32 gc_socache_file_version = 9;
256 | optional string txn_country_code = 10;
257 | optional bytes game_data2 = 11;
258 | optional uint32 rtime32_gc_welcome_timestamp = 12;
259 | optional uint32 currency = 13;
260 | optional uint32 balance = 14;
261 | optional string balance_url = 15;
262 | optional bool has_accepted_china_ssa = 16;
263 | optional bool is_banned_steam_china = 17;
264 | optional dota.CExtraMsgBlock additional_welcome_msgs = 18;
265 | }
266 |
267 | message CMsgConnectionStatus {
268 | optional dota.GCConnectionStatus status = 1 [default = GCConnectionStatus_HAVE_SESSION];
269 | optional uint32 client_session_need = 2;
270 | optional int32 queue_position = 3;
271 | optional int32 queue_size = 4;
272 | optional int32 wait_seconds = 5;
273 | optional int32 estimated_wait_seconds_remaining = 6;
274 | }
275 |
276 | message CMsgGCToGCSOCacheSubscribe {
277 | message CMsgHaveVersions {
278 | optional uint32 service_id = 1;
279 | optional uint64 version = 2;
280 | }
281 |
282 | optional fixed64 subscriber = 1;
283 | optional fixed64 subscribe_to_id = 2;
284 | optional fixed64 sync_version = 3;
285 | repeated dota.CMsgGCToGCSOCacheSubscribe.CMsgHaveVersions have_versions = 4;
286 | optional uint32 subscribe_to_type = 5;
287 | }
288 |
289 | message CMsgGCToGCSOCacheUnsubscribe {
290 | optional fixed64 subscriber = 1;
291 | optional fixed64 unsubscribe_from_id = 2;
292 | optional uint32 unsubscribe_from_type = 3;
293 | }
294 |
295 | message CMsgGCClientPing {
296 | }
297 |
298 | message CMsgGCToGCForwardAccountDetails {
299 | optional fixed64 steamid = 1;
300 | optional dota.CGCSystemMsg_GetAccountDetails_Response account_details = 2;
301 | optional uint32 age_seconds = 3;
302 | }
303 |
304 | message CMsgGCToGCLoadSessionSOCache {
305 | optional uint32 account_id = 1;
306 | optional dota.CMsgGCToGCForwardAccountDetails forward_account_details = 2;
307 | }
308 |
309 | message CMsgGCToGCLoadSessionSOCacheResponse {
310 | }
311 |
312 | message CMsgGCToGCUpdateSessionStats {
313 | optional uint32 user_sessions = 1;
314 | optional uint32 server_sessions = 2;
315 | optional bool in_logon_surge = 3;
316 | }
317 |
318 | message CMsgGCToClientRequestDropped {
319 | }
320 |
321 | message CWorkshop_PopulateItemDescriptions_Request {
322 | message SingleItemDescription {
323 | optional uint32 gameitemid = 1;
324 | optional string item_description = 2;
325 | }
326 |
327 | message ItemDescriptionsLanguageBlock {
328 | optional string language = 1;
329 | repeated dota.CWorkshop_PopulateItemDescriptions_Request.SingleItemDescription descriptions = 2;
330 | }
331 |
332 | optional uint32 appid = 1;
333 | repeated dota.CWorkshop_PopulateItemDescriptions_Request.ItemDescriptionsLanguageBlock languages = 2;
334 | }
335 |
336 | message CWorkshop_GetContributors_Request {
337 | optional uint32 appid = 1;
338 | optional uint32 gameitemid = 2;
339 | }
340 |
341 | message CWorkshop_GetContributors_Response {
342 | repeated fixed64 contributors = 1;
343 | }
344 |
345 | message CWorkshop_SetItemPaymentRules_Request {
346 | message WorkshopItemPaymentRule {
347 | optional uint64 workshop_file_id = 1;
348 | optional float revenue_percentage = 2;
349 | optional string rule_description = 3;
350 | optional uint32 rule_type = 4 [default = 1];
351 | }
352 |
353 | message WorkshopDirectPaymentRule {
354 | optional uint64 workshop_file_id = 1;
355 | optional string rule_description = 2;
356 | }
357 |
358 | message PartnerItemPaymentRule {
359 | optional uint32 account_id = 1;
360 | optional float revenue_percentage = 2;
361 | optional string rule_description = 3;
362 | }
363 |
364 | optional uint32 appid = 1;
365 | optional uint32 gameitemid = 2;
366 | repeated dota.CWorkshop_SetItemPaymentRules_Request.WorkshopItemPaymentRule associated_workshop_files = 3;
367 | repeated dota.CWorkshop_SetItemPaymentRules_Request.PartnerItemPaymentRule partner_accounts = 4;
368 | optional bool validate_only = 5;
369 | optional bool make_workshop_files_subscribable = 6;
370 | optional dota.CWorkshop_SetItemPaymentRules_Request.WorkshopDirectPaymentRule associated_workshop_file_for_direct_payments = 7;
371 | }
372 |
373 | message CWorkshop_SetItemPaymentRules_Response {
374 | repeated string validation_errors = 1;
375 | }
376 |
377 | message CCommunity_ClanAnnouncementInfo {
378 | optional uint64 gid = 1;
379 | optional uint64 clanid = 2;
380 | optional uint64 posterid = 3;
381 | optional string headline = 4;
382 | optional uint32 posttime = 5;
383 | optional uint32 updatetime = 6;
384 | optional string body = 7;
385 | optional int32 commentcount = 8;
386 | repeated string tags = 9;
387 | optional int32 language = 10;
388 | optional bool hidden = 11;
389 | optional fixed64 forum_topic_id = 12;
390 | }
391 |
392 | message CCommunity_GetClanAnnouncements_Request {
393 | optional uint64 steamid = 1;
394 | optional uint32 offset = 2;
395 | optional uint32 count = 3;
396 | optional uint32 maxchars = 4;
397 | optional bool strip_html = 5;
398 | repeated string required_tags = 6;
399 | optional bool require_no_tags = 7;
400 | repeated uint32 language_preference = 8;
401 | optional bool hidden_only = 9;
402 | optional bool only_gid = 10;
403 | optional uint32 rtime_oldest_date = 11;
404 | optional bool include_hidden = 12;
405 | optional bool include_partner_events = 13;
406 | }
407 |
408 | message CCommunity_GetClanAnnouncements_Response {
409 | optional uint32 maxchars = 1;
410 | optional bool strip_html = 2;
411 | repeated dota.CCommunity_ClanAnnouncementInfo announcements = 3;
412 | }
413 |
414 | message CBroadcast_PostGameDataFrame_Request {
415 | optional uint32 appid = 1;
416 | optional fixed64 steamid = 2;
417 | optional fixed64 broadcast_id = 3;
418 | optional bytes frame_data = 4;
419 | }
420 |
421 | message CMsgSerializedSOCache {
422 | message TypeCache {
423 | optional uint32 type = 1;
424 | repeated bytes objects = 2;
425 | optional uint32 service_id = 3;
426 | }
427 |
428 | message Cache {
429 | message Version {
430 | optional uint32 service = 1;
431 | optional uint64 version = 2;
432 | }
433 |
434 | optional uint32 type = 1;
435 | optional uint64 id = 2;
436 | repeated dota.CMsgSerializedSOCache.Cache.Version versions = 3;
437 | repeated dota.CMsgSerializedSOCache.TypeCache type_caches = 4;
438 | }
439 |
440 | optional uint32 file_version = 1;
441 | repeated dota.CMsgSerializedSOCache.Cache caches = 2;
442 | optional uint32 gc_socache_file_version = 3;
443 | }
444 |
445 | message CMsgGCToClientPollConvarRequest {
446 | optional string convar_name = 1;
447 | optional uint32 poll_id = 2;
448 | }
449 |
450 | message CMsgGCToClientPollConvarResponse {
451 | optional uint32 poll_id = 1;
452 | optional string convar_value = 2;
453 | }
454 |
455 | message CGCMsgCompressedMsgToClient {
456 | optional uint32 msg_id = 1;
457 | optional bytes compressed_msg = 2;
458 | }
459 |
460 | message CMsgGCToGCMasterBroadcastMessage {
461 | optional uint32 users_per_second = 1;
462 | optional bool send_to_users = 2;
463 | optional bool send_to_servers = 3;
464 | optional uint32 msg_id = 4;
465 | optional bytes msg_data = 5;
466 | }
467 |
468 | message CMsgGCToGCMasterSubscribeToCache {
469 | optional uint32 soid_type = 1;
470 | optional fixed64 soid_id = 2;
471 | repeated uint32 account_ids = 3;
472 | repeated fixed64 steam_ids = 4;
473 | }
474 |
475 | message CMsgGCToGCMasterSubscribeToCacheResponse {
476 | }
477 |
478 | message CMsgGCToGCMasterSubscribeToCacheAsync {
479 | optional dota.CMsgGCToGCMasterSubscribeToCache subscribe_msg = 1;
480 | }
481 |
482 | message CMsgGCToGCMasterUnsubscribeFromCache {
483 | optional uint32 soid_type = 1;
484 | optional fixed64 soid_id = 2;
485 | repeated uint32 account_ids = 3;
486 | repeated fixed64 steam_ids = 4;
487 | }
488 |
489 | message CMsgGCToGCMasterDestroyCache {
490 | optional uint32 soid_type = 1;
491 | optional fixed64 soid_id = 2;
492 | }
493 |
--------------------------------------------------------------------------------
/protobufs/gcsystemmsgs.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | package dota;
3 | option optimize_for = SPEED;
4 | option py_generic_services = false;
5 |
6 | enum ESOMsg {
7 | k_ESOMsg_Create = 21;
8 | k_ESOMsg_Update = 22;
9 | k_ESOMsg_Destroy = 23;
10 | k_ESOMsg_CacheSubscribed = 24;
11 | k_ESOMsg_CacheUnsubscribed = 25;
12 | k_ESOMsg_UpdateMultiple = 26;
13 | k_ESOMsg_CacheSubscriptionRefresh = 28;
14 | k_ESOMsg_CacheSubscribedUpToDate = 29;
15 | }
16 |
17 | enum EGCBaseClientMsg {
18 | k_EMsgGCPingRequest = 3001;
19 | k_EMsgGCPingResponse = 3002;
20 | k_EMsgGCToClientPollConvarRequest = 3003;
21 | k_EMsgGCToClientPollConvarResponse = 3004;
22 | k_EMsgGCCompressedMsgToClient = 3005;
23 | k_EMsgGCCompressedMsgToClient_Legacy = 523;
24 | k_EMsgGCToClientRequestDropped = 3006;
25 | k_EMsgGCClientWelcome = 4004;
26 | k_EMsgGCServerWelcome = 4005;
27 | k_EMsgGCClientHello = 4006;
28 | k_EMsgGCServerHello = 4007;
29 | k_EMsgGCClientConnectionStatus = 4009;
30 | k_EMsgGCServerConnectionStatus = 4010;
31 | }
32 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | enum34==1.1.2; python_version < '3.4'
2 | gevent>=1.3.0
3 | protobuf>=3.0.0
4 | steam[client]~=1.0
5 | gevent-eventemitter~=2.1
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from setuptools import setup, find_packages
4 | from codecs import open
5 | from os import path
6 | import sys
7 |
8 | here = path.abspath(path.dirname(__file__))
9 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
10 | long_description = f.read()\
11 | .replace('.io/en/latest/', '.io/en/stable/')\
12 | .replace('?badge=latest', '?badge=stable')\
13 | .replace('projects/dota2/badge/?version=latest', 'projects/dota2/badge/?version=stable')
14 | with open(path.join(here, 'dota2/__init__.py'), encoding='utf-8') as f:
15 | __version__ = f.readline().split('"')[1]
16 |
17 | install_requires = [
18 | 'steam[client]~=1.0',
19 | 'gevent-eventemitter~=2.1',
20 | 'gevent>=1.3.0',
21 | 'protobuf>=3.0.0',
22 | ]
23 |
24 | if sys.version_info < (3, 4):
25 | install_requires.append('enum34>=1.0.4')
26 |
27 | setup(
28 | name='dota2',
29 | version=__version__,
30 | description='Module for interacting Dota2\'s Game Coordinator',
31 | long_description=long_description,
32 | url='https://github.com/ValvePython/dota2',
33 | author="Rossen Georgiev",
34 | author_email='rossen@rgp.io',
35 | license='MIT',
36 | classifiers=[
37 | 'Development Status :: 4 - Beta',
38 | 'Intended Audience :: Developers',
39 | 'License :: OSI Approved :: MIT License',
40 | 'Topic :: Software Development :: Libraries :: Python Modules',
41 | 'Natural Language :: English',
42 | 'Operating System :: OS Independent',
43 | 'Programming Language :: Python :: 2.7',
44 | 'Programming Language :: Python :: 3.4',
45 | 'Programming Language :: Python :: 3.5',
46 | 'Programming Language :: Python :: 3.6',
47 | 'Programming Language :: Python :: 3.7',
48 | 'Programming Language :: Python :: 3.8',
49 | ],
50 | keywords='valve steam steamid api webapi',
51 | packages=['dota2'] + ['dota2.'+x for x in find_packages(where='dota2')],
52 | install_requires=install_requires,
53 | zip_safe=True,
54 | )
55 |
--------------------------------------------------------------------------------