├── tests ├── __init__.py ├── data │ └── test.dem └── test_demo.py ├── skadi ├── io │ ├── __init__.py │ ├── unpacker │ │ ├── __init__.py │ │ ├── string_table.py │ │ ├── entity.py │ │ ├── cEntity.pyx │ │ ├── prop.py │ │ └── cProp.pyx │ ├── cBitstream.pxd │ ├── protobuf │ │ ├── __init__.py │ │ ├── demo.py │ │ └── packet.py │ ├── bitstream.py │ └── cBitstream.pyx ├── engine │ ├── __init__.py │ ├── dt │ │ ├── __init__.py │ │ ├── consts.pxd │ │ ├── consts.py │ │ ├── send.py │ │ ├── recv.py │ │ ├── cRecv.pyx │ │ └── prop.py │ ├── string_table.py │ ├── game_event.py │ ├── modifiers.py │ ├── world.py │ └── user_message.py ├── index │ ├── demo │ │ ├── __init__.py │ │ ├── epilogue.py │ │ └── prologue.py │ ├── embed │ │ ├── __init__.py │ │ ├── send_tables.py │ │ └── packet.py │ └── __init__.py ├── protoc │ ├── __init__.py │ ├── dota_modifiers_pb2.py │ ├── dota_commonmessages_pb2.py │ └── networkbasetypes_pb2.py ├── __init__.py └── demo.py ├── .gitignore ├── setup_basic.py ├── LICENSE ├── setup.py ├── protobuf ├── dota_modifiers.proto ├── dota_commonmessages.proto ├── networkbasetypes.proto ├── demo.proto ├── usermessages.proto ├── netmessages.proto ├── dota_usermessages.proto └── ai_activity.proto ├── bin └── skadi └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skadi/io/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skadi/engine/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skadi/engine/dt/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skadi/index/demo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skadi/protoc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skadi/index/embed/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | demos 4 | *.pyc 5 | *.so 6 | *.c 7 | -------------------------------------------------------------------------------- /tests/data/test.dem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onethirtyfive/skadi/HEAD/tests/data/test.dem -------------------------------------------------------------------------------- /skadi/index/demo/epilogue.py: -------------------------------------------------------------------------------- 1 | from skadi import index as i 2 | from skadi.protoc import demo_pb2 as pb_d 3 | 4 | 5 | def construct(io, tick=0): 6 | return Index(((p, m) for p, m in iter(io))) 7 | 8 | 9 | class EpilogueIndex(i.Index): 10 | def __init__(self, iterable): 11 | super(EpilogueIndex, self).__init__(iterable) 12 | 13 | @property 14 | def dem_file_info(self): 15 | kind = pb_d.DEM_FileInfo 16 | p, m = self.find(kind) 17 | return p, d_io.parse(kind, p.compressed, m) 18 | -------------------------------------------------------------------------------- /skadi/io/unpacker/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from skadi.io import cBitstream as b_io 3 | except ImportError: 4 | from skadi.io import bitstream as b_io 5 | 6 | 7 | class UnpackComplete(RuntimeError): 8 | pass 9 | 10 | 11 | class Unpacker(object): 12 | def __init__(self, bitstream): 13 | self.bitstream = bitstream 14 | 15 | def __iter__(self): 16 | def unpack(): 17 | try: 18 | return self.unpack() 19 | except UnpackComplete: 20 | raise StopIteration() 21 | 22 | return iter(unpack, None) 23 | -------------------------------------------------------------------------------- /skadi/io/cBitstream.pxd: -------------------------------------------------------------------------------- 1 | from libc.stdint cimport int64_t, uint64_t, uint32_t 2 | from cpython cimport array 3 | 4 | cdef class Bitstream: 5 | cdef public int pos 6 | cdef int data_n 7 | cdef uint32_t *data 8 | 9 | cdef uint32_t _read(Bitstream self, int length) 10 | cdef void _read_data(Bitstream self, array.array[unsigned int] arr) 11 | cdef _dealloc(Bitstream self) 12 | cdef bytes _read_long(Bitstream self, int length) 13 | cdef bytes _read_string(Bitstream self, int length) 14 | cdef uint64_t _read_varint(Bitstream self) 15 | -------------------------------------------------------------------------------- /skadi/index/embed/send_tables.py: -------------------------------------------------------------------------------- 1 | from skadi import index as i 2 | from skadi.io.protobuf import packet as p_io 3 | from skadi.protoc import netmessages_pb2 as pb_n 4 | 5 | 6 | def construct(io, tick=0): 7 | return SendTablesIndex(((p, m) for p, m in iter(io))) 8 | 9 | 10 | class SendTablesIndex(i.Index): 11 | def __init__(self, iterable): 12 | super(SendTablesIndex, self).__init__(iterable) 13 | 14 | @property 15 | def all_svc_send_table(self): 16 | kind = pb_n.svc_SendTable 17 | return ((p, p_io.parse(kind, m)) for p, m in self.find_all(kind)) 18 | -------------------------------------------------------------------------------- /tests/test_demo.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import io as _io 4 | import os 5 | import sys 6 | 7 | pwd = os.path.dirname(__file__) 8 | root = os.path.abspath(os.path.join(pwd, '..')) 9 | sys.path.append(root) 10 | 11 | from skadi import * 12 | from skadi import demo 13 | 14 | DEMO_FILE_PATH = os.path.abspath(os.path.join(pwd, 'data/test.dem')) 15 | 16 | 17 | class TestDemo(unittest.TestCase): 18 | demo = None 19 | 20 | @classmethod 21 | def setUpClass(cls): 22 | # Cache demo for re-use in multiple tests 23 | cls.demo = demo.construct(DEMO_FILE_PATH) 24 | 25 | def test_demo_construct(self): 26 | assert self.demo 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /skadi/engine/string_table.py: -------------------------------------------------------------------------------- 1 | import collections as c 2 | import copy 3 | 4 | 5 | def construct(*args): 6 | return StringTable(*args) 7 | 8 | 9 | class StringTable(object): 10 | def __init__(self, name, ent_bits, sz_fixed, sz_bits, ents): 11 | self.name = name 12 | self.entry_bits = ent_bits 13 | self.size_fixed = sz_fixed 14 | self.size_bits = sz_bits 15 | self.update_all(ents) 16 | 17 | def get(self, name): 18 | return self.by_name[name] 19 | 20 | def update_all(self, entries): 21 | self.by_index = c.OrderedDict() 22 | self.by_name = c.OrderedDict() 23 | 24 | [self.update(entry) for entry in entries] 25 | 26 | def update(self, entry): 27 | i, n, d = entry 28 | 29 | self.by_index[i] = (n, d) 30 | if n: 31 | self.by_name[n] = (i, d) 32 | -------------------------------------------------------------------------------- /skadi/engine/dt/consts.pxd: -------------------------------------------------------------------------------- 1 | cdef: 2 | public enum Types: 3 | INT = 0 4 | FLOAT = 1 5 | VECTOR = 2 6 | VECTORXY = 3 7 | STRING = 4 8 | ARRAY = 5 9 | DATATABLE = 6 10 | INT64 = 7 11 | 12 | public enum Flags: 13 | UNSIGNED = 1 << 0 14 | COORD = 1 << 1 15 | NOSCALE = 1 << 2 16 | ROUNDDOWN = 1 << 3 17 | ROUNDUP = 1 << 4 18 | NORMAL = 1 << 5 19 | EXCLUDE = 1 << 6 20 | XYZE = 1 << 7 21 | INSIDEARRAY = 1 << 8 22 | PROXYALWAYS = 1 << 9 23 | VECTORELEM = 1 << 10 24 | COLLAPSIBLE = 1 << 11 25 | COORDMP = 1 << 12 26 | COORDMPLOWPRECISION = 1 << 13 27 | COORDMPINTEGRAL = 1 << 14 28 | CELLCOORD = 1 << 15 29 | CELLCOORDLOWPRECISION = 1 << 16 30 | CELLCOORDINTEGRAL = 1 << 17 31 | CHANGESOFTEN = 1 << 18 32 | ENCODEDAGAINSTTICKCOUNT = 1 << 19 -------------------------------------------------------------------------------- /skadi/engine/dt/consts.py: -------------------------------------------------------------------------------- 1 | from skadi import enum 2 | 3 | Flag = enum( 4 | Unsigned = 1 << 0, Coord = 1 << 1, 5 | NoScale = 1 << 2, RoundDown = 1 << 3, 6 | RoundUp = 1 << 4, Normal = 1 << 5, 7 | Exclude = 1 << 6, XYZE = 1 << 7, 8 | InsideArray = 1 << 8, ProxyAlways = 1 << 9, 9 | VectorElem = 1 << 10, Collapsible = 1 << 11, 10 | CoordMP = 1 << 12, CoordMPLowPrecision = 1 << 13, 11 | CoordMPIntegral = 1 << 14, CellCoord = 1 << 15, 12 | CellCoordLowPrecision = 1 << 16, CellCoordIntegral = 1 << 17, 13 | ChangesOften = 1 << 18, EncodedAgainstTickcount = 1 << 19 14 | ) 15 | 16 | Type = enum( 17 | Int = 0, Float = 1, Vector = 2, 18 | VectorXY = 3, String = 4, Array = 5, 19 | DataTable = 6, Int64 = 7 20 | ) 21 | -------------------------------------------------------------------------------- /skadi/index/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import collections 4 | import itertools as it 5 | 6 | 7 | def construct(*args): 8 | return Index(*args) 9 | 10 | 11 | class Index(object): 12 | def __init__(self, iterable): 13 | self.entries = collections.OrderedDict(list(iterable)) 14 | 15 | def __iter__(self): 16 | return self.entries.iteritems() 17 | 18 | def find(self, kind): 19 | return next(it.ifilter(lambda (p, _): p.kind == kind, self)) 20 | 21 | def find_all(self, kind): 22 | return it.ifilter(lambda (p, _): p.kind == kind, self) 23 | 24 | def find_behind(self, tell): 25 | return it.ifilter(lambda (p, _): p.tell < tell, self) 26 | 27 | def find_at(self, tell): 28 | return it.ifilter(lambda (p, _): p.tell == tell, self) 29 | 30 | def find_ahead(self, tell): 31 | return it.ifilter(lambda (p, _): p.tell > tell, self) 32 | 33 | def find_between(self, start, stop): 34 | return it.ifilter(lambda (p, _): start < p.tell < stop, self) 35 | -------------------------------------------------------------------------------- /skadi/engine/game_event.py: -------------------------------------------------------------------------------- 1 | import collections as c 2 | 3 | 4 | def humanize(game_event, game_event_list): 5 | _type, data = game_event 6 | name, keys = game_event_list[_type] 7 | 8 | attrs = c.OrderedDict() 9 | 10 | for i, (k_type, k_name) in enumerate(keys): 11 | attrs[k_name] = data[i] 12 | 13 | return name, attrs 14 | 15 | 16 | def parse(pbmsg, game_event_list): 17 | _, keys = game_event_list[pbmsg.eventid] 18 | 19 | attrs = [] 20 | 21 | for i, (k_type, k_name) in enumerate(keys): 22 | key = pbmsg.keys[i] 23 | if k_type == 1: 24 | value = key.val_string 25 | elif k_type == 2: 26 | value = key.val_float 27 | elif k_type == 3: 28 | value = key.val_long 29 | elif k_type == 4: 30 | value = key.val_short 31 | elif k_type == 5: 32 | value = key.val_byte 33 | elif k_type == 6: 34 | value = key.val_bool 35 | elif k_type == 7: 36 | value = key.val_uint64 37 | 38 | attrs.append(value) 39 | 40 | return pbmsg.eventid, attrs 41 | -------------------------------------------------------------------------------- /setup_basic.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='skadi', 5 | version='0.1', 6 | description='A Dota 2 replay parser.', 7 | long_description=open('README.md').read(), 8 | author='Joshua Morris', 9 | author_email='joshua.a.morris@gmail.com', 10 | zip_safe=True, 11 | url='https://github.com/onethirtyfive/skadi', 12 | license='MIT', 13 | packages=find_packages(), 14 | keywords='dota replay', 15 | install_requires=[ 16 | 'protobuf==2.5', 17 | 'python-snappy==0.5', 18 | 'bitstring==3.1.2', 19 | ], 20 | classifiers=[ 21 | 'Intended Audience :: Developers', 22 | 'Operating System :: OS Independent', 23 | 'License :: OSI Approved :: MIT License', 24 | 'Programming Language :: Python', 25 | 'Topic :: Software Development :: Libraries :: Python Modules', 26 | "Programming Language :: Python :: 2.6", 27 | "Programming Language :: Python :: 2.7", 28 | "Topic :: Database", 29 | ] 30 | ) -------------------------------------------------------------------------------- /skadi/io/protobuf/__init__.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | from skadi.protoc import demo_pb2 as pb_d 4 | 5 | 6 | def parse(impl, message): 7 | pbmsg = impl() 8 | pbmsg.ParseFromString(message) 9 | return pbmsg 10 | 11 | 12 | class ProtobufIO(object): 13 | class InvalidVarint(Exception): 14 | pass 15 | 16 | vi_max_bytes, vi_shift = 5, 7 17 | vi_mask = (1 << 32) - 1 18 | 19 | def __init__(self, _io): 20 | self.io = _io 21 | 22 | def __iter__(self): 23 | return iter(self.read, None) 24 | 25 | # via Google protobuf library 26 | def read_varint(self): 27 | size, value, shift = 0, 0, 0 28 | 29 | while True: 30 | try: 31 | byte = self.io.read(1) 32 | assert len(byte) == 1 33 | except AssertionError: 34 | raise EOFError() 35 | 36 | size += 1 37 | value |= (ord(byte) & 0x7f) << shift 38 | shift += ProtobufIO.vi_shift 39 | 40 | if not (ord(byte) & 0x80): 41 | value &= ProtobufIO.vi_mask 42 | return value 43 | 44 | if shift >= ProtobufIO.vi_shift * ProtobufIO.vi_max_bytes: 45 | raise ProtobufIO.InvalidVarint() 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Joshua Morris 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /skadi/engine/dt/send.py: -------------------------------------------------------------------------------- 1 | from skadi.engine.dt import prop 2 | 3 | 4 | def construct(*args): 5 | return SendTable(*args) 6 | 7 | 8 | class SendTable(object): 9 | def __init__(self, dt, props, is_end, needs_decoder): 10 | self.dt = dt 11 | self.props = list(props) 12 | self.is_end = is_end 13 | self.needs_decoder = needs_decoder 14 | 15 | def __repr__(self): 16 | cls = self.__class__.__name__ 17 | lenprops = len(self.props) 18 | return '<{0} {1} ({2} props)>'.format(cls, self.dt, lenprops) 19 | 20 | @property 21 | def baseclass(self): 22 | return next((p.dt for p in self.props if prop.test_baseclass(p)), None) 23 | 24 | @property 25 | def exclusions(self): 26 | def describe_exclusion(p): 27 | return (p.dt_name, p.var_name) 28 | return map(describe_exclusion, filter(prop.test_exclude, self.props)) 29 | 30 | @property 31 | def non_exclusion_props(self): 32 | return filter(prop.test_not_exclude, self.props) 33 | 34 | @property 35 | def dt_props(self): 36 | return filter(prop.test_data_table, self.non_exclusion_props) 37 | 38 | @property 39 | def non_dt_props(self): 40 | def test_eligible(p): 41 | return not prop.test_data_table(p) 42 | return filter(test_eligible, self.non_exclusion_props) 43 | -------------------------------------------------------------------------------- /skadi/index/demo/prologue.py: -------------------------------------------------------------------------------- 1 | from skadi import index as i 2 | from skadi.io.protobuf import demo as d_io 3 | from skadi.protoc import demo_pb2 as pb_d 4 | 5 | 6 | def construct(io, tick=0): 7 | iter_entries = iter(io) 8 | 9 | def advance(): 10 | p, m = next(iter_entries) 11 | if p.kind == pb_d.DEM_SyncTick: 12 | raise StopIteration() 13 | return (p, m) 14 | 15 | return Index(((p, m) for p, m in iter(advance, None))) 16 | 17 | 18 | class Index(i.Index): 19 | def __init__(self, iterable): 20 | super(Index, self).__init__(iterable) 21 | 22 | @property 23 | def dem_file_header(self): 24 | kind = pb_d.DEM_FileHeader 25 | p, m = self.find(kind) 26 | return p, d_io.parse(kind, p.compressed, m) 27 | 28 | @property 29 | def dem_class_info(self): 30 | kind = pb_d.DEM_ClassInfo 31 | p, m = self.find(kind) 32 | return p, d_io.parse(kind, p.compressed, m) 33 | 34 | @property 35 | def dem_send_tables(self): 36 | kind = pb_d.DEM_SendTables 37 | p, m = self.find(kind) 38 | return p, d_io.parse(kind, p.compressed, m) 39 | 40 | @property 41 | def all_dem_signon_packet(self): 42 | kind = pb_d.DEM_SignonPacket 43 | ee = self.find_all(kind) 44 | return ((p, d_io.parse(kind, p.compressed, m)) for p, m in ee) 45 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from Cython.Build import cythonize 3 | 4 | setup( 5 | name='skadi', 6 | version='0.1', 7 | description='A Dota 2 replay parser.', 8 | long_description=open('README.md').read(), 9 | author='Joshua Morris', 10 | author_email='joshua.a.morris@gmail.com', 11 | zip_safe=True, 12 | url='https://github.com/onethirtyfive/skadi', 13 | license='MIT', 14 | packages=find_packages(), 15 | keywords='dota replay', 16 | install_requires=[ 17 | 'protobuf==2.5', 18 | 'python-snappy==0.5', 19 | 'bitstring==3.1.2', 20 | 'cython>=0.19.1' 21 | ], 22 | classifiers=[ 23 | 'Intended Audience :: Developers', 24 | 'Operating System :: OS Independent', 25 | 'License :: OSI Approved :: MIT License', 26 | 'Programming Language :: Python', 27 | 'Topic :: Software Development :: Libraries :: Python Modules', 28 | "Programming Language :: Python :: 2.6", 29 | "Programming Language :: Python :: 2.7", 30 | "Topic :: Database", 31 | ], 32 | ext_modules=cythonize([ 33 | "skadi/io/cBitstream.pyx", 34 | "skadi/io/unpacker/cProp.pyx", 35 | "skadi/io/unpacker/cEntity.pyx", 36 | "skadi/engine/dt/cRecv.pyx", 37 | ]) 38 | ) 39 | -------------------------------------------------------------------------------- /skadi/engine/dt/recv.py: -------------------------------------------------------------------------------- 1 | from skadi.engine.dt import prop as dt_prop 2 | 3 | 4 | def construct(dt, props): 5 | rt = RecvTable(dt, props) 6 | priorities = [64] 7 | 8 | for p in rt.props: 9 | gen = (pr for pr in priorities if pr == p.priority) 10 | if not next(gen, None): 11 | priorities.append(p.priority) 12 | 13 | priorities, p_offset = sorted(priorities), 0 14 | 15 | for pr in priorities: 16 | proplen = len(rt.props) 17 | hole = p_offset 18 | cursor = p_offset 19 | 20 | while cursor < proplen: 21 | p = rt.props[cursor] 22 | is_co = (pr == 64 and (p.flags & dt_prop.Flag.ChangesOften)) 23 | 24 | if is_co or p.priority == pr: 25 | rt = rt.swap(rt.props[hole], p) 26 | hole += 1 27 | p_offset += 1 28 | cursor += 1 29 | 30 | return rt 31 | 32 | 33 | class RecvTable(object): 34 | def __init__(self, dt, props): 35 | self.dt = dt 36 | self.props = props 37 | 38 | def __repr__(self): 39 | cls = self.__class__.__name__ 40 | lenprops = len(self.props) 41 | return '<{0} {1} ({2} props)>'.format(cls, self.dt, lenprops) 42 | 43 | def swap(self, first, second): 44 | l = list(self.props) 45 | i = l.index(first) 46 | j = l.index(second) 47 | l[i], l[j] = l[j], l[i] 48 | return RecvTable(self.dt, l) 49 | -------------------------------------------------------------------------------- /protobuf/dota_modifiers.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | import "networkbasetypes.proto"; 3 | 4 | enum DOTA_MODIFIER_ENTRY_TYPE { 5 | DOTA_MODIFIER_ENTRY_TYPE_ACTIVE = 1; 6 | DOTA_MODIFIER_ENTRY_TYPE_REMOVED = 2; 7 | } 8 | 9 | message CDOTAModifierBuffTableEntry { 10 | required .DOTA_MODIFIER_ENTRY_TYPE entry_type = 1 [default = DOTA_MODIFIER_ENTRY_TYPE_ACTIVE]; 11 | required int32 parent = 2; 12 | required int32 index = 3; 13 | required int32 serial_num = 4; 14 | optional int32 name = 5; 15 | optional int32 ability_level = 6; 16 | optional int32 stack_count = 7; 17 | optional float creation_time = 8; 18 | optional float duration = 9 [default = -1]; 19 | optional int32 caster = 10; 20 | optional int32 ability = 11; 21 | optional int32 armor = 12; 22 | optional float fade_time = 13; 23 | optional bool subtle = 14; 24 | optional float channel_time = 15; 25 | optional .CMsgVector v_start = 16; 26 | optional .CMsgVector v_end = 17; 27 | optional string portal_loop_appear = 18; 28 | optional string portal_loop_disappear = 19; 29 | optional string hero_loop_appear = 20; 30 | optional string hero_loop_disappear = 21; 31 | optional int32 movement_speed = 22; 32 | optional bool aura = 23; 33 | optional int32 activity = 24; 34 | optional int32 damage = 25; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /skadi/engine/dt/cRecv.pyx: -------------------------------------------------------------------------------- 1 | from skadi.engine.dt import prop as dt_prop 2 | 3 | 4 | def construct(dt, props): 5 | return _construct(dt, props) 6 | 7 | cdef _construct(object dt, object props): 8 | cdef RecvTable rt 9 | cdef object properties, p 10 | 11 | rt = RecvTable(dt, props) 12 | priorities = set([64]) 13 | 14 | for p in rt.props: 15 | priorities.add(p.priority) 16 | 17 | priorities = sorted(list(priorities)) 18 | cdef int p_offset = 0 19 | 20 | cdef int pr, hole, cursor, proplen 21 | cdef object is_co 22 | 23 | for pr in priorities: 24 | proplen = len(rt.props) 25 | hole = p_offset 26 | cursor = p_offset 27 | 28 | while cursor < proplen: 29 | p = rt.props[cursor] 30 | is_co = (pr == 64 and (p.flags & dt_prop.Flag.ChangesOften)) 31 | 32 | if is_co or p.priority == pr: 33 | rt.props[hole], rt.props[cursor] = rt.props[cursor], rt.props[hole] 34 | hole += 1 35 | p_offset += 1 36 | cursor += 1 37 | 38 | return rt 39 | 40 | 41 | cdef class RecvTable(object): 42 | cdef public object dt, props 43 | 44 | def __init__(self, dt, props): 45 | self.dt = dt 46 | self.props = props 47 | 48 | def __repr__(self): 49 | cls = self.__class__.__name__ 50 | lenprops = len(self.props) 51 | return '<{0} {1} ({2} props)>'.format(cls, self.dt, lenprops) -------------------------------------------------------------------------------- /protobuf/dota_commonmessages.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | import "networkbasetypes.proto"; 3 | 4 | enum EDOTAChatWheelMessage { 5 | k_EDOTA_CW_Ok = 0; 6 | k_EDOTA_CW_Care = 1; 7 | k_EDOTA_CW_GetBack = 2; 8 | k_EDOTA_CW_NeedWards = 3; 9 | k_EDOTA_CW_Stun = 4; 10 | k_EDOTA_CW_Help = 5; 11 | k_EDOTA_CW_Push = 6; 12 | k_EDOTA_CW_GoodJob = 7; 13 | k_EDOTA_CW_Missing = 8; 14 | k_EDOTA_CW_Missing_Top = 9; 15 | k_EDOTA_CW_Missing_Mid = 10; 16 | k_EDOTA_CW_Missing_Bottom = 11; 17 | } 18 | 19 | enum EDOTAStatPopupTypes { 20 | k_EDOTA_SPT_Textline = 0; 21 | k_EDOTA_SPT_Basic = 1; 22 | k_EDOTA_SPT_Poll = 2; 23 | } 24 | 25 | message CDOTAMsg_LocationPing { 26 | optional int32 x = 1; 27 | optional int32 y = 2; 28 | optional int32 target = 3; 29 | optional bool direct_ping = 4; 30 | optional int32 type = 5; 31 | } 32 | 33 | message CDOTAMsg_ItemAlert { 34 | optional int32 x = 1; 35 | optional int32 y = 2; 36 | optional int32 itemid = 3; 37 | } 38 | 39 | message CDOTAMsg_MapLine { 40 | optional int32 x = 1; 41 | optional int32 y = 2; 42 | optional bool initial = 3; 43 | } 44 | 45 | message CDOTAMsg_WorldLine { 46 | optional int32 x = 1; 47 | optional int32 y = 2; 48 | optional int32 z = 3; 49 | optional bool initial = 4; 50 | optional bool end = 5; 51 | } 52 | 53 | message CDOTAMsg_SendStatPopup { 54 | optional .EDOTAStatPopupTypes style = 1 [default = k_EDOTA_SPT_Textline]; 55 | repeated string stat_strings = 2; 56 | repeated int32 stat_images = 3; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /bin/skadi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import io as _io 4 | import optparse 5 | import os 6 | import sys 7 | 8 | pwd = os.path.dirname(__file__) 9 | root = os.path.abspath(os.path.join(pwd, '..')) 10 | sys.path.append(root) 11 | 12 | from skadi import demo as d 13 | 14 | usage = "skadi [FILE] \n\nExample: 'bin/%prog tests/data/test.dem'" 15 | option_parser = optparse.OptionParser(usage = usage) 16 | (options, args) = option_parser.parse_args() 17 | 18 | if len(args) < 1: 19 | print "No arguments provided. Run skadi -h for example usage." 20 | 21 | for abspath in args: 22 | print 'opening {0}...'.format(os.path.basename(abspath)) 23 | 24 | demo = d.construct(abspath) 25 | 26 | file_info = demo.file_info 27 | print 'playback info:' 28 | print '- time: {}'.format(file_info.playback_time) 29 | print '- ticks: {}'.format(file_info.playback_ticks) 30 | print '- frames: {}'.format(file_info.playback_frames) 31 | 32 | print 'player summary:' 33 | for pi in file_info.game_info.dota.player_info: 34 | player_name = pi.player_name.encode('UTF-8') 35 | hero_name = pi.hero_name.encode('UTF-8') 36 | print '- {} ({})'.format(player_name, hero_name) 37 | 38 | for game in demo.stream(tick=5000): 39 | tick, user_msgs, game_evts, world, modifiers = game 40 | 41 | print 't {}'.format(tick) 42 | 43 | # Print all active modifiers at every tick. 44 | for ehandle, m_list in modifiers: 45 | pretty = map(lambda (_, a): a['name'], m_list.items()) 46 | dt = world.fetch_recv_table(ehandle).dt 47 | print ' {dt} (#{eh}): {attrs}'.format(dt=dt, eh=ehandle, attrs=pretty) 48 | -------------------------------------------------------------------------------- /skadi/engine/dt/prop.py: -------------------------------------------------------------------------------- 1 | from skadi import enum 2 | from skadi.engine.dt.consts import Flag, Type 3 | 4 | test_baseclass = lambda prop: prop.name == 'baseclass' 5 | test_collapsible = lambda prop: prop.flags & Flag.Collapsible 6 | test_data_table = lambda prop: prop.type == Type.DataTable 7 | test_exclude = lambda prop: prop.flags & Flag.Exclude 8 | test_inside_array = lambda prop: prop.flags & Flag.InsideArray 9 | test_not_exclude = lambda prop: prop.flags ^ Flag.Exclude 10 | 11 | def construct(*args): 12 | return Prop(*args) 13 | 14 | 15 | class Prop(object): 16 | DELEGATED = ( 17 | 'var_name', 'type', 'flags', 'num_elements', 18 | 'num_bits', 'dt_name', 'priority', 'low_value', 19 | 'high_value' 20 | ) 21 | 22 | def __init__(self, origin_dt, attributes): 23 | self.origin_dt = origin_dt 24 | for name in self.DELEGATED: 25 | setattr(self, name, attributes[name]) 26 | 27 | def __repr__(self): 28 | odt, vn, t = self.origin_dt, self.var_name, self._type() 29 | f = ','.join(self._flags()) if self.flags else '-' 30 | p = self.priority if self.priority < 128 else 128 31 | terse = ('num_bits', 'num_elements', 'dt_name') 32 | b, e, dt = map(lambda i: getattr(self, i) or '-', terse) 33 | 34 | _repr = "" 35 | return _repr.format(odt, vn, t, f, p, b, e, dt) 36 | 37 | def _type(self): 38 | for k, v in Type.tuples.items(): 39 | if self.type == v: 40 | return k.lower() 41 | 42 | def _flags(self): 43 | named_flags = [] 44 | for k, v in Flag.tuples.items(): 45 | if self.flags & v: 46 | named_flags.append(k.lower()) 47 | return named_flags 48 | -------------------------------------------------------------------------------- /protobuf/networkbasetypes.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | 3 | enum SIGNONSTATE { 4 | SIGNONSTATE_NONE = 0; 5 | SIGNONSTATE_CHALLENGE = 1; 6 | SIGNONSTATE_CONNECTED = 2; 7 | SIGNONSTATE_NEW = 3; 8 | SIGNONSTATE_PRESPAWN = 4; 9 | SIGNONSTATE_SPAWN = 5; 10 | SIGNONSTATE_FULL = 6; 11 | SIGNONSTATE_CHANGELEVEL = 7; 12 | } 13 | 14 | message CMsgVector { 15 | optional float x = 1; 16 | optional float y = 2; 17 | optional float z = 3; 18 | } 19 | 20 | message CMsgVector2D { 21 | optional float x = 1; 22 | optional float y = 2; 23 | } 24 | 25 | message CMsgQAngle { 26 | optional float x = 1; 27 | optional float y = 2; 28 | optional float z = 3; 29 | } 30 | 31 | message CSVCMsg_GameEvent { 32 | message key_t { 33 | optional int32 type = 1; 34 | optional string val_string = 2; 35 | optional float val_float = 3; 36 | optional int32 val_long = 4; 37 | optional int32 val_short = 5; 38 | optional int32 val_byte = 6; 39 | optional bool val_bool = 7; 40 | optional uint64 val_uint64 = 8; 41 | } 42 | 43 | optional string event_name = 1; 44 | optional int32 eventid = 2; 45 | repeated .CSVCMsg_GameEvent.key_t keys = 3; 46 | } 47 | 48 | message CSVCMsgList_GameEvents { 49 | message event_t { 50 | optional int32 tick = 1; 51 | optional .CSVCMsg_GameEvent event = 2; 52 | } 53 | 54 | repeated .CSVCMsgList_GameEvents.event_t events = 1; 55 | } 56 | 57 | message CSVCMsg_UserMessage { 58 | optional int32 msg_type = 1; 59 | optional bytes msg_data = 2; 60 | } 61 | 62 | message CSVCMsgList_UserMessages { 63 | message usermsg_t { 64 | optional int32 tick = 1; 65 | optional .CSVCMsg_UserMessage msg = 2; 66 | } 67 | 68 | repeated .CSVCMsgList_UserMessages.usermsg_t usermsgs = 1; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /skadi/index/embed/packet.py: -------------------------------------------------------------------------------- 1 | from skadi import index as i 2 | from skadi.io.protobuf import packet as p_io 3 | from skadi.protoc import netmessages_pb2 as pb_n 4 | 5 | 6 | def construct(io, tick=0): 7 | return PacketIndex(((p, m) for p, m in iter(io))) 8 | 9 | 10 | class PacketIndex(i.Index): 11 | def __init__(self, iterable): 12 | super(PacketIndex, self).__init__(iterable) 13 | 14 | # DEM_SignonPacket: 15 | 16 | @property 17 | def svc_game_event_list(self): 18 | kind = pb_n.svc_GameEventList 19 | p, m = self.find(kind) 20 | return p, p_io.parse(kind, m) 21 | 22 | @property 23 | def svc_server_info(self): 24 | kind = pb_n.svc_ServerInfo 25 | p, m = self.find(kind) 26 | return p, p_io.parse(kind, m) 27 | 28 | @property 29 | def svc_voice_init(self): 30 | kind = pb_n.svc_VoiceInit 31 | p, m = self.find(kind) 32 | return p, p_io.parse(kind, m) 33 | 34 | @property 35 | def all_svc_create_string_table(self): 36 | kind = pb_n.svc_CreateStringTable 37 | return ((p, p_io.parse(kind, m)) for p, m in self.find_all(kind)) 38 | 39 | # DEM_Packet: 40 | 41 | @property 42 | def net_tick(self): 43 | kind = pb_n.net_Tick 44 | p, m = self.find(kind) 45 | return p, p_io.parse(kind, m) 46 | 47 | @property 48 | def svc_packet_entities(self): 49 | kind = pb_n.svc_PacketEntities 50 | p, m = self.find(kind) 51 | return p, p_io.parse(kind, m) 52 | 53 | @property 54 | def all_svc_update_string_table(self): 55 | kind = pb_n.svc_UpdateStringTable 56 | return ((p, p_io.parse(kind, m)) for p, m in self.find_all(kind)) 57 | 58 | @property 59 | def all_svc_game_event(self): 60 | kind = pb_n.svc_GameEvent 61 | return ((p, p_io.parse(kind, m)) for p, m in self.find_all(kind)) 62 | 63 | @property 64 | def all_svc_user_message(self): 65 | kind = pb_n.svc_UserMessage 66 | return ((p, p_io.parse(kind, m)) for p, m in self.find_all(kind)) 67 | -------------------------------------------------------------------------------- /skadi/io/bitstream.py: -------------------------------------------------------------------------------- 1 | import bitstring 2 | 3 | 4 | SIZEOF_WORD_BYTES = 4 5 | SIZEOF_WORD_BITS = SIZEOF_WORD_BYTES * 8 6 | FORMAT = 'uintle:{0}'.format(SIZEOF_WORD_BITS) 7 | 8 | 9 | def construct(_bytes): 10 | return Bitstream(_bytes) 11 | 12 | 13 | class Bitstream(object): 14 | def __init__(self, _bytes): 15 | self.pos = 0 16 | self.data = [] 17 | 18 | remainder = len(_bytes) % 4 19 | if remainder: 20 | _bytes = _bytes + '\0' * (4 - remainder) 21 | 22 | bs = bitstring.ConstBitStream(bytes=_bytes) 23 | while True: 24 | try: 25 | word = bs.read('uintle:32') 26 | self.data.append(word) 27 | except bitstring.ReadError: 28 | break 29 | 30 | def read(self, length): # in bits 31 | try: 32 | l = self.data[self.pos / SIZEOF_WORD_BITS] 33 | r = self.data[(self.pos + length - 1) / SIZEOF_WORD_BITS] 34 | except IndexError: 35 | raise EOFError('bitstream at end of data') 36 | 37 | pos_shift = self.pos & (SIZEOF_WORD_BITS - 1) 38 | rebuild = r << (SIZEOF_WORD_BITS - pos_shift) | l >> pos_shift 39 | 40 | self.pos += length 41 | 42 | return int(rebuild & ((1 << length) - 1)) 43 | 44 | def read_long(self, length): 45 | remaining, _bytes = length, [] 46 | while remaining > 7: 47 | remaining -= 8 48 | _bytes.append(self.read(8)) 49 | if remaining: 50 | _bytes.append(self.read(remaining)) 51 | return str(bytearray(_bytes)) 52 | 53 | def read_string(self, length): 54 | i, _bytes = 0, [] 55 | while i < length: 56 | byte = self.read(8) 57 | if byte == 0: 58 | return str(bytearray(_bytes)) 59 | _bytes.append(byte) 60 | i += 1 61 | return str(bytearray(_bytes)) 62 | 63 | def read_varint(self): 64 | run, value = 0, 0 65 | 66 | while True: 67 | bits = self.read(8) 68 | value |= (bits & 0x7f) << run 69 | run += 7 70 | 71 | if not (bits >> 7) or run == 35: 72 | break 73 | 74 | return value 75 | -------------------------------------------------------------------------------- /skadi/io/unpacker/string_table.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | from skadi.io import unpacker 4 | 5 | 6 | MAX_NAME_LENGTH = 0x400 7 | KEY_HISTORY_SIZE = 32 8 | 9 | 10 | def construct(*args): 11 | return Unpacker(*args) 12 | 13 | 14 | class Unpacker(unpacker.Unpacker): 15 | def __init__(self, bitstream, num_ent, ent_bits, sz_fixed, sz_bits): 16 | super(Unpacker, self).__init__(bitstream) 17 | self.num_entries = num_ent 18 | self.entry_bits = ent_bits 19 | self.size_fixed = sz_fixed 20 | self.size_bits = sz_bits 21 | self._option = self.bitstream.read(1) 22 | self._key_history = collections.deque() 23 | self._index = -1 24 | self._entries_read = 0 25 | 26 | def unpack(self): 27 | if self._entries_read == self.num_entries: 28 | raise unpacker.UnpackComplete() 29 | 30 | consecutive = self.bitstream.read(1) 31 | if consecutive: 32 | self._index += 1 33 | else: 34 | self._index = self.bitstream.read(self.entry_bits) 35 | 36 | name, value = None, '' 37 | 38 | has_name = self.bitstream.read(1) 39 | if has_name: 40 | assert not (self._option and self.bitstream.read(1)) 41 | 42 | additive = self.bitstream.read(1) 43 | 44 | if additive: 45 | basis, length = self.bitstream.read(5), self.bitstream.read(5) 46 | name = self._key_history[basis][0:length] 47 | name += self.bitstream.read_string(MAX_NAME_LENGTH - length) 48 | else: 49 | name = self.bitstream.read_string(MAX_NAME_LENGTH) 50 | 51 | if len(self._key_history) == KEY_HISTORY_SIZE: 52 | self._key_history.popleft() 53 | 54 | self._key_history.append(name) 55 | 56 | has_value = self.bitstream.read(1) 57 | if has_value: 58 | if self.size_fixed: 59 | bit_length = self.size_bits 60 | else: 61 | bit_length = self.bitstream.read(14) * 8 62 | 63 | value = self.bitstream.read_long(bit_length) 64 | 65 | self._entries_read += 1 66 | 67 | return self._index, name, value 68 | -------------------------------------------------------------------------------- /skadi/io/protobuf/demo.py: -------------------------------------------------------------------------------- 1 | import snappy 2 | 3 | from skadi import * 4 | from skadi import index 5 | from skadi.io import protobuf 6 | from skadi.protoc import demo_pb2 as pb_d 7 | 8 | 9 | IMPL_BY_KIND = { 10 | pb_d.DEM_Stop: pb_d.CDemoStop, 11 | pb_d.DEM_FileHeader: pb_d.CDemoFileHeader, 12 | pb_d.DEM_FileInfo: pb_d.CDemoFileInfo, 13 | pb_d.DEM_SendTables: pb_d.CDemoSendTables, 14 | pb_d.DEM_SyncTick: pb_d.CDemoSyncTick, 15 | pb_d.DEM_ClassInfo: pb_d.CDemoClassInfo, 16 | pb_d.DEM_StringTables: pb_d.CDemoStringTables, 17 | pb_d.DEM_Packet: pb_d.CDemoPacket, 18 | pb_d.DEM_SignonPacket: pb_d.CDemoPacket, 19 | pb_d.DEM_ConsoleCmd: pb_d.CDemoConsoleCmd, 20 | pb_d.DEM_CustomData: pb_d.CDemoCustomData, 21 | pb_d.DEM_CustomDataCallbacks: pb_d.CDemoCustomDataCallbacks, 22 | pb_d.DEM_UserCmd: pb_d.CDemoUserCmd, 23 | pb_d.DEM_FullPacket: pb_d.CDemoFullPacket 24 | } 25 | 26 | 27 | def construct(io): 28 | return DemoIO(io) 29 | 30 | 31 | def parse(kind, compressed, message): 32 | if compressed: 33 | message = snappy.uncompress(message) 34 | 35 | return protobuf.parse(IMPL_BY_KIND[kind], message) 36 | 37 | 38 | class DemoIO(protobuf.ProtobufIO): 39 | def __init__(self, io): 40 | super(DemoIO, self).__init__(io) 41 | 42 | def read(self): 43 | try: 44 | kind = self.read_varint() 45 | comp = bool(kind & pb_d.DEM_IsCompressed) 46 | kind = (kind & ~pb_d.DEM_IsCompressed) if comp else kind 47 | 48 | tick = self.read_varint() 49 | size = self.read_varint() 50 | except EOFError: 51 | raise StopIteration() 52 | 53 | if kind in IMPL_BY_KIND: 54 | message = self.io.read(size) 55 | else: 56 | # TODO: log here. 57 | print 'unknown kind {}'.format(kind) 58 | message = None 59 | self.io.read(size) 60 | 61 | try: 62 | tell = self.io.tell() 63 | except IOError: 64 | tell = None 65 | 66 | return Peek(tick, kind, tell, size, comp), message 67 | -------------------------------------------------------------------------------- /skadi/io/protobuf/packet.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from skadi import Peek 4 | from skadi.io import protobuf 5 | from skadi.protoc import netmessages_pb2 as pb_n 6 | from skadi.protoc import networkbasetypes_pb2 as pb_nbt 7 | 8 | import io as _io 9 | 10 | 11 | IMPL_BY_KIND = { 12 | pb_n.net_SetConVar: pb_n.CNETMsg_SetConVar, 13 | pb_n.net_SignonState: pb_n.CNETMsg_SignonState, 14 | pb_n.net_Tick: pb_n.CNETMsg_Tick, 15 | pb_n.svc_ClassInfo: pb_n.CSVCMsg_ClassInfo, 16 | pb_n.svc_CreateStringTable: pb_n.CSVCMsg_CreateStringTable, 17 | pb_n.svc_GameEventList: pb_n.CSVCMsg_GameEventList, 18 | pb_n.svc_Menu: pb_n.CSVCMsg_Menu, 19 | pb_n.svc_PacketEntities: pb_n.CSVCMsg_PacketEntities, 20 | pb_n.svc_SendTable: pb_n.CSVCMsg_SendTable, 21 | pb_n.svc_ServerInfo: pb_n.CSVCMsg_ServerInfo, 22 | pb_n.svc_SetView: pb_n.CSVCMsg_SetView, 23 | pb_n.svc_Sounds: pb_n.CSVCMsg_Sounds, 24 | pb_n.svc_TempEntities: pb_n.CSVCMsg_TempEntities, 25 | pb_n.svc_UpdateStringTable: pb_n.CSVCMsg_UpdateStringTable, 26 | pb_n.svc_VoiceInit: pb_n.CSVCMsg_VoiceInit, 27 | pb_n.svc_VoiceData: pb_n.CSVCMsg_VoiceData, 28 | pb_n.svc_GameEvent: pb_nbt.CSVCMsg_GameEvent, 29 | pb_n.svc_UserMessage: pb_nbt.CSVCMsg_UserMessage 30 | } 31 | 32 | 33 | def construct(data): 34 | buff = _io.BufferedReader(_io.BytesIO(data)) 35 | return PacketIO(buff) 36 | 37 | 38 | def parse(kind, message): 39 | return protobuf.parse(IMPL_BY_KIND[kind], message) 40 | 41 | 42 | class PacketIO(protobuf.ProtobufIO): 43 | def __init__(self, io, tick=0): 44 | super(PacketIO, self).__init__(io) 45 | self.tick = tick 46 | 47 | def read(self): 48 | try: 49 | kind = self.read_varint() 50 | size = self.read_varint() 51 | except EOFError: 52 | raise StopIteration() 53 | 54 | if kind in IMPL_BY_KIND: 55 | message = self.io.read(size) 56 | else: 57 | # TODO: log here. 58 | print 'unknown kind {}'.format(kind) 59 | message = None 60 | 61 | return Peek(self.tick, kind, self.io.tell(), size, False), message 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Skadi 2 | ===== 3 | 4 | Skadi parses [Dota 2](http://www.dota2.com) replay files. 5 | 6 | **This project does not yet use semantic versioning. There is no public/private API distinction at this point, though we are increasingly resisting changes to the main demo/streaming interface. For now, best to use Skadi with some caution. It may not be production ready.** 7 | 8 | 9 | The Wiki 10 | ======== 11 | 12 | We will be moving everything currently in this README into the [wiki](https://github.com/onethirtyfive/skadi/wiki) soon™. 13 | 14 | Be sure to check out the "Pages" section, since organization is a work in progress. 15 | 16 | 17 | In a Hurry? 18 | =========== 19 | 20 | Check out some simple usage in [bin/skadi](https://github.com/onethirtyfive/skadi/blob/master/bin/skadi). 21 | 22 | 23 | Installation 24 | ============ 25 | 26 | Skadi comes in two forms; as a pure Python library and as a cython optimised library. The cython version is significantly faster (from 2x to over 3x the speed), but may not work on all systems. To install the cython version, use: 27 | 28 | python setup.py install 29 | 30 | And, if that fails, the pure python version: 31 | 32 | python setup_basic.py install 33 | 34 | If you are doing development work on skadi, or don't want to install it but still want to use the cython accelerated modules, you can build the cython modules in place: 35 | 36 | python setup.py build_ext -i 37 | 38 | ### Dependencies 39 | 40 | #### Cython 41 | 42 | The following C libraries and development headers are required 43 | 44 | * snappy 45 | * python-dev 46 | 47 | And the python packages 48 | 49 | * protobuf 50 | 51 | To install these dependencies with Ubuntu/Debian, the following may work: 52 | 53 | apt-get install python-dev python-snappy python-protobuf 54 | 55 | #### Pure Python 56 | 57 | The following C libraries and python bindings are required: 58 | 59 | * snappy 60 | 61 | And the python packages 62 | 63 | * protobuf 64 | * bitstring 65 | 66 | To install these dependencies with Ubuntu/Debian, the following may work: 67 | 68 | apt-get install python-snappy python-protobuf 69 | pip install bitstring 70 | 71 | Thanks 72 | ====== 73 | 74 | I use the pioneering [edith](https://github.com/dschleck/edith) project as a reference implementation for parsing bit streams. 75 | 76 | A big shoutout to the folks in #dota2replay on Quakenet. Feel free to stop by if you have any questions! (Be patient, we're around!) 77 | 78 | 79 | License 80 | ======= 81 | 82 | **We're counting on you: please mention Skadi when used in your projects. We ask for "Powered by [Skadi](https://github.com/skadistats/skadi)" in the footer of your site template.** 83 | 84 | Skadi is offered under the [MIT license](https://github.com/onethirtyfive/skadi/blob/master/LICENSE). 85 | 86 | This license applies to all revisions of source code until otherwise noted in the latest version of this document. 87 | -------------------------------------------------------------------------------- /skadi/io/unpacker/entity.py: -------------------------------------------------------------------------------- 1 | from skadi import enum 2 | from skadi.io import unpacker 3 | 4 | try: 5 | from skadi.io.unpacker import cProp as pu 6 | except ImportError: 7 | from skadi.io.unpacker import prop as pu 8 | 9 | 10 | PVS = enum(Leaving=1, Entering=2, Deleting=4) 11 | 12 | 13 | def construct(*args): 14 | return Unpacker(*args) 15 | 16 | 17 | class Unpacker(unpacker.Unpacker): 18 | def __init__(self, bitstream, base_index, count, delta, class_bits, world): 19 | super(Unpacker, self).__init__(bitstream) 20 | self.base_index = base_index 21 | self.count = count 22 | self.is_delta = delta 23 | self.class_bits = class_bits 24 | self.world = world 25 | self._index = -1 26 | self._entities_read = 0 27 | 28 | def unpack(self): 29 | if self._entities_read == self.count: 30 | if not self.is_delta: 31 | raise unpacker.UnpackComplete() 32 | try: 33 | if self.bitstream.read(1): 34 | return PVS.Deleting, self.bitstream.read(11), () 35 | except EOFError: 36 | raise unpacker.UnpackComplete() 37 | 38 | try: 39 | self._index, mode = self._read_header() 40 | 41 | if mode & PVS.Entering: 42 | cls = str(self.bitstream.read(self.class_bits)) 43 | serial = self.bitstream.read(10) 44 | rt = self.world.recv_tables[cls] 45 | delta = self._read_delta(self._read_prop_list(), rt) 46 | 47 | context = (cls, serial, delta) 48 | elif mode & PVS.Leaving: 49 | context = () 50 | else: 51 | rt = self.world.fetch_recv_table(self.world.by_index[self._index]) 52 | context = self._read_delta(self._read_prop_list(), rt) 53 | 54 | return self._index, mode, context 55 | 56 | finally: 57 | self._entities_read += 1 58 | 59 | def unpack_baseline(self, recv_table): 60 | prop_list = self._read_prop_list() 61 | return self._read_delta(prop_list, recv_table) 62 | 63 | def _read_header(self): 64 | encoded_index = self.bitstream.read(6) 65 | 66 | if encoded_index & 0x30: 67 | a = (encoded_index >> 0x04) & 0x03 68 | b = 16 if a == 0x03 else 0 69 | encoded_index = \ 70 | self.bitstream.read(4 * a + b) << 4 | (encoded_index & 0x0f) 71 | 72 | mode = 0 73 | if not self.bitstream.read(1): 74 | if self.bitstream.read(1): 75 | mode |= PVS.Entering 76 | else: 77 | mode |= PVS.Leaving 78 | if self.bitstream.read(1): 79 | mode |= PVS.Deleting 80 | 81 | return self._index + encoded_index + 1, mode 82 | 83 | def _read_prop_list(self): 84 | prop_list, cursor = [], -1 85 | 86 | while True: 87 | if self.bitstream.read(1): 88 | cursor += 1 89 | else: 90 | offset = self.bitstream.read_varint() 91 | if offset == 0x3fff: 92 | return prop_list 93 | else: 94 | cursor += offset + 1 95 | 96 | prop_list.append(cursor) 97 | 98 | def _read_delta(self, prop_list, recv_table): 99 | props = [recv_table.props[i] for i in prop_list] 100 | unpacker = pu.Unpacker(self.bitstream, props) 101 | 102 | return {(p.origin_dt, p.var_name): unpacker.unpack() for p in props} 103 | -------------------------------------------------------------------------------- /skadi/engine/modifiers.py: -------------------------------------------------------------------------------- 1 | import collections as c 2 | 3 | from skadi.engine import world as w 4 | from skadi.protoc import dota_modifiers_pb2 as pb_dm 5 | 6 | 7 | def humanize(modifier, world): 8 | pass 9 | 10 | 11 | def construct(modifier_names, baseline=None): 12 | return Modifiers(modifier_names, baseline) 13 | 14 | 15 | class Modifiers(object): 16 | optionals = [ 17 | 'ability_level', 'stack_count', 'creation_time', 'caster', 'ability', 18 | 'armor', 'fade_time', 'channel_time', 'portal_loop_appear', 19 | 'portal_loop_disappear', 'hero_loop_appear', 'hero_loop_disappear', 20 | 'movement_speed', 'activity', 'damage', 'duration' 21 | ] 22 | 23 | def __init__(self, modifier_names, baseline): 24 | self.modifier_names = modifier_names 25 | self.reset() 26 | 27 | if baseline: 28 | for i, (n, d) in baseline.by_index.items(): 29 | self.note((i, n, d)) 30 | 31 | def __iter__(self): 32 | return self.by_parent.iteritems() 33 | 34 | def reset(self): 35 | self.by_parent = c.defaultdict(c.OrderedDict) 36 | self.to_expire = [] 37 | 38 | def limit(self, world): 39 | for parent in self.by_parent.keys(): 40 | if parent not in world.by_ehandle: 41 | # TODO: log here. 42 | del self.by_parent[parent] 43 | 44 | def expire(self, epoch): 45 | gone = [(e, (p, m)) for e, (p, m) in self.to_expire if epoch >= e] 46 | [self._remove(p, m) for _, (p, m) in gone] 47 | [self.to_expire.remove(record) for record in gone] 48 | 49 | def note(self, entry): 50 | i, n, d = entry 51 | 52 | if not d: 53 | # TODO: log here. 54 | return 55 | 56 | pbmsg = pb_dm.CDOTAModifierBuffTableEntry() 57 | pbmsg.ParseFromString(d) 58 | 59 | parent = pbmsg.parent 60 | index, serial_num = pbmsg.index, pbmsg.serial_num 61 | 62 | if pbmsg.entry_type == pb_dm.DOTA_MODIFIER_ENTRY_TYPE_ACTIVE: 63 | attrs = {} 64 | for o in Modifiers.optionals: 65 | val = getattr(pbmsg, o, None) 66 | if val: 67 | attrs[o] = val 68 | 69 | name, _ = self.modifier_names.by_index[pbmsg.name] 70 | attrs['name'] = name 71 | 72 | vs = pbmsg.v_start 73 | vec = (vs.x, vs.y, vs.z) 74 | if vec != (0, 0, 0): 75 | attrs['v_start'] = vec 76 | 77 | ve = pbmsg.v_end 78 | vec = (ve.x, ve.y, ve.z) 79 | if vec != (0, 0, 0): 80 | attrs['v_end'] = vec 81 | 82 | if 'duration' in attrs and attrs['duration'] <= 0: 83 | del attrs['duration'] 84 | 85 | attrs['aura'] = pbmsg.aura or False 86 | attrs['subtle'] = pbmsg.aura or False 87 | 88 | if 'creation_time' in attrs and 'duration' in attrs: 89 | expiry = attrs['creation_time'] + attrs['duration'] 90 | else: 91 | expiry = None 92 | 93 | self._add(parent, index, attrs, until=expiry) 94 | else: 95 | self._remove(parent, index) 96 | 97 | def _add(self, parent, index, attrs, until): 98 | self.by_parent[parent][index] = attrs 99 | if until: 100 | record = (until, (parent, index)) 101 | self.to_expire.append(record) 102 | 103 | def _remove(self, parent, index): 104 | if index in self.by_parent[parent]: 105 | del self.by_parent[parent][index] 106 | if parent in self.by_parent and len(self.by_parent[parent]) == 0: 107 | del self.by_parent[parent] 108 | -------------------------------------------------------------------------------- /skadi/io/cBitstream.pyx: -------------------------------------------------------------------------------- 1 | from libc cimport stdlib 2 | from libc.stdint cimport int64_t, uint32_t, uint64_t, uint8_t 3 | from cpython cimport array 4 | 5 | def construct(_bytes): 6 | return Bitstream(_bytes) 7 | 8 | cdef extern from "arpa/inet.h": 9 | uint32_t ntohl(uint32_t) 10 | 11 | cdef class Bitstream: 12 | def __cinit__(Bitstream self): 13 | self.pos = 0 14 | self.data = NULL 15 | self.data_n = 0 16 | 17 | cdef void _read_data(Bitstream self, array.array[unsigned int] arr): 18 | self.data_n = len(arr) 19 | self.data = stdlib.malloc(self.data_n * sizeof(uint32_t)) 20 | if self.data is NULL: 21 | raise MemoryError() 22 | self.pos = 0 23 | 24 | cdef int i = 0 25 | cdef uint32_t be 26 | for i in range(self.data_n): 27 | be = ntohl(arr[i]) 28 | self.data[i] = (((be & 0xFF) << 24) | 29 | ((be & 0xFF00) << 8) | 30 | ((be >> 8) & 0xFF00) | 31 | (be >> 24)) 32 | 33 | def __init__(self, _bytes): 34 | remainder = len(_bytes) % 4 35 | if remainder: 36 | _bytes = _bytes + "\0" * (4 - remainder) 37 | self._read_data(array.array("I", _bytes)) 38 | 39 | cdef uint32_t _read(Bitstream self, int n): 40 | cdef uint32_t a, b 41 | a = self.data[self.pos / 32]; 42 | b = self.data[(self.pos + n - 1) / 32]; 43 | 44 | cdef uint32_t read 45 | read = self.pos & 31 46 | 47 | a = a >> read 48 | b = b << (32 - read) 49 | 50 | # cast up to 64 because 1 << 32 will be 0 otherwise 51 | cdef uint32_t mask, ret 52 | mask = ((1 << n) - 1) 53 | ret = (a | b) & mask 54 | 55 | self.pos += n; 56 | return ret 57 | 58 | cdef _dealloc(Bitstream self): 59 | if self.data != NULL: 60 | stdlib.free(self.data) 61 | 62 | def __dealloc__(Bitstream self): 63 | self._dealloc() 64 | 65 | def read(self, length): 66 | return self._read(length) 67 | 68 | cdef bytes _read_long(Bitstream self, int length): 69 | cdef unsigned char *data = stdlib.malloc(sizeof(char) * (length / 8 + 1)) 70 | cdef int i, remainder 71 | i = 0 72 | remainder = length 73 | while remainder > 7: 74 | data[i] = self.read(8) 75 | remainder -= 8 76 | i += 1 77 | 78 | if remainder: 79 | data[i] = self._read(remainder) 80 | i += 1 81 | 82 | cdef bytes output 83 | try: 84 | # Need to specify the length to deal with embedded NULLs 85 | output = data[:i] 86 | finally: 87 | stdlib.free(data) 88 | return output 89 | 90 | def read_long(self, length): 91 | return self._read_long(length) 92 | 93 | cdef bytes _read_string(Bitstream self, int length): 94 | cdef unsigned char *data = stdlib.malloc(sizeof(char) * (length + 1)) 95 | cdef int i 96 | i = 0 97 | while i < length: 98 | data[i] = self.read(8) 99 | if data[i] == 0: 100 | break 101 | i += 1 102 | 103 | cdef bytes output 104 | try: 105 | # Need to specify the length to deal with embedded NULLs 106 | output = data[:i] 107 | finally: 108 | stdlib.free(data) 109 | return output 110 | 111 | def read_string(self, length): 112 | return self._read_string(length) 113 | 114 | cdef uint64_t _read_varint(Bitstream self): 115 | cdef uint64_t run, value 116 | run = value = 0 117 | 118 | cdef uint64_t bits 119 | while True: 120 | bits = self.read(8) 121 | value |= (bits & 0x7f) << run 122 | run += 7 123 | 124 | if not (bits >> 7) or run == 35: 125 | break 126 | 127 | return value 128 | 129 | def read_varint(self): 130 | return self._read_varint() 131 | -------------------------------------------------------------------------------- /protobuf/demo.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | 3 | enum EDemoCommands { 4 | DEM_Error = -1; 5 | DEM_Stop = 0; 6 | DEM_FileHeader = 1; 7 | DEM_FileInfo = 2; 8 | DEM_SyncTick = 3; 9 | DEM_SendTables = 4; 10 | DEM_ClassInfo = 5; 11 | DEM_StringTables = 6; 12 | DEM_Packet = 7; 13 | DEM_SignonPacket = 8; 14 | DEM_ConsoleCmd = 9; 15 | DEM_CustomData = 10; 16 | DEM_CustomDataCallbacks = 11; 17 | DEM_UserCmd = 12; 18 | DEM_FullPacket = 13; 19 | DEM_Max = 14; 20 | DEM_IsCompressed = 112; 21 | } 22 | 23 | message CDemoFileHeader { 24 | required string demo_file_stamp = 1; 25 | optional int32 network_protocol = 2; 26 | optional string server_name = 3; 27 | optional string client_name = 4; 28 | optional string map_name = 5; 29 | optional string game_directory = 6; 30 | optional int32 fullpackets_version = 7; 31 | optional bool allow_clientside_entities = 8; 32 | optional bool allow_clientside_particles = 9; 33 | } 34 | 35 | message CGameInfo { 36 | message CDotaGameInfo { 37 | message CPlayerInfo { 38 | optional string hero_name = 1; 39 | optional string player_name = 2; 40 | optional bool is_fake_client = 3; 41 | optional uint64 steamid = 4; 42 | optional int32 game_team = 5; 43 | } 44 | 45 | message CHeroSelectEvent { 46 | optional bool is_pick = 1; 47 | optional uint32 team = 2; 48 | optional uint32 hero_id = 3; 49 | } 50 | 51 | optional uint32 match_id = 1; 52 | optional int32 game_mode = 2; 53 | optional int32 game_winner = 3; 54 | repeated .CGameInfo.CDotaGameInfo.CPlayerInfo player_info = 4; 55 | optional uint32 leagueid = 5; 56 | repeated .CGameInfo.CDotaGameInfo.CHeroSelectEvent picks_bans = 6; 57 | optional uint32 radiant_team_id = 7; 58 | optional uint32 dire_team_id = 8; 59 | optional string radiant_team_tag = 9; 60 | optional string dire_team_tag = 10; 61 | optional uint32 end_time = 11; 62 | } 63 | 64 | optional .CGameInfo.CDotaGameInfo dota = 4; 65 | } 66 | 67 | message CDemoFileInfo { 68 | optional float playback_time = 1; 69 | optional int32 playback_ticks = 2; 70 | optional int32 playback_frames = 3; 71 | optional .CGameInfo game_info = 4; 72 | } 73 | 74 | message CDemoPacket { 75 | optional int32 sequence_in = 1; 76 | optional int32 sequence_out_ack = 2; 77 | optional bytes data = 3; 78 | } 79 | 80 | message CDemoFullPacket { 81 | optional .CDemoStringTables string_table = 1; 82 | optional .CDemoPacket packet = 2; 83 | } 84 | 85 | message CDemoSyncTick { 86 | } 87 | 88 | message CDemoConsoleCmd { 89 | optional string cmdstring = 1; 90 | } 91 | 92 | message CDemoSendTables { 93 | optional bytes data = 1; 94 | } 95 | 96 | message CDemoClassInfo { 97 | message class_t { 98 | optional int32 class_id = 1; 99 | optional string network_name = 2; 100 | optional string table_name = 3; 101 | } 102 | 103 | repeated .CDemoClassInfo.class_t classes = 1; 104 | } 105 | 106 | message CDemoCustomData { 107 | optional int32 callback_index = 1; 108 | optional bytes data = 2; 109 | } 110 | 111 | message CDemoCustomDataCallbacks { 112 | repeated string save_id = 1; 113 | } 114 | 115 | message CDemoStringTables { 116 | message items_t { 117 | optional string str = 1; 118 | optional bytes data = 2; 119 | } 120 | 121 | message table_t { 122 | optional string table_name = 1; 123 | repeated .CDemoStringTables.items_t items = 2; 124 | repeated .CDemoStringTables.items_t items_clientside = 3; 125 | optional int32 table_flags = 4; 126 | } 127 | 128 | repeated .CDemoStringTables.table_t tables = 1; 129 | } 130 | 131 | message CDemoStop { 132 | } 133 | 134 | message CDemoUserCmd { 135 | optional int32 cmd_number = 1; 136 | optional bytes data = 2; 137 | } 138 | 139 | -------------------------------------------------------------------------------- /skadi/io/unpacker/cEntity.pyx: -------------------------------------------------------------------------------- 1 | from skadi import enum 2 | from skadi.io import unpacker 3 | from skadi.io cimport cBitstream as bs 4 | from skadi.io.unpacker import cProp as pu 5 | 6 | 7 | PVS = enum(Leaving=1, Entering=2, Deleting=4) 8 | 9 | DEF LEAVING = 1 10 | DEF ENTERING = 2 11 | DEF DELETING = 4 12 | 13 | 14 | def construct(*args): 15 | return Unpacker(*args) 16 | 17 | 18 | cdef class Unpacker(object): 19 | cdef int base_index, count, is_delta, class_bits, _index, _entities_read 20 | cdef object world 21 | cdef bs.Bitstream bitstream 22 | 23 | def __init__(self, bitstream, base_index, count, delta, class_bits, world): 24 | self.bitstream = bitstream 25 | self.base_index = base_index 26 | self.count = count 27 | self.is_delta = delta 28 | self.class_bits = class_bits 29 | self.world = world 30 | self._index = -1 31 | self._entities_read = 0 32 | 33 | cdef object unpack(self): 34 | if self._entities_read == self.count: 35 | if not self.is_delta: 36 | raise unpacker.UnpackComplete() 37 | try: 38 | if self.bitstream.read(1): 39 | return DELETING, self.bitstream.read(11), () 40 | except EOFError: 41 | raise unpacker.UnpackComplete() 42 | 43 | cdef int mode, serial 44 | cdef object cls, rt, delta, context 45 | try: 46 | self._index, mode = self._read_header() 47 | 48 | if mode & ENTERING: 49 | cls = str(self.bitstream.read(self.class_bits)) 50 | serial = self.bitstream.read(10) 51 | rt = self.world.recv_tables[cls] 52 | delta = self._read_delta(self._read_prop_list(), rt) 53 | 54 | context = (cls, serial, delta) 55 | elif mode & PVS.Leaving: 56 | context = () 57 | else: 58 | rt = self.world.fetch_recv_table(self.world.by_index[self._index]) 59 | context = self._read_delta(self._read_prop_list(), rt) 60 | 61 | return self._index, mode, context 62 | 63 | finally: 64 | self._entities_read += 1 65 | 66 | def unpack_baseline(self, recv_table): 67 | prop_list = self._read_prop_list() 68 | return self._read_delta(prop_list, recv_table) 69 | 70 | cdef object _read_header(Unpacker self): 71 | cdef int encoded_index, mode 72 | 73 | encoded_index = self.bitstream.read(6) 74 | 75 | if encoded_index & 0x30: 76 | a = (encoded_index >> 0x04) & 0x03 77 | b = 16 if a == 0x03 else 0 78 | encoded_index = \ 79 | self.bitstream.read(4 * a + b) << 4 | (encoded_index & 0x0f) 80 | 81 | mode = 0 82 | if not self.bitstream.read(1): 83 | if self.bitstream.read(1): 84 | mode |= ENTERING 85 | else: 86 | mode |= PVS.Leaving 87 | if self.bitstream.read(1): 88 | mode |= DELETING 89 | 90 | return self._index + encoded_index + 1, mode 91 | 92 | cdef object _read_prop_list(Unpacker self): 93 | cdef object prop_list = [] 94 | cdef int cursor = -1 95 | cdef int offset 96 | 97 | while True: 98 | if self.bitstream.read(1): 99 | cursor += 1 100 | else: 101 | offset = self.bitstream.read_varint() 102 | if offset == 0x3fff: 103 | return prop_list 104 | else: 105 | cursor += offset + 1 106 | 107 | prop_list.append(cursor) 108 | 109 | cdef object _read_delta(Unpacker self, object prop_list, object recv_table): 110 | cdef int i 111 | cdef object p 112 | props = [recv_table.props[i] for i in prop_list] 113 | unpacker = pu.Unpacker(self.bitstream, props) 114 | 115 | return {(p.origin_dt, p.var_name): unpacker.unpack() for p in props} 116 | 117 | def __iter__(self): 118 | def unpack(): 119 | try: 120 | return self.unpack() 121 | except unpacker.UnpackComplete: 122 | raise StopIteration() 123 | 124 | return iter(unpack, None) -------------------------------------------------------------------------------- /skadi/engine/world.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | 4 | MAX_EDICT_BITS = 11 5 | 6 | 7 | def to_ehandle(index, serial): 8 | return (serial << MAX_EDICT_BITS) | index 9 | 10 | 11 | def from_ehandle(ehandle): 12 | index = ehandle & ((1 << MAX_EDICT_BITS) - 1) 13 | serial = ehandle >> MAX_EDICT_BITS 14 | return index, serial 15 | 16 | 17 | def construct(*args): 18 | return World(*args) 19 | 20 | 21 | class World(object): 22 | def __init__(self, recv_tables): 23 | self.recv_tables = recv_tables 24 | 25 | self.by_index = collections.OrderedDict() 26 | self.by_ehandle = collections.OrderedDict() 27 | self.delta_by_ehandle = collections.defaultdict() 28 | self.by_cls = collections.defaultdict(list) 29 | self.by_dt = collections.defaultdict(list) 30 | 31 | self.classes = {} 32 | 33 | def __iter__(self): 34 | return iter(self.by_ehandle.items()) 35 | 36 | def create(self, cls, index, serial, state, delta): 37 | dt = self.recv_tables[cls].dt 38 | ehandle = to_ehandle(index, serial) 39 | 40 | # no assertions because of duplicate creation at replay start 41 | self.by_index[index] = ehandle 42 | self.by_ehandle[ehandle] = state 43 | self.delta_by_ehandle[ehandle] = delta 44 | self.by_cls[cls].append(ehandle) 45 | self.by_dt[dt].append(ehandle) 46 | self.classes[ehandle] = cls 47 | 48 | def update(self, index, state, delta): 49 | ehandle = self.by_index[index] 50 | cls = self.fetch_cls(ehandle) 51 | dt = self.fetch_recv_table(ehandle).dt 52 | 53 | assert index in self.by_index 54 | assert ehandle in self.by_ehandle 55 | assert ehandle in self.delta_by_ehandle 56 | assert ehandle in self.by_cls[cls] 57 | assert ehandle in self.by_dt[dt] 58 | assert ehandle in self.classes 59 | 60 | self.by_ehandle[ehandle] = state 61 | self.delta_by_ehandle[ehandle] = delta 62 | 63 | def delete(self, index): 64 | ehandle = self.by_index[index] 65 | cls = self.fetch_cls(ehandle) 66 | dt = self.fetch_recv_table(ehandle).dt 67 | 68 | # no assertions because these will raise errors 69 | del self.by_index[index] 70 | del self.by_ehandle[ehandle] 71 | del self.delta_by_ehandle[ehandle] 72 | self.by_cls[cls].remove(ehandle) 73 | self.by_dt[dt].remove(ehandle) 74 | del self.classes[ehandle] 75 | 76 | def find(self, ehandle): 77 | return self.by_ehandle[ehandle] 78 | 79 | def find_delta(self, ehandle): 80 | return self.delta_by_ehandle[ehandle] 81 | 82 | def find_index(self, index): 83 | ehandle = self.by_index[index] 84 | return self.find(ehandle) 85 | 86 | def find_delta_index(self, index): 87 | ehandle = self.by_index[index] 88 | return self.find_delta(ehandle) 89 | 90 | def find_all_by_cls(self, cls): 91 | coll = [(ehandle, self.find(ehandle)) for ehandle in self.by_cls[cls]] 92 | return collections.OrderedDict(coll) 93 | 94 | def find_all_delta_by_cls(self, cls): 95 | coll = [(ehandle, self.find_delta(ehandle)) for ehandle in self.by_cls[cls]] 96 | return collections.OrderedDict(coll) 97 | 98 | def find_by_cls(self, cls): 99 | try: 100 | return next(self.find_all_by_cls(cls).iteritems()) 101 | except StopIteration: 102 | raise KeyError(cls) 103 | 104 | def find_delta_by_cls(self, cls): 105 | try: 106 | return next(self.find_all_delta_by_cls(cls).iteritems()) 107 | except StopIteration: 108 | raise KeyError(cls) 109 | 110 | def find_all_by_dt(self, dt): 111 | coll = [] 112 | if dt.endswith('*'): # handle wildcard 113 | dt = dt.strip('*') 114 | for wc_dt in (k for k in self.by_dt.keys() if k.startswith(dt)): 115 | coll.extend(((h, self.find(h)) for h in self.by_dt[wc_dt])) 116 | else: 117 | coll = [(ehandle, self.find(ehandle)) for ehandle in self.by_dt[dt]] 118 | return collections.OrderedDict(coll) 119 | 120 | def find_all_delta_by_dt(self, dt): 121 | coll = [] 122 | if dt.endswith('*'): # handle wildcard 123 | dt = dt.strip('*') 124 | for wc_dt in (k for k in self.by_dt.keys() if k.startswith(dt)): 125 | coll.extend(((h, self.find_delta(h)) for h in self.by_dt[wc_dt])) 126 | else: 127 | coll = [(ehandle, self.find_delta(ehandle)) for ehandle in self.by_dt[dt]] 128 | return collections.OrderedDict(coll) 129 | 130 | def find_by_dt(self, dt): 131 | try: 132 | return next(self.find_all_by_dt(dt).iteritems()) 133 | except StopIteration: 134 | raise KeyError(dt) 135 | 136 | def find_delta_by_dt(self, dt): 137 | try: 138 | return next(self.find_all_delta_by_dt(dt).iteritems()) 139 | except StopIteration: 140 | raise KeyError(dt) 141 | 142 | def fetch_cls(self, ehandle): 143 | return self.classes[ehandle] 144 | 145 | def fetch_recv_table(self, ehandle): 146 | return self.recv_tables[self.fetch_cls(ehandle)] 147 | -------------------------------------------------------------------------------- /skadi/engine/user_message.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from skadi.protoc import usermessages_pb2 as pb_um 4 | from skadi.protoc import dota_usermessages_pb2 as pb_dota_um 5 | 6 | 7 | DOTA_UM_ID_BASE = 64 8 | 9 | NAME_BY_TYPE = { 10 | 1: 'AchievementEvent', 2: 'CloseCaption', 11 | 3: 'CloseCaptionDirect', 4: 'CurrentTimescale', 12 | 5: 'DesiredTimescale', 6: 'Fade', 13 | 7: 'GameTitle', 8: 'Geiger', 14 | 9: 'HintText', 10: 'HudMsg', 15 | 11: 'HudText', 12: 'KeyHintText', 16 | 13: 'MessageText', 14: 'RequestState', 17 | 15: 'ResetHUD', 16: 'Rumble', 18 | 17: 'SayText', 18: 'SayText2', 19 | 19: 'SayTextChannel', 20: 'Shake', 20 | 21: 'ShakeDir', 22: 'StatsCrawlMsg', 21 | 23: 'StatsSkipState', 24: 'TextMsg', 22 | 25: 'Tilt', 26: 'Train', 23 | 27: 'VGUIMenu', 28: 'VoiceMask', 24 | 29: 'VoiceSubtitle', 30: 'SendAudio', 25 | 63: 'MAX_BASE', 64: 'AddUnitToSelection', 26 | 65: 'AIDebugLine', 66: 'ChatEvent', 27 | 67: 'CombatHeroPositions', 68: 'CombatLogData', 28 | 70: 'CombatLogShowDeath', 71: 'CreateLinearProjectile', 29 | 72: 'DestroyLinearProjectile', 73: 'DodgeTrackingProjectiles', 30 | 74: 'GlobalLightColor', 75: 'GlobalLightDirection', 31 | 76: 'InvalidCommand', 77: 'LocationPing', 32 | 78: 'MapLine', 79: 'MiniKillCamInfo', 33 | 80: 'MinimapDebugPoint', 81: 'MinimapEvent', 34 | 82: 'NevermoreRequiem', 83: 'OverheadEvent', 35 | 84: 'SetNextAutobuyItem', 85: 'SharedCooldown', 36 | 86: 'SpectatorPlayerClick', 87: 'TutorialTipInfo', 37 | 88: 'UnitEvent', 89: 'ParticleManager', 38 | 90: 'BotChat', 91: 'HudError', 39 | 92: 'ItemPurchased', 93: 'Ping', 40 | 94: 'ItemFound', 95: 'CharacterSpeakConcept', 41 | 96: 'SwapVerify', 97: 'WorldLine', 42 | 98: 'TournamentDrop', 99: 'ItemAlert', 43 | 100: 'HalloweenDrops', 101: 'ChatWheel', 44 | 102: 'ReceivedXmasGift', 103: 'UpdateSharedContent', 45 | 104: 'TutorialRequestExp', 105: 'TutorialPingMinimap', 46 | 106: 'GamerulesStateChanged', 107: 'ShowSurvey', 47 | 108: 'TutorialFade', 109: 'AddQuestLogEntry', 48 | 110: 'SendStatPopup', 111: 'TutorialFinish', 49 | 112: 'SendRoshanPopup', 113: 'SendGenericToolTip', 50 | 114: 'SendFinalGold' 51 | } 52 | 53 | CHAT_MESSAGE_BY_TYPE = { 54 | -1: 'INVALID', 0: 'HERO_KILL', 55 | 1: 'HERO_DENY', 2: 'BARRACKS_KILL', 56 | 3: 'TOWER_KILL', 4: 'TOWER_DENY', 57 | 5: 'FIRSTBLOOD', 6: 'STREAK_KILL', 58 | 7: 'BUYBACK', 8: 'AEGIS', 59 | 9: 'ROSHAN_KILL', 10: 'COURIER_LOST', 60 | 11: 'COURIER_RESPAWNED', 12: 'GLYPH_USED', 61 | 13: 'ITEM_PURCHASE', 14: 'CONNECT', 62 | 15: 'DISCONNECT', 16: 'DISCONNECT_WAIT_FOR_RECONNECT', 63 | 17: 'DISCONNECT_TIME_REMAINING',18: 'DISCONNECT_TIME_REMAINING_PLURAL', 64 | 19: 'RECONNECT', 20: 'ABANDON', 65 | 21: 'SAFE_TO_LEAVE', 22: 'RUNE_PICKUP', 66 | 23: 'RUNE_BOTTLE', 24: 'INTHEBAG', 67 | 25: 'SECRETSHOP', 26: 'ITEM_AUTOPURCHASED', 68 | 27: 'ITEMS_COMBINED', 28: 'SUPER_CREEPS', 69 | 29: 'CANT_USE_ACTION_ITEM', 30: 'CHARGES_EXHAUSTED', 70 | 31: 'CANTPAUSE', 32: 'NOPAUSESLEFT', 71 | 33: 'CANTPAUSEYET', 34: 'PAUSED', 72 | 35: 'UNPAUSE_COUNTDOWN', 36: 'UNPAUSED', 73 | 37: 'AUTO_UNPAUSED', 38: 'YOUPAUSED', 74 | 39: 'CANTUNPAUSETEAM', 40: 'SAFE_TO_LEAVE_ABANDONER', 75 | 41: 'VOICE_TEXT_BANNED', 42: 'SPECTATORS_WATCHING_THIS_GAME', 76 | 43: 'REPORT_REMINDER', 44: 'ECON_ITEM', 77 | 45: 'TAUNT', 46: 'RANDOM', 78 | 47: 'RD_TURN', 48: 'SAFE_TO_LEAVE_ABANDONER_EARLY', 79 | 49: 'DROP_RATE_BONUS', 50: 'NO_BATTLE_POINTS', 80 | 51: 'DENIED_AEGIS', 52: 'INFORMATIONAL', 81 | 53: 'AEGIS_STOLEN', 54: 'ROSHAN_CANDY', 82 | 55: 'ITEM_GIFTED', 56: 'HERO_KILL_WITH_GREEVIL' 83 | } 84 | 85 | def parse(pbmsg): 86 | _type = pbmsg.msg_type 87 | 88 | if _type == 106: # wtf one-off? 89 | ns = pb_dota_um 90 | cls = 'CDOTA_UM_GamerulesStateChanged' 91 | else: 92 | ns = pb_um if _type < DOTA_UM_ID_BASE else pb_dota_um 93 | infix = 'DOTA' if ns is pb_dota_um else '' 94 | cls = 'C{0}UserMsg_{1}'.format(infix, NAME_BY_TYPE[_type]) 95 | 96 | try: 97 | _pbmsg = getattr(ns, cls)() 98 | _pbmsg.ParseFromString(pbmsg.msg_data) 99 | except AttributeError, e: 100 | err = '! protobuf {0}: open an issue at github.com/onethirtyfive/skadi' 101 | print err.format(cls) 102 | 103 | return _type, _pbmsg 104 | -------------------------------------------------------------------------------- /protobuf/usermessages.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | import "networkbasetypes.proto"; 3 | 4 | enum EBaseUserMessages { 5 | UM_AchievementEvent = 1; 6 | UM_CloseCaption = 2; 7 | UM_CloseCaptionDirect = 3; 8 | UM_CurrentTimescale = 4; 9 | UM_DesiredTimescale = 5; 10 | UM_Fade = 6; 11 | UM_GameTitle = 7; 12 | UM_Geiger = 8; 13 | UM_HintText = 9; 14 | UM_HudMsg = 10; 15 | UM_HudText = 11; 16 | UM_KeyHintText = 12; 17 | UM_MessageText = 13; 18 | UM_RequestState = 14; 19 | UM_ResetHUD = 15; 20 | UM_Rumble = 16; 21 | UM_SayText = 17; 22 | UM_SayText2 = 18; 23 | UM_SayTextChannel = 19; 24 | UM_Shake = 20; 25 | UM_ShakeDir = 21; 26 | UM_StatsCrawlMsg = 22; 27 | UM_StatsSkipState = 23; 28 | UM_TextMsg = 24; 29 | UM_Tilt = 25; 30 | UM_Train = 26; 31 | UM_VGUIMenu = 27; 32 | UM_VoiceMask = 28; 33 | UM_VoiceSubtitle = 29; 34 | UM_SendAudio = 30; 35 | UM_MAX_BASE = 63; 36 | } 37 | 38 | message CUserMsg_AchievementEvent { 39 | optional uint32 achievement = 1; 40 | } 41 | 42 | message CUserMsg_CloseCaption { 43 | optional fixed32 hash = 1; 44 | optional float duration = 2; 45 | optional bool from_player = 3; 46 | } 47 | 48 | message CUserMsg_CurrentTimescale { 49 | optional float current = 1; 50 | } 51 | 52 | message CUserMsg_DesiredTimescale { 53 | optional float desired = 1; 54 | optional float duration = 2; 55 | optional uint32 interpolator = 3; 56 | optional float start_blend_time = 4; 57 | } 58 | 59 | message CUserMsg_Fade { 60 | optional uint32 duration = 1; 61 | optional uint32 hold_time = 2; 62 | optional uint32 flags = 3; 63 | optional fixed32 color = 4; 64 | } 65 | 66 | message CUserMsg_Shake { 67 | optional uint32 command = 1; 68 | optional float amplitude = 2; 69 | optional float frequency = 3; 70 | optional float duration = 4; 71 | } 72 | 73 | message CUserMsg_ShakeDir { 74 | optional .CUserMsg_Shake shake = 1; 75 | optional .CMsgVector direction = 2; 76 | } 77 | 78 | message CUserMsg_Tilt { 79 | optional uint32 command = 1; 80 | optional bool ease_in_out = 2; 81 | optional .CMsgVector angle = 3; 82 | optional float duration = 4; 83 | optional float time = 5; 84 | } 85 | 86 | message CUserMsg_SayText { 87 | optional uint32 client = 1; 88 | optional string text = 2; 89 | optional bool chat = 3; 90 | } 91 | 92 | message CUserMsg_SayText2 { 93 | optional uint32 client = 1; 94 | optional bool chat = 2; 95 | optional string format = 3; 96 | optional string prefix = 4; 97 | optional string text = 5; 98 | optional string location = 6; 99 | } 100 | 101 | message CUserMsg_HudMsg { 102 | optional uint32 channel = 1; 103 | optional float x = 2; 104 | optional float y = 3; 105 | optional uint32 color1 = 4; 106 | optional uint32 color2 = 5; 107 | optional uint32 effect = 6; 108 | optional float fade_in_time = 7; 109 | optional float fade_out_time = 8; 110 | optional float hold_time = 9; 111 | optional float fx_time = 10; 112 | optional string message = 11; 113 | } 114 | 115 | message CUserMsg_HudText { 116 | optional string message = 1; 117 | } 118 | 119 | message CUserMsg_TextMsg { 120 | optional uint32 dest = 1; 121 | repeated string param = 2; 122 | } 123 | 124 | message CUserMsg_GameTitle { 125 | } 126 | 127 | message CUserMsg_ResetHUD { 128 | } 129 | 130 | message CUserMsg_SendAudio { 131 | optional bool stop = 2; 132 | optional string name = 3; 133 | } 134 | 135 | message CUserMsg_VoiceMask { 136 | repeated int32 audible_players_mask = 1; 137 | optional bool player_mod_enabled = 2; 138 | } 139 | 140 | message CUserMsg_RequestState { 141 | } 142 | 143 | message CUserMsg_HintText { 144 | optional string message = 1; 145 | } 146 | 147 | message CUserMsg_KeyHintText { 148 | repeated string messages = 1; 149 | } 150 | 151 | message CUserMsg_StatsCrawlMsg { 152 | } 153 | 154 | message CUserMsg_StatsSkipState { 155 | optional int32 num_skips = 1; 156 | optional int32 num_players = 2; 157 | } 158 | 159 | message CUserMsg_VoiceSubtitle { 160 | optional int32 ent_index = 1; 161 | optional int32 menu = 2; 162 | optional int32 item = 3; 163 | } 164 | 165 | message CUserMsg_VGUIMenu { 166 | message Keys { 167 | optional string name = 1; 168 | optional string value = 2; 169 | } 170 | 171 | optional string name = 1; 172 | optional bool show = 2; 173 | repeated .CUserMsg_VGUIMenu.Keys keys = 3; 174 | } 175 | 176 | message CUserMsg_Geiger { 177 | optional int32 range = 1; 178 | } 179 | 180 | message CUserMsg_Rumble { 181 | optional int32 index = 1; 182 | optional int32 data = 2; 183 | optional int32 flags = 3; 184 | } 185 | 186 | message CUserMsg_Train { 187 | optional int32 train = 1; 188 | } 189 | 190 | message CUserMsg_SayTextChannel { 191 | optional int32 player = 1; 192 | optional int32 channel = 2; 193 | optional string text = 3; 194 | } 195 | 196 | message CUserMsg_MessageText { 197 | optional uint32 color = 1; 198 | optional string text = 2; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /skadi/io/unpacker/prop.py: -------------------------------------------------------------------------------- 1 | import bitstring 2 | import math 3 | 4 | from skadi.io import unpacker 5 | from skadi.engine.dt.prop import Flag, Type 6 | 7 | 8 | def construct(bitstream, props): 9 | return Unpacker(bitstream, props) 10 | 11 | 12 | class Unpacker(unpacker.Unpacker): 13 | def __init__(self, bitstream, props): 14 | self.bitstream = bitstream 15 | self.props = props 16 | self._props_read = 0 17 | 18 | def unpack(self): 19 | if self._props_read == len(self.props): 20 | raise unpacker.UnpackComplete() 21 | 22 | prop = self.props[self._props_read] 23 | 24 | try: 25 | return self._actually_unpack(prop) 26 | finally: 27 | self._props_read += 1 28 | 29 | def _actually_unpack(self, prop): 30 | if prop.type == Type.Int: 31 | return self._unpack_int(prop.flags, prop.num_bits) 32 | elif prop.type in (Type.Float, Type.Vector, Type.VectorXY): 33 | args = [prop.flags, prop.num_bits, prop.high_value, prop.low_value] 34 | if prop.type == Type.Float: 35 | fn = self._unpack_float 36 | elif prop.type == Type.Vector: 37 | fn = self._unpack_vector 38 | elif prop.type == Type.VectorXY: 39 | fn = self._unpack_vectorxy 40 | return fn(*args) 41 | elif prop.type == Type.String: 42 | return self._unpack_string() 43 | elif prop.type == Type.Array: 44 | return self._unpack_array(prop.num_elements, prop.array_prop) 45 | elif prop.type == Type.Int64: 46 | return self._unpack_int64(prop.flags, prop.num_bits) 47 | 48 | raise NotImplementedError('prop type {0}'.format(prop.type)) 49 | 50 | def _unpack_int(self, flags, num_bits): 51 | if flags & Flag.EncodedAgainstTickcount: 52 | if flags & Flag.Unsigned: 53 | return self.bitstream.read_varint() 54 | else: 55 | value = self.bitstream.read_varint() 56 | return (-(value & 1)) ^ (value >> 1) 57 | 58 | value = self.bitstream.read(num_bits) 59 | l = 0x80000000 >> (32 - num_bits) 60 | r = (flags & Flag.Unsigned) - 1 61 | 62 | return (value ^ (l & r)) - (l & r) 63 | 64 | def _unpack_float(self, flags, num_bits, high_value, low_value): 65 | if flags & Flag.Coord: 66 | integer = self.bitstream.read(1) 67 | fraction = self.bitstream.read(1) 68 | 69 | if not integer and not fraction: 70 | return 0.0 71 | 72 | negate = self.bitstream.read(1) 73 | 74 | if integer: 75 | integer = self.bitstream.read(0x0e) + 1 76 | 77 | if fraction: 78 | fraction = self.bitstream.read(5) 79 | 80 | value = 0.03125 * fraction 81 | value += integer 82 | 83 | if negate: 84 | value *= -1 85 | 86 | return value 87 | elif flags & Flag.NoScale: 88 | bit_array = bitstring.BitArray(uint=self.bitstream.read(32), length=32) 89 | return bit_array.float 90 | elif flags & Flag.Normal: 91 | sign = self.bitstream.read(1) 92 | bit_array = bitstring.BitArray(uint=self.bitstream.read(11), length=32) 93 | 94 | value = bit_array.float 95 | if bit_array >> 31: 96 | value += 4.2949673e9 97 | value *= 4.885197850512946e-4 98 | if sign: 99 | value *= -1 100 | 101 | return value 102 | elif flags & Flag.CellCoord: 103 | value = self.bitstream.read(num_bits) 104 | return value + 0.03125 * self.bitstream.read(5) 105 | elif flags & Flag.CellCoordIntegral: 106 | value = self.bitstream.read(num_bits) 107 | if value >> 31: 108 | value += 4.2949673e9 # wat, edith? 109 | return float(value) 110 | 111 | dividend = self.bitstream.read(num_bits) 112 | divisor = (1 << num_bits) - 1 113 | 114 | f = float(dividend) / divisor 115 | r = high_value - low_value 116 | return f * r + low_value 117 | 118 | def _unpack_vector(self, flags, num_bits, high_value, low_value): 119 | x = self._unpack_float(flags, num_bits, high_value, low_value) 120 | y = self._unpack_float(flags, num_bits, high_value, low_value) 121 | 122 | if flags & Flag.Normal: 123 | f = x * x + y * y 124 | z = 0 if (f <= 1) else math.sqrt(1 - f) 125 | 126 | sign = self.bitstream.read(1) 127 | if sign: 128 | z *= -1 129 | else: 130 | z = self._unpack_float(flags, num_bits, high_value, low_value) 131 | 132 | return x, y, z 133 | 134 | def _unpack_vectorxy(self, flags, num_bits, high_value, low_value): 135 | x = self._unpack_float(flags, num_bits, high_value, low_value) 136 | y = self._unpack_float(flags, num_bits, high_value, low_value) 137 | return x, y 138 | 139 | def _unpack_string(self): 140 | return self.bitstream.read_string(self.bitstream.read(9)) 141 | 142 | def _unpack_array(self, num_elements, array_prop): 143 | n, bits = num_elements, 0 144 | 145 | while n: 146 | bits += 1 147 | n >>= 1 148 | 149 | count, i, elements = self.bitstream.read(bits), 0, [] 150 | 151 | while i < count: 152 | elements.append(self._actually_unpack(array_prop)) 153 | i += 1 154 | 155 | return elements 156 | 157 | def _unpack_int64(self, flags, num_bits): 158 | if flags & Flag.EncodedAgainstTickcount: 159 | raise NotImplementedError('int64 cant be encoded against tickcount') 160 | 161 | negate = False 162 | second_bits = num_bits - 32 163 | 164 | if not (flags & Flag.Unsigned): 165 | second_bits -= 1 166 | if self.bitstream.read(1): 167 | negate = True 168 | 169 | a = self.bitstream.read(32) 170 | b = self.bitstream.read(second_bits) 171 | 172 | value = (a << 32) | b 173 | if negate: 174 | value *= -1 175 | 176 | return value 177 | -------------------------------------------------------------------------------- /skadi/io/unpacker/cProp.pyx: -------------------------------------------------------------------------------- 1 | from libc.stdint cimport * 2 | from skadi.io cimport cBitstream as bs 3 | 4 | import math 5 | 6 | from skadi.io import unpacker 7 | 8 | from skadi.engine.dt.consts cimport * 9 | 10 | def construct(bitstream, props): 11 | return Unpacker(bitstream, props) 12 | 13 | # If sizeof(float) != sizeof(uint32_t), then we're all fucked. But 14 | # it's worth checking that via an assert before using this 15 | cdef union UIntOrFloat: 16 | float asFloat 17 | uint32_t asUInt 18 | 19 | cdef class Unpacker(object): 20 | cdef public bs.Bitstream bitstream 21 | cdef public object props 22 | cdef int _props_read 23 | 24 | def __init__(self, bitstream, props): 25 | self.bitstream = bitstream 26 | self.props = props 27 | self._props_read = 0 28 | 29 | def unpack(self): 30 | return self._unpack() 31 | 32 | cdef object _unpack(Unpacker self): 33 | if self._props_read == len(self.props): 34 | raise unpacker.UnpackComplete() 35 | 36 | cdef object prop 37 | prop = self.props[self._props_read] 38 | 39 | try: 40 | return self._actually_unpack(prop) 41 | finally: 42 | self._props_read += 1 43 | 44 | cdef object _actually_unpack(Unpacker self, object prop): 45 | cdef char type_ = prop.type 46 | if type_ == INT: 47 | return self._unpack_int(prop.flags, prop.num_bits) 48 | elif type_ == FLOAT: 49 | return self._unpack_float(prop.flags, prop.num_bits, 50 | prop.high_value, prop.low_value) 51 | elif type_ == VECTOR: 52 | return self._unpack_vector(prop.flags, prop.num_bits, 53 | prop.high_value, prop.low_value) 54 | elif type_ == VECTORXY: 55 | return self._unpack_vectorxy(prop.flags, prop.num_bits, 56 | prop.high_value, prop.low_value) 57 | elif type_ == STRING: 58 | return self._unpack_string() 59 | elif type_ == ARRAY: 60 | return self._unpack_array(prop.num_elements, prop.array_prop) 61 | elif type_ == INT64: 62 | return self._unpack_int64(prop.flags, prop.num_bits) 63 | 64 | raise NotImplementedError('prop type {0}'.format(prop.type)) 65 | 66 | cdef int _unpack_int(Unpacker self, int flags, int num_bits): 67 | cdef int64_t value, l, r 68 | 69 | if flags & ENCODEDAGAINSTTICKCOUNT: 70 | if flags & UNSIGNED: 71 | return self.bitstream._read_varint() 72 | else: 73 | value = self.bitstream._read_varint() 74 | return (-(value & 1)) ^ (value >> 1) 75 | 76 | value = self.bitstream._read(num_bits) 77 | l = 0x80000000 >> (32 - num_bits) 78 | r = (flags & UNSIGNED) - 1 79 | 80 | return (value ^ (l & r)) - (l & r) 81 | 82 | cdef float _unpack_float(Unpacker self, uint64_t flags, int num_bits, 83 | int high_value, int low_value): 84 | # assert bool(sizeof(uint32_t) == sizeof(float)), \ 85 | # "sizeof(float) != sizeof(uint32_t). Petition for a float32_t type." 86 | cdef UIntOrFloat float_conv 87 | 88 | cdef int integer, fraction, negate 89 | cdef float value 90 | 91 | if flags & COORD: 92 | integer = self.bitstream._read(1) 93 | fraction = self.bitstream._read(1) 94 | 95 | if not integer and not fraction: 96 | return 0.0 97 | 98 | negate = self.bitstream._read(1) 99 | 100 | if integer: 101 | integer = self.bitstream._read(0x0e) + 1 102 | 103 | if fraction: 104 | fraction = self.bitstream._read(5) 105 | 106 | value = 0.03125 * fraction 107 | value += integer 108 | 109 | if negate: 110 | value *= -1 111 | 112 | return value 113 | elif flags & NOSCALE: 114 | float_conv.asUInt = self.bitstream._read(32) 115 | return float_conv.asFloat 116 | elif flags & NORMAL: 117 | sign = self.bitstream._read(1) 118 | float_conv.asUInt = self.bitstream._read(11) 119 | 120 | value = float_conv.asFloat 121 | if float_conv.asUInt >> 31: 122 | value += 4.2949673e9 123 | value *= 4.885197850512946e-4 124 | if sign: 125 | value *= -1 126 | 127 | return value 128 | elif flags & CELLCOORD: 129 | value = self.bitstream._read(num_bits) 130 | return value + 0.03125 * self.bitstream._read(5) 131 | elif flags & CELLCOORDINTEGRAL: 132 | raw = self.bitstream._read(num_bits) 133 | if raw >> 31: 134 | value = raw + 4.2949673e9 # wat, edith? 135 | return value 136 | 137 | cdef int dividend, divisor 138 | dividend = self.bitstream._read(num_bits) 139 | divisor = (1 << num_bits) - 1 140 | 141 | cdef float f 142 | f = dividend / divisor 143 | r = high_value - low_value 144 | return f * r + low_value 145 | 146 | cdef object _unpack_vector(Unpacker self, uint64_t flags, int num_bits, 147 | int high_value, int low_value): 148 | cdef float x, y, f, z 149 | cdef int sign 150 | x = self._unpack_float(flags, num_bits, high_value, low_value) 151 | y = self._unpack_float(flags, num_bits, high_value, low_value) 152 | 153 | if flags & NORMAL: 154 | f = x * x + y * y 155 | z = 0 if (f <= 1) else math.sqrt(1 - f) 156 | 157 | sign = self.bitstream._read(1) 158 | if sign: 159 | z *= -1 160 | else: 161 | z = self._unpack_float(flags, num_bits, high_value, low_value) 162 | 163 | return x, y, z 164 | 165 | cdef object _unpack_vectorxy(Unpacker self, uint64_t flags, int num_bits, 166 | int high_value, int low_value): 167 | cdef float x, y 168 | x = self._unpack_float(flags, num_bits, high_value, low_value) 169 | y = self._unpack_float(flags, num_bits, high_value, low_value) 170 | return x, y 171 | 172 | cdef object _unpack_string(Unpacker self): 173 | return self.bitstream._read_string(self.bitstream._read(9)) 174 | 175 | cdef object _unpack_array(Unpacker self, int num_elements, object array_prop): 176 | cdef int n, bits 177 | n, bits = num_elements, 0 178 | 179 | while n: 180 | bits += 1 181 | n >>= 1 182 | 183 | cdef int count, i 184 | count = self.bitstream._read(bits) 185 | 186 | cdef object elements 187 | # Preallocate to be fast! 188 | elements = [None] * count 189 | 190 | for i in range(count): 191 | elements[i] = self._actually_unpack(array_prop) 192 | 193 | return elements 194 | 195 | cdef int64_t _unpack_int64(Unpacker self, uint64_t flags, int num_bits): 196 | if flags & ENCODEDAGAINSTTICKCOUNT: 197 | raise NotImplementedError('int64 cant be encoded against tickcount') 198 | 199 | cdef int negate, second_bits 200 | 201 | negate = 1 202 | second_bits = num_bits - 32 203 | 204 | if not (flags & UNSIGNED): 205 | second_bits -= 1 206 | if self.bitstream._read(1): 207 | negate = -1 208 | 209 | cdef uint64_t a, b 210 | a = self.bitstream._read(32) 211 | b = self.bitstream._read(second_bits) 212 | 213 | cdef int64_t value 214 | value = (a << 32) | b 215 | value *= negate 216 | 217 | return value 218 | 219 | def __iter__(self): 220 | try: 221 | while True: 222 | yield self._unpack() 223 | except unpacker.UnpackComplete: 224 | pass 225 | -------------------------------------------------------------------------------- /skadi/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import collections as c 4 | import copy 5 | import io as _io 6 | import itertools as it 7 | import math 8 | 9 | 10 | def enum(**enums): 11 | _enum = type('Enum', (), enums) 12 | _enum.tuples = enums 13 | return _enum 14 | 15 | Peek = c.namedtuple('Peek', 'tick, kind, tell, size, compressed') 16 | 17 | 18 | from skadi import * 19 | from skadi.engine import string_table as stab 20 | from skadi.engine.dt import prop as dt_p 21 | from skadi.engine.dt import send as dt_s 22 | from skadi.index.demo import prologue as id_prologue 23 | from skadi.index.embed import packet as ie_packet 24 | from skadi.index.embed import send_tables as ie_send_tables 25 | from skadi.io.protobuf import demo as d_io 26 | from skadi.io.protobuf import packet as p_io 27 | from skadi.io.unpacker import string_table as u_st 28 | from skadi.protoc import demo_pb2 as pb_d 29 | from skadi.protoc import netmessages_pb2 as pb_n 30 | try: 31 | from skadi.io import cBitstream as b_io 32 | except ImportError: 33 | from skadi.io import bitstream as b_io 34 | try: 35 | from skadi.engine.dt import cRecv as dt_r 36 | except ImportError: 37 | from skadi.engine.dt import recv as dt_r 38 | 39 | Meta = c.namedtuple('Meta', ['file_header', 'server_info', 'voice_init']) 40 | 41 | FileHeader = c.namedtuple('FileHeader', [ 42 | 'demo_file_stamp', 'network_protocol', 'server_name', 'client_name', 43 | 'map_name', 'game_directory', 'fullpackets_version' 44 | ]) 45 | 46 | ServerInfo = c.namedtuple('ServerInfo', [ 47 | 'protocol', 'server_count', 'is_dedicated', 'is_hltv', 'c_os', 'map_crc', 48 | 'client_crc', 'string_table_crc', 'max_clients', 'max_classes', 49 | 'player_slot', 'tick_interval', 'game_dir', 'map_name', 'sky_name', 50 | 'host_name' 51 | ]) 52 | 53 | VoiceInit = c.namedtuple('VoiceInit', ['quality', 'codec']) 54 | 55 | Prologue = c.namedtuple('Prologue', [ 56 | 'meta', 'recv_tables', 'string_tables', 'game_event_list', 'class_bits' 57 | ]) 58 | 59 | test_needs_decoder = lambda st: st.needs_decoder 60 | 61 | 62 | class InvalidDemo(RuntimeError): 63 | pass 64 | 65 | 66 | def load(io, tick=0): 67 | demo_io = d_io.construct(io) 68 | prologue = id_prologue.construct(demo_io) 69 | 70 | # mash all packet svc messages together, then index them 71 | signon_packets = list(prologue.all_dem_signon_packet) 72 | data = ''.join([pb.data for _, pb in signon_packets]) 73 | packet = ie_packet.construct(p_io.construct(data)) 74 | 75 | # meta: file header 76 | _, pbmsg = prologue.dem_file_header 77 | file_header = FileHeader(*[getattr(pbmsg, a) for a in FileHeader._fields]) 78 | 79 | # meta: server info 80 | _, pbmsg = packet.svc_server_info 81 | server_info = ServerInfo(*[getattr(pbmsg, a) for a in ServerInfo._fields]) 82 | 83 | # meta: voice init 84 | _, pbmsg = packet.svc_voice_init 85 | voice_init = VoiceInit(*[getattr(pbmsg, a) for a in VoiceInit._fields]) 86 | 87 | # prologue: meta 88 | meta = Meta(file_header, server_info, voice_init) 89 | 90 | # prologue: send tables 91 | _, pbmsg = prologue.dem_send_tables 92 | _send_tables = ie_send_tables.construct(p_io.construct(pbmsg.data)) 93 | send_tables = c.OrderedDict() 94 | 95 | for pbmsg in [pb for _, pb in _send_tables.all_svc_send_table]: 96 | if pbmsg.is_end: 97 | break 98 | 99 | send_table = _parse_cdemo_send_table(pbmsg) 100 | send_tables[send_table.dt] = send_table 101 | 102 | # prologue: recv tables 103 | flattener = Flattener(send_tables) 104 | recv_tables = c.OrderedDict() 105 | 106 | _, pbmsg = prologue.dem_class_info 107 | class_info = c.OrderedDict() 108 | 109 | for cls in pbmsg.classes: 110 | _id, dt, name = str(cls.class_id), cls.table_name, cls.network_name 111 | class_info[_id] = (dt, name) 112 | 113 | for st in filter(test_needs_decoder, send_tables.values()): 114 | props = flattener.flatten(st) 115 | cls = next(_id for _id, (dt, _) in class_info.items() if dt == st.dt) 116 | recv_tables[cls] = dt_r.construct(st.dt, props) 117 | 118 | # prologue: string tables 119 | pbmsgs = [pb for _, pb in packet.all_svc_create_string_table] 120 | string_tables = _parse_all_csvc_create_string_tables(pbmsgs) 121 | 122 | # prologue: game event list 123 | _, pbmsg = packet.svc_game_event_list 124 | game_event_list = c.OrderedDict() 125 | 126 | for desc in pbmsg.descriptors: 127 | _id, name = desc.eventid, desc.name 128 | keys = [(k.type, k.name) for k in desc.keys] 129 | game_event_list[_id] = (name, keys) 130 | 131 | # prologue: class bits 132 | class_bits = server_info.max_classes.bit_length() 133 | 134 | return Prologue(meta, recv_tables, string_tables, game_event_list, class_bits) 135 | 136 | 137 | def _parse_cdemo_send_table(pbmsg): 138 | dt, props = pbmsg.net_table_name, [] 139 | 140 | for p in pbmsg.props: 141 | attributes = { 142 | 'var_name': p.var_name, 143 | 'type': p.type, 144 | 'flags': p.flags, 145 | 'num_elements': p.num_elements, 146 | 'num_bits': p.num_bits, 147 | 'dt_name': p.dt_name, 148 | 'priority': p.priority, 149 | 'low_value': p.low_value, 150 | 'high_value': p.high_value 151 | } 152 | props.append(dt_p.construct(dt, attributes)) 153 | 154 | # assign properties used for parsing array elements 155 | for i, p in enumerate(props): 156 | if p.type == dt_p.Type.Array: 157 | p.array_prop = props[i - 1] 158 | 159 | return dt_s.construct(dt, props, pbmsg.is_end, pbmsg.needs_decoder) 160 | 161 | 162 | def _parse_all_csvc_create_string_tables(pbmsgs): 163 | string_tables = c.OrderedDict() 164 | 165 | for pbmsg in pbmsgs: 166 | ne = pbmsg.num_entries 167 | eb = int(math.ceil(math.log(pbmsg.max_entries, 2))) 168 | sf = pbmsg.user_data_fixed_size 169 | sb = pbmsg.user_data_size_bits 170 | bs = b_io.construct(pbmsg.string_data) 171 | 172 | entries = list(u_st.construct(bs, ne, eb, sf, sb)) 173 | name = pbmsg.name 174 | string_tables[name] = stab.construct(name, eb, sf, sb, entries) 175 | 176 | return string_tables 177 | 178 | 179 | class Flattener(object): 180 | def __init__(self, send_tables): 181 | self.send_tables = send_tables 182 | 183 | def flatten(self, st): 184 | aggregate = [] 185 | exclusions = self._aggregate_exclusions(st) 186 | self._build(st, aggregate, exclusions, []) 187 | return aggregate 188 | 189 | def _build(self, st, aggregate, exclusions, props, proxy_for=None): 190 | self._compile(st, aggregate, exclusions, props) 191 | for p in props: 192 | if proxy_for: 193 | _p = copy.copy(p) 194 | _p.var_name = '{}.{}'.format(p.origin_dt, p.var_name).encode('UTF-8') 195 | _p.origin_dt = proxy_for 196 | else: 197 | _p = p 198 | aggregate.append(_p) 199 | 200 | def _compile(self, st, aggregate, exclusions, props): 201 | def test_excluded(p): 202 | return 203 | 204 | for p in st.props: 205 | excluded = (st.dt, p.var_name) in exclusions 206 | ineligible = p.flags & (dt_p.Flag.Exclude | dt_p.Flag.InsideArray) 207 | if excluded or ineligible: 208 | continue 209 | 210 | if p.type == dt_p.Type.DataTable: 211 | _st = self.send_tables[p.dt_name] 212 | if dt_p.test_collapsible(p): 213 | self._compile(_st, aggregate, exclusions, props) 214 | else: 215 | self._build(_st, aggregate, exclusions, [], proxy_for=p.origin_dt) 216 | else: 217 | props.append(p) 218 | 219 | def _aggregate_exclusions(self, st): 220 | def recurse(_dt_prop): 221 | st = self.send_tables[_dt_prop.dt_name] 222 | return self._aggregate_exclusions(st) 223 | 224 | inherited = map(recurse, st.dt_props) 225 | 226 | return st.exclusions + list(it.chain(*inherited)) 227 | -------------------------------------------------------------------------------- /skadi/demo.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import collections as c 4 | import copy 5 | import io as _io 6 | 7 | from skadi import * 8 | from skadi.engine import world as e_w 9 | from skadi.engine import game_event as e_ge 10 | from skadi.engine import modifiers as e_m 11 | from skadi.engine import user_message as e_um 12 | from skadi.index.embed import packet as ie_packet 13 | from skadi.io.protobuf import demo as d_io 14 | from skadi.io.protobuf import packet as p_io 15 | from skadi.io.unpacker import string_table as u_st 16 | from skadi.protoc import demo_pb2 as pb_d 17 | from skadi.protoc import netmessages_pb2 as pb_n 18 | from skadi.protoc import dota_modifiers_pb2 as pb_dm 19 | 20 | try: 21 | from skadi.io import cBitstream as b_io 22 | except ImportError: 23 | from skadi.io import bitstream as b_io 24 | try: 25 | from skadi.io.unpacker import cEntity as u_ent 26 | except ImportError: 27 | from skadi.io.unpacker import entity as u_ent 28 | 29 | 30 | def scan(prologue, demo_io, tick=None): 31 | full_packets, remaining_packets = [], [] 32 | 33 | if tick is not None: 34 | iter_bootstrap = iter(demo_io) 35 | 36 | try: 37 | p, m = next(iter_bootstrap) 38 | item = (p, d_io.parse(p.kind, p.compressed, m)) 39 | 40 | while True: 41 | if p.kind == pb_d.DEM_FullPacket: 42 | full_packets.append(item) 43 | remaining_packets = [] 44 | else: 45 | remaining_packets.append(item) 46 | 47 | if p.tick >= tick: 48 | break 49 | 50 | p, m = next(iter_bootstrap) 51 | item = (p, d_io.parse(p.kind, p.compressed, m)) 52 | except StopIteration: 53 | raise EOFError() 54 | 55 | return full_packets, remaining_packets 56 | 57 | 58 | def reconstitute(full_packets, class_bits, recv_tables, string_tables): 59 | w = e_w.construct(recv_tables) 60 | st = string_tables 61 | 62 | st_mn = st['ModifierNames'] 63 | st_am = st['ActiveModifiers'] 64 | m = e_m.construct(st_mn, baseline=st_am) 65 | 66 | for _, fp in full_packets: 67 | for table in fp.string_table.tables: 68 | assert not table.items_clientside 69 | 70 | entries = [(_i, e.str, e.data) for _i, e in enumerate(table.items)] 71 | st[table.table_name].update_all(entries) 72 | 73 | if table.table_name == 'ActiveModifiers': 74 | m.reset() 75 | [m.note(e) for e in entries] 76 | 77 | if full_packets: 78 | _, fp = full_packets[-1] 79 | packet = ie_packet.construct(p_io.construct(fp.packet.data)) 80 | 81 | _, pe = packet.svc_packet_entities 82 | ct = pe.updated_entries 83 | bs = b_io.construct(pe.entity_data) 84 | unpacker = u_ent.construct(bs, -1, ct, False, class_bits, w) 85 | 86 | for index, mode, (cls, serial, diff) in unpacker: 87 | data = st['instancebaseline'].get(cls)[1] 88 | bs = b_io.construct(data) 89 | unpacker = u_ent.construct(bs, -1, 1, False, class_bits, w) 90 | 91 | state = unpacker.unpack_baseline(recv_tables[cls]) 92 | state.update(diff) 93 | 94 | w.create(cls, index, serial, state, dict(diff)) 95 | 96 | return w, m, st 97 | 98 | 99 | def construct(*args): 100 | return Demo(*args) 101 | 102 | 103 | class Stream(object): 104 | def __init__(self, prologue, io, world, mods, sttabs, rem, sparse=False): 105 | self.prologue = prologue 106 | self.demo_io = d_io.construct(io) 107 | self.tick = None 108 | self.user_messages = None 109 | self.game_events = None 110 | self.world = world 111 | self.modifiers = mods 112 | self.string_tables = sttabs 113 | self.sparse = sparse 114 | 115 | for p, pb in rem: 116 | self.advance(p.tick, pb) 117 | 118 | def __iter__(self): 119 | iter_entries = iter(self.demo_io) 120 | 121 | if self.tick is not None: 122 | t = self.tick 123 | um, ge = self.user_messages, self.game_events 124 | w, m = self.world, self.modifiers 125 | yield [t, um, ge, w, m] 126 | 127 | while True: 128 | peek, message = next(iter_entries) 129 | 130 | if peek.kind == pb_d.DEM_FullPacket: 131 | continue 132 | elif peek.kind == pb_d.DEM_Stop: 133 | raise StopIteration() 134 | else: 135 | pbmsg = d_io.parse(peek.kind, peek.compressed, message) 136 | self.advance(peek.tick, pbmsg) 137 | 138 | t = self.tick 139 | um, ge = self.user_messages, self.game_events 140 | w, m = self.world, self.modifiers 141 | yield [t, um, ge, w, m] 142 | 143 | def iterfullticks(self): 144 | iter_entries = iter(self.demo_io) 145 | 146 | while True: 147 | peek, message = next(iter_entries) 148 | 149 | if peek.kind == pb_d.DEM_Stop: 150 | raise StopIteration() 151 | elif peek.kind != pb_d.DEM_FullPacket: 152 | continue 153 | 154 | pro = self.prologue 155 | 156 | full_packet = (peek, d_io.parse(peek.kind, peek.compressed, message)) 157 | self.world, self.modifiers, self.string_tables = reconstitute( 158 | [full_packet], pro.class_bits, pro.recv_tables, self.string_tables) 159 | self.tick = peek.tick 160 | self.user_messages = [] 161 | self.game_events = [] 162 | yield [self.tick, self.user_messages, self.game_events, self.world, 163 | self.modifiers] 164 | 165 | def advance(self, tick, pbmsg): 166 | self.tick = tick 167 | 168 | packet = ie_packet.construct(p_io.construct(pbmsg.data)) 169 | am_entries = [] 170 | 171 | for _, _pbmsg in packet.all_svc_update_string_table: 172 | key = self.string_tables.keys()[_pbmsg.table_id] 173 | _st = self.string_tables[key] 174 | 175 | bs = b_io.construct(_pbmsg.string_data) 176 | ne = _pbmsg.num_changed_entries 177 | eb, sf, sb = _st.entry_bits, _st.size_fixed, _st.size_bits 178 | 179 | entries = u_st.construct(bs, ne, eb, sf, sb) 180 | if key == 'ActiveModifiers': 181 | am_entries = list(entries) 182 | else: 183 | [_st.update(e) for e in entries] 184 | 185 | um = packet.find_all(pb_n.svc_UserMessage) 186 | self.user_messages = [e_um.parse(p_io.parse(p.kind, m)) for p, m in um] 187 | 188 | ge = packet.find_all(pb_n.svc_GameEvent) 189 | gel = self.prologue.game_event_list 190 | self.game_events = [e_ge.parse(p_io.parse(p.kind, m), gel) for p, m in ge] 191 | 192 | p, m = packet.find(pb_n.svc_PacketEntities) 193 | pe = p_io.parse(p.kind, m) 194 | ct = pe.updated_entries 195 | bs = b_io.construct(pe.entity_data) 196 | 197 | class_bits = self.prologue.class_bits 198 | recv_tables = self.prologue.recv_tables 199 | 200 | unpacker = u_ent.construct(bs, -1, ct, False, class_bits, self.world) 201 | 202 | for index, mode, context in unpacker: 203 | if mode & u_ent.PVS.Entering: 204 | cls, serial, diff = context 205 | 206 | data = self.string_tables['instancebaseline'].get(cls)[1] 207 | bs = b_io.construct(data) 208 | unpacker = u_ent.construct(bs, -1, 1, False, class_bits, self.world) 209 | 210 | state = unpacker.unpack_baseline(self.prologue.recv_tables[cls]) 211 | state.update(diff) 212 | 213 | self.world.create(cls, index, serial, state, dict(diff)) 214 | elif mode & u_ent.PVS.Deleting: 215 | self.world.delete(index) 216 | elif mode ^ u_ent.PVS.Leaving: 217 | state = dict(context) if self.sparse else dict(self.world.find_index(index), **context) 218 | diff = state if self.sparse else dict(context) 219 | 220 | self.world.update(index, state, diff) 221 | 222 | [self.modifiers.note(e) for e in am_entries] 223 | self.modifiers.limit(self.world) 224 | 225 | _, gamerules = self.world.find_by_dt('DT_DOTAGamerulesProxy') 226 | game_time_key = ('DT_DOTAGamerulesProxy', 'DT_DOTAGamerules.m_fGameTime') 227 | self.modifiers.expire(gamerules[game_time_key]) 228 | 229 | def _report(self): 230 | t = self.tick 231 | um, ge = self.user_messages, self.game_events 232 | w, m = self.world, self.modifiers 233 | return t, um, ge, w, m 234 | 235 | 236 | class Demo(object): 237 | def __init__(self, abspath): 238 | infile = _io.open(abspath, 'r+b') 239 | if infile.read(8) != "PBUFDEM\0": 240 | raise InvalidDemo('malformed header') 241 | 242 | gio = bytearray(infile.read(4)) # LE uint file offset 243 | gio = sum(gio[i] << (i * 8) for i in range(4)) 244 | 245 | try: 246 | tell = infile.tell() 247 | infile.seek(gio) 248 | p, m = d_io.construct(infile).read() 249 | self.file_info = d_io.parse(p.kind, p.compressed, m) 250 | assert p.kind == pb_d.DEM_FileInfo 251 | infile.seek(tell) 252 | except EOFError: 253 | raise InvalidDemo('no end game summary') 254 | 255 | self.prologue = load(infile) 256 | self.io = infile 257 | self._tell = infile.tell() 258 | 259 | def stream(self, tick=None, sparse=False): 260 | self.io.seek(self._tell) 261 | 262 | p = self.prologue 263 | fp, rem = scan(p, d_io.construct(self.io), tick=tick) 264 | clean_st = copy.deepcopy(p.string_tables) 265 | w, m, st = reconstitute(fp, p.class_bits, p.recv_tables, clean_st) 266 | 267 | return Stream(p, self.io, w, m, st, rem, sparse=sparse) 268 | -------------------------------------------------------------------------------- /protobuf/netmessages.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | import "networkbasetypes.proto"; 3 | 4 | enum NET_Messages { 5 | net_NOP = 0; 6 | net_Disconnect = 1; 7 | net_File = 2; 8 | net_SplitScreenUser = 3; 9 | net_Tick = 4; 10 | net_StringCmd = 5; 11 | net_SetConVar = 6; 12 | net_SignonState = 7; 13 | } 14 | 15 | enum CLC_Messages { 16 | clc_ClientInfo = 8; 17 | clc_Move = 9; 18 | clc_VoiceData = 10; 19 | clc_BaselineAck = 11; 20 | clc_ListenEvents = 12; 21 | clc_RespondCvarValue = 13; 22 | clc_FileCRCCheck = 14; 23 | clc_LoadingProgress = 15; 24 | clc_SplitPlayerConnect = 16; 25 | clc_ClientMessage = 17; 26 | } 27 | 28 | enum VoiceDataFormat_t { 29 | VOICEDATA_FORMAT_STEAM = 0; 30 | VOICEDATA_FORMAT_ENGINE = 1; 31 | } 32 | 33 | enum SVC_Messages { 34 | svc_ServerInfo = 8; 35 | svc_SendTable = 9; 36 | svc_ClassInfo = 10; 37 | svc_SetPause = 11; 38 | svc_CreateStringTable = 12; 39 | svc_UpdateStringTable = 13; 40 | svc_VoiceInit = 14; 41 | svc_VoiceData = 15; 42 | svc_Print = 16; 43 | svc_Sounds = 17; 44 | svc_SetView = 18; 45 | svc_FixAngle = 19; 46 | svc_CrosshairAngle = 20; 47 | svc_BSPDecal = 21; 48 | svc_SplitScreen = 22; 49 | svc_UserMessage = 23; 50 | svc_EntityMessage = 24; 51 | svc_GameEvent = 25; 52 | svc_PacketEntities = 26; 53 | svc_TempEntities = 27; 54 | svc_Prefetch = 28; 55 | svc_Menu = 29; 56 | svc_GameEventList = 30; 57 | svc_GetCvarValue = 31; 58 | svc_PacketReliable = 32; 59 | } 60 | 61 | enum ESplitScreenMessageType { 62 | MSG_SPLITSCREEN_ADDUSER = 0; 63 | MSG_SPLITSCREEN_REMOVEUSER = 1; 64 | } 65 | 66 | message CMsg_CVars { 67 | message CVar { 68 | optional string name = 1; 69 | optional string value = 2; 70 | } 71 | 72 | repeated .CMsg_CVars.CVar cvars = 1; 73 | } 74 | 75 | message CNETMsg_NOP { 76 | } 77 | 78 | message CNETMsg_Disconnect { 79 | optional string text = 1; 80 | } 81 | 82 | message CNETMsg_File { 83 | optional int32 transfer_id = 1; 84 | optional string file_name = 2; 85 | optional bool is_replay_demo_file = 3; 86 | optional bool deny = 4; 87 | } 88 | 89 | message CNETMsg_SplitScreenUser { 90 | optional int32 slot = 1; 91 | } 92 | 93 | message CNETMsg_Tick { 94 | optional uint32 tick = 1; 95 | optional uint32 host_frametime = 2; 96 | optional uint32 host_frametime_std_deviation = 3; 97 | } 98 | 99 | message CNETMsg_StringCmd { 100 | optional string command = 1; 101 | } 102 | 103 | message CNETMsg_SetConVar { 104 | optional .CMsg_CVars convars = 1; 105 | } 106 | 107 | message CNETMsg_SignonState { 108 | optional uint32 signon_state = 1; 109 | optional uint32 spawn_count = 2; 110 | optional uint32 num_server_players = 3; 111 | repeated string players_networkids = 4; 112 | optional string map_name = 5; 113 | } 114 | 115 | message CCLCMsg_ClientInfo { 116 | optional fixed32 send_table_crc = 1; 117 | optional uint32 server_count = 2; 118 | optional bool is_hltv = 3; 119 | optional bool is_replay = 4; 120 | optional uint32 friends_id = 5; 121 | optional string friends_name = 6; 122 | repeated fixed32 custom_files = 7; 123 | } 124 | 125 | message CCLCMsg_Move { 126 | optional uint32 num_backup_commands = 1; 127 | optional uint32 num_new_commands = 2; 128 | optional bytes data = 3; 129 | } 130 | 131 | message CCLCMsg_VoiceData { 132 | optional bytes data = 1; 133 | optional fixed64 xuid = 2; 134 | optional .VoiceDataFormat_t format = 3 [default = VOICEDATA_FORMAT_STEAM]; 135 | } 136 | 137 | message CCLCMsg_BaselineAck { 138 | optional int32 baseline_tick = 1; 139 | optional int32 baseline_nr = 2; 140 | } 141 | 142 | message CCLCMsg_ListenEvents { 143 | repeated fixed32 event_mask = 1; 144 | } 145 | 146 | message CCLCMsg_RespondCvarValue { 147 | optional int32 cookie = 1; 148 | optional int32 status_code = 2; 149 | optional string name = 3; 150 | optional string value = 4; 151 | } 152 | 153 | message CCLCMsg_FileCRCCheck { 154 | optional int32 code_path = 1; 155 | optional string path = 2; 156 | optional int32 code_filename = 3; 157 | optional string filename = 4; 158 | optional fixed32 crc = 5; 159 | } 160 | 161 | message CCLCMsg_LoadingProgress { 162 | optional int32 progress = 1; 163 | } 164 | 165 | message CCLCMsg_SplitPlayerConnect { 166 | optional .CMsg_CVars convars = 1; 167 | } 168 | 169 | message CCLCMsg_ClientMessage { 170 | optional int32 msg_type = 1; 171 | optional bytes data = 2; 172 | } 173 | 174 | message CSVCMsg_ServerInfo { 175 | optional int32 protocol = 1; 176 | optional int32 server_count = 2; 177 | optional bool is_dedicated = 3; 178 | optional bool is_hltv = 4; 179 | optional bool is_replay = 5; 180 | optional int32 c_os = 6; 181 | optional fixed32 map_crc = 7; 182 | optional fixed32 client_crc = 8; 183 | optional fixed32 string_table_crc = 9; 184 | optional int32 max_clients = 10; 185 | optional int32 max_classes = 11; 186 | optional int32 player_slot = 12; 187 | optional float tick_interval = 13; 188 | optional string game_dir = 14; 189 | optional string map_name = 15; 190 | optional string sky_name = 16; 191 | optional string host_name = 17; 192 | } 193 | 194 | message CSVCMsg_ClassInfo { 195 | message class_t { 196 | optional int32 class_id = 1; 197 | optional string data_table_name = 2; 198 | optional string class_name = 3; 199 | } 200 | 201 | optional bool create_on_client = 1; 202 | repeated .CSVCMsg_ClassInfo.class_t classes = 2; 203 | } 204 | 205 | message CSVCMsg_SetPause { 206 | optional bool paused = 1; 207 | } 208 | 209 | message CSVCMsg_VoiceInit { 210 | optional int32 quality = 1; 211 | optional string codec = 2; 212 | optional int32 version = 3 [default = 0]; 213 | } 214 | 215 | message CSVCMsg_Print { 216 | optional string text = 1; 217 | } 218 | 219 | message CSVCMsg_Sounds { 220 | message sounddata_t { 221 | optional sint32 origin_x = 1; 222 | optional sint32 origin_y = 2; 223 | optional sint32 origin_z = 3; 224 | optional uint32 volume = 4; 225 | optional float delay_value = 5; 226 | optional int32 sequence_number = 6; 227 | optional int32 entity_index = 7; 228 | optional int32 channel = 8; 229 | optional int32 pitch = 9; 230 | optional int32 flags = 10; 231 | optional uint32 sound_num = 11; 232 | optional fixed32 sound_num_handle = 12; 233 | optional int32 speaker_entity = 13; 234 | optional int32 random_seed = 14; 235 | optional int32 sound_level = 15; 236 | optional bool is_sentence = 16; 237 | optional bool is_ambient = 17; 238 | } 239 | 240 | optional bool reliable_sound = 1; 241 | repeated .CSVCMsg_Sounds.sounddata_t sounds = 2; 242 | } 243 | 244 | message CSVCMsg_Prefetch { 245 | optional int32 sound_index = 1; 246 | } 247 | 248 | message CSVCMsg_SetView { 249 | optional int32 entity_index = 1; 250 | } 251 | 252 | message CSVCMsg_FixAngle { 253 | optional bool relative = 1; 254 | optional .CMsgQAngle angle = 2; 255 | } 256 | 257 | message CSVCMsg_CrosshairAngle { 258 | optional .CMsgQAngle angle = 1; 259 | } 260 | 261 | message CSVCMsg_BSPDecal { 262 | optional .CMsgVector pos = 1; 263 | optional int32 decal_texture_index = 2; 264 | optional int32 entity_index = 3; 265 | optional int32 model_index = 4; 266 | optional bool low_priority = 5; 267 | } 268 | 269 | message CSVCMsg_SplitScreen { 270 | optional .ESplitScreenMessageType type = 1 [default = MSG_SPLITSCREEN_ADDUSER]; 271 | optional int32 slot = 2; 272 | optional int32 player_index = 3; 273 | } 274 | 275 | message CSVCMsg_GetCvarValue { 276 | optional int32 cookie = 1; 277 | optional string cvar_name = 2; 278 | } 279 | 280 | message CSVCMsg_Menu { 281 | optional int32 dialog_type = 1; 282 | optional bytes menu_key_values = 2; 283 | } 284 | 285 | message CSVCMsg_SendTable { 286 | message sendprop_t { 287 | optional int32 type = 1; 288 | optional string var_name = 2; 289 | optional int32 flags = 3; 290 | optional int32 priority = 4; 291 | optional string dt_name = 5; 292 | optional int32 num_elements = 6; 293 | optional float low_value = 7; 294 | optional float high_value = 8; 295 | optional int32 num_bits = 9; 296 | } 297 | 298 | optional bool is_end = 1; 299 | optional string net_table_name = 2; 300 | optional bool needs_decoder = 3; 301 | repeated .CSVCMsg_SendTable.sendprop_t props = 4; 302 | } 303 | 304 | message CSVCMsg_GameEventList { 305 | message key_t { 306 | optional int32 type = 1; 307 | optional string name = 2; 308 | } 309 | 310 | message descriptor_t { 311 | optional int32 eventid = 1; 312 | optional string name = 2; 313 | repeated .CSVCMsg_GameEventList.key_t keys = 3; 314 | } 315 | 316 | repeated .CSVCMsg_GameEventList.descriptor_t descriptors = 1; 317 | } 318 | 319 | message CSVCMsg_PacketEntities { 320 | optional int32 max_entries = 1; 321 | optional int32 updated_entries = 2; 322 | optional bool is_delta = 3; 323 | optional bool update_baseline = 4; 324 | optional int32 baseline = 5; 325 | optional int32 delta_from = 6; 326 | optional bytes entity_data = 7; 327 | } 328 | 329 | message CSVCMsg_TempEntities { 330 | optional bool reliable = 1; 331 | optional int32 num_entries = 2; 332 | optional bytes entity_data = 3; 333 | } 334 | 335 | message CSVCMsg_CreateStringTable { 336 | optional string name = 1; 337 | optional int32 max_entries = 2; 338 | optional int32 num_entries = 3; 339 | optional bool user_data_fixed_size = 4; 340 | optional int32 user_data_size = 5; 341 | optional int32 user_data_size_bits = 6; 342 | optional int32 flags = 7; 343 | optional bytes string_data = 8; 344 | } 345 | 346 | message CSVCMsg_UpdateStringTable { 347 | optional int32 table_id = 1; 348 | optional int32 num_changed_entries = 2; 349 | optional bytes string_data = 3; 350 | } 351 | 352 | message CSVCMsg_VoiceData { 353 | optional int32 client = 1; 354 | optional bool proximity = 2; 355 | optional fixed64 xuid = 3; 356 | optional int32 audible_mask = 4; 357 | optional bytes voice_data = 5; 358 | optional .VoiceDataFormat_t format = 6 [default = VOICEDATA_FORMAT_STEAM]; 359 | } 360 | 361 | message CSVCMsg_PacketReliable { 362 | optional int32 tick = 1; 363 | optional int32 messagessize = 2; 364 | } 365 | 366 | -------------------------------------------------------------------------------- /skadi/protoc/dota_modifiers_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: dota_modifiers.proto 3 | 4 | from google.protobuf.internal import enum_type_wrapper 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import descriptor_pb2 9 | # @@protoc_insertion_point(imports) 10 | 11 | 12 | import google.protobuf.descriptor_pb2 13 | import networkbasetypes_pb2 14 | 15 | 16 | DESCRIPTOR = _descriptor.FileDescriptor( 17 | name='dota_modifiers.proto', 18 | package='', 19 | serialized_pb='\n\x14\x64ota_modifiers.proto\x1a google/protobuf/descriptor.proto\x1a\x16networkbasetypes.proto\"\xe4\x04\n\x1b\x43\x44OTAModifierBuffTableEntry\x12N\n\nentry_type\x18\x01 \x02(\x0e\x32\x19.DOTA_MODIFIER_ENTRY_TYPE:\x1f\x44OTA_MODIFIER_ENTRY_TYPE_ACTIVE\x12\x0e\n\x06parent\x18\x02 \x02(\x05\x12\r\n\x05index\x18\x03 \x02(\x05\x12\x12\n\nserial_num\x18\x04 \x02(\x05\x12\x0c\n\x04name\x18\x05 \x01(\x05\x12\x15\n\rability_level\x18\x06 \x01(\x05\x12\x13\n\x0bstack_count\x18\x07 \x01(\x05\x12\x15\n\rcreation_time\x18\x08 \x01(\x02\x12\x14\n\x08\x64uration\x18\t \x01(\x02:\x02-1\x12\x0e\n\x06\x63\x61ster\x18\n \x01(\x05\x12\x0f\n\x07\x61\x62ility\x18\x0b \x01(\x05\x12\r\n\x05\x61rmor\x18\x0c \x01(\x05\x12\x11\n\tfade_time\x18\r \x01(\x02\x12\x0e\n\x06subtle\x18\x0e \x01(\x08\x12\x14\n\x0c\x63hannel_time\x18\x0f \x01(\x02\x12\x1c\n\x07v_start\x18\x10 \x01(\x0b\x32\x0b.CMsgVector\x12\x1a\n\x05v_end\x18\x11 \x01(\x0b\x32\x0b.CMsgVector\x12\x1a\n\x12portal_loop_appear\x18\x12 \x01(\t\x12\x1d\n\x15portal_loop_disappear\x18\x13 \x01(\t\x12\x18\n\x10hero_loop_appear\x18\x14 \x01(\t\x12\x1b\n\x13hero_loop_disappear\x18\x15 \x01(\t\x12\x16\n\x0emovement_speed\x18\x16 \x01(\x05\x12\x0c\n\x04\x61ura\x18\x17 \x01(\x08\x12\x10\n\x08\x61\x63tivity\x18\x18 \x01(\x05\x12\x0e\n\x06\x64\x61mage\x18\x19 \x01(\x05*e\n\x18\x44OTA_MODIFIER_ENTRY_TYPE\x12#\n\x1f\x44OTA_MODIFIER_ENTRY_TYPE_ACTIVE\x10\x01\x12$\n DOTA_MODIFIER_ENTRY_TYPE_REMOVED\x10\x02') 20 | 21 | _DOTA_MODIFIER_ENTRY_TYPE = _descriptor.EnumDescriptor( 22 | name='DOTA_MODIFIER_ENTRY_TYPE', 23 | full_name='DOTA_MODIFIER_ENTRY_TYPE', 24 | filename=None, 25 | file=DESCRIPTOR, 26 | values=[ 27 | _descriptor.EnumValueDescriptor( 28 | name='DOTA_MODIFIER_ENTRY_TYPE_ACTIVE', index=0, number=1, 29 | options=None, 30 | type=None), 31 | _descriptor.EnumValueDescriptor( 32 | name='DOTA_MODIFIER_ENTRY_TYPE_REMOVED', index=1, number=2, 33 | options=None, 34 | type=None), 35 | ], 36 | containing_type=None, 37 | options=None, 38 | serialized_start=697, 39 | serialized_end=798, 40 | ) 41 | 42 | DOTA_MODIFIER_ENTRY_TYPE = enum_type_wrapper.EnumTypeWrapper(_DOTA_MODIFIER_ENTRY_TYPE) 43 | DOTA_MODIFIER_ENTRY_TYPE_ACTIVE = 1 44 | DOTA_MODIFIER_ENTRY_TYPE_REMOVED = 2 45 | 46 | 47 | 48 | _CDOTAMODIFIERBUFFTABLEENTRY = _descriptor.Descriptor( 49 | name='CDOTAModifierBuffTableEntry', 50 | full_name='CDOTAModifierBuffTableEntry', 51 | filename=None, 52 | file=DESCRIPTOR, 53 | containing_type=None, 54 | fields=[ 55 | _descriptor.FieldDescriptor( 56 | name='entry_type', full_name='CDOTAModifierBuffTableEntry.entry_type', index=0, 57 | number=1, type=14, cpp_type=8, label=2, 58 | has_default_value=True, default_value=1, 59 | message_type=None, enum_type=None, containing_type=None, 60 | is_extension=False, extension_scope=None, 61 | options=None), 62 | _descriptor.FieldDescriptor( 63 | name='parent', full_name='CDOTAModifierBuffTableEntry.parent', index=1, 64 | number=2, type=5, cpp_type=1, label=2, 65 | has_default_value=False, default_value=0, 66 | message_type=None, enum_type=None, containing_type=None, 67 | is_extension=False, extension_scope=None, 68 | options=None), 69 | _descriptor.FieldDescriptor( 70 | name='index', full_name='CDOTAModifierBuffTableEntry.index', index=2, 71 | number=3, type=5, cpp_type=1, label=2, 72 | has_default_value=False, default_value=0, 73 | message_type=None, enum_type=None, containing_type=None, 74 | is_extension=False, extension_scope=None, 75 | options=None), 76 | _descriptor.FieldDescriptor( 77 | name='serial_num', full_name='CDOTAModifierBuffTableEntry.serial_num', index=3, 78 | number=4, type=5, cpp_type=1, label=2, 79 | has_default_value=False, default_value=0, 80 | message_type=None, enum_type=None, containing_type=None, 81 | is_extension=False, extension_scope=None, 82 | options=None), 83 | _descriptor.FieldDescriptor( 84 | name='name', full_name='CDOTAModifierBuffTableEntry.name', index=4, 85 | number=5, type=5, cpp_type=1, label=1, 86 | has_default_value=False, default_value=0, 87 | message_type=None, enum_type=None, containing_type=None, 88 | is_extension=False, extension_scope=None, 89 | options=None), 90 | _descriptor.FieldDescriptor( 91 | name='ability_level', full_name='CDOTAModifierBuffTableEntry.ability_level', index=5, 92 | number=6, type=5, cpp_type=1, label=1, 93 | has_default_value=False, default_value=0, 94 | message_type=None, enum_type=None, containing_type=None, 95 | is_extension=False, extension_scope=None, 96 | options=None), 97 | _descriptor.FieldDescriptor( 98 | name='stack_count', full_name='CDOTAModifierBuffTableEntry.stack_count', index=6, 99 | number=7, type=5, cpp_type=1, label=1, 100 | has_default_value=False, default_value=0, 101 | message_type=None, enum_type=None, containing_type=None, 102 | is_extension=False, extension_scope=None, 103 | options=None), 104 | _descriptor.FieldDescriptor( 105 | name='creation_time', full_name='CDOTAModifierBuffTableEntry.creation_time', index=7, 106 | number=8, type=2, cpp_type=6, label=1, 107 | has_default_value=False, default_value=0, 108 | message_type=None, enum_type=None, containing_type=None, 109 | is_extension=False, extension_scope=None, 110 | options=None), 111 | _descriptor.FieldDescriptor( 112 | name='duration', full_name='CDOTAModifierBuffTableEntry.duration', index=8, 113 | number=9, type=2, cpp_type=6, label=1, 114 | has_default_value=True, default_value=-1, 115 | message_type=None, enum_type=None, containing_type=None, 116 | is_extension=False, extension_scope=None, 117 | options=None), 118 | _descriptor.FieldDescriptor( 119 | name='caster', full_name='CDOTAModifierBuffTableEntry.caster', index=9, 120 | number=10, type=5, cpp_type=1, label=1, 121 | has_default_value=False, default_value=0, 122 | message_type=None, enum_type=None, containing_type=None, 123 | is_extension=False, extension_scope=None, 124 | options=None), 125 | _descriptor.FieldDescriptor( 126 | name='ability', full_name='CDOTAModifierBuffTableEntry.ability', index=10, 127 | number=11, type=5, cpp_type=1, label=1, 128 | has_default_value=False, default_value=0, 129 | message_type=None, enum_type=None, containing_type=None, 130 | is_extension=False, extension_scope=None, 131 | options=None), 132 | _descriptor.FieldDescriptor( 133 | name='armor', full_name='CDOTAModifierBuffTableEntry.armor', index=11, 134 | number=12, type=5, cpp_type=1, label=1, 135 | has_default_value=False, default_value=0, 136 | message_type=None, enum_type=None, containing_type=None, 137 | is_extension=False, extension_scope=None, 138 | options=None), 139 | _descriptor.FieldDescriptor( 140 | name='fade_time', full_name='CDOTAModifierBuffTableEntry.fade_time', index=12, 141 | number=13, type=2, cpp_type=6, label=1, 142 | has_default_value=False, default_value=0, 143 | message_type=None, enum_type=None, containing_type=None, 144 | is_extension=False, extension_scope=None, 145 | options=None), 146 | _descriptor.FieldDescriptor( 147 | name='subtle', full_name='CDOTAModifierBuffTableEntry.subtle', index=13, 148 | number=14, type=8, cpp_type=7, label=1, 149 | has_default_value=False, default_value=False, 150 | message_type=None, enum_type=None, containing_type=None, 151 | is_extension=False, extension_scope=None, 152 | options=None), 153 | _descriptor.FieldDescriptor( 154 | name='channel_time', full_name='CDOTAModifierBuffTableEntry.channel_time', index=14, 155 | number=15, type=2, cpp_type=6, label=1, 156 | has_default_value=False, default_value=0, 157 | message_type=None, enum_type=None, containing_type=None, 158 | is_extension=False, extension_scope=None, 159 | options=None), 160 | _descriptor.FieldDescriptor( 161 | name='v_start', full_name='CDOTAModifierBuffTableEntry.v_start', index=15, 162 | number=16, type=11, cpp_type=10, label=1, 163 | has_default_value=False, default_value=None, 164 | message_type=None, enum_type=None, containing_type=None, 165 | is_extension=False, extension_scope=None, 166 | options=None), 167 | _descriptor.FieldDescriptor( 168 | name='v_end', full_name='CDOTAModifierBuffTableEntry.v_end', index=16, 169 | number=17, type=11, cpp_type=10, label=1, 170 | has_default_value=False, default_value=None, 171 | message_type=None, enum_type=None, containing_type=None, 172 | is_extension=False, extension_scope=None, 173 | options=None), 174 | _descriptor.FieldDescriptor( 175 | name='portal_loop_appear', full_name='CDOTAModifierBuffTableEntry.portal_loop_appear', index=17, 176 | number=18, type=9, cpp_type=9, label=1, 177 | has_default_value=False, default_value=unicode("", "utf-8"), 178 | message_type=None, enum_type=None, containing_type=None, 179 | is_extension=False, extension_scope=None, 180 | options=None), 181 | _descriptor.FieldDescriptor( 182 | name='portal_loop_disappear', full_name='CDOTAModifierBuffTableEntry.portal_loop_disappear', index=18, 183 | number=19, type=9, cpp_type=9, label=1, 184 | has_default_value=False, default_value=unicode("", "utf-8"), 185 | message_type=None, enum_type=None, containing_type=None, 186 | is_extension=False, extension_scope=None, 187 | options=None), 188 | _descriptor.FieldDescriptor( 189 | name='hero_loop_appear', full_name='CDOTAModifierBuffTableEntry.hero_loop_appear', index=19, 190 | number=20, type=9, cpp_type=9, label=1, 191 | has_default_value=False, default_value=unicode("", "utf-8"), 192 | message_type=None, enum_type=None, containing_type=None, 193 | is_extension=False, extension_scope=None, 194 | options=None), 195 | _descriptor.FieldDescriptor( 196 | name='hero_loop_disappear', full_name='CDOTAModifierBuffTableEntry.hero_loop_disappear', index=20, 197 | number=21, type=9, cpp_type=9, label=1, 198 | has_default_value=False, default_value=unicode("", "utf-8"), 199 | message_type=None, enum_type=None, containing_type=None, 200 | is_extension=False, extension_scope=None, 201 | options=None), 202 | _descriptor.FieldDescriptor( 203 | name='movement_speed', full_name='CDOTAModifierBuffTableEntry.movement_speed', index=21, 204 | number=22, type=5, cpp_type=1, label=1, 205 | has_default_value=False, default_value=0, 206 | message_type=None, enum_type=None, containing_type=None, 207 | is_extension=False, extension_scope=None, 208 | options=None), 209 | _descriptor.FieldDescriptor( 210 | name='aura', full_name='CDOTAModifierBuffTableEntry.aura', index=22, 211 | number=23, type=8, cpp_type=7, label=1, 212 | has_default_value=False, default_value=False, 213 | message_type=None, enum_type=None, containing_type=None, 214 | is_extension=False, extension_scope=None, 215 | options=None), 216 | _descriptor.FieldDescriptor( 217 | name='activity', full_name='CDOTAModifierBuffTableEntry.activity', index=23, 218 | number=24, type=5, cpp_type=1, label=1, 219 | has_default_value=False, default_value=0, 220 | message_type=None, enum_type=None, containing_type=None, 221 | is_extension=False, extension_scope=None, 222 | options=None), 223 | _descriptor.FieldDescriptor( 224 | name='damage', full_name='CDOTAModifierBuffTableEntry.damage', index=24, 225 | number=25, type=5, cpp_type=1, label=1, 226 | has_default_value=False, default_value=0, 227 | message_type=None, enum_type=None, containing_type=None, 228 | is_extension=False, extension_scope=None, 229 | options=None), 230 | ], 231 | extensions=[ 232 | ], 233 | nested_types=[], 234 | enum_types=[ 235 | ], 236 | options=None, 237 | is_extendable=False, 238 | extension_ranges=[], 239 | serialized_start=83, 240 | serialized_end=695, 241 | ) 242 | 243 | _CDOTAMODIFIERBUFFTABLEENTRY.fields_by_name['entry_type'].enum_type = _DOTA_MODIFIER_ENTRY_TYPE 244 | _CDOTAMODIFIERBUFFTABLEENTRY.fields_by_name['v_start'].message_type = networkbasetypes_pb2._CMSGVECTOR 245 | _CDOTAMODIFIERBUFFTABLEENTRY.fields_by_name['v_end'].message_type = networkbasetypes_pb2._CMSGVECTOR 246 | DESCRIPTOR.message_types_by_name['CDOTAModifierBuffTableEntry'] = _CDOTAMODIFIERBUFFTABLEENTRY 247 | 248 | class CDOTAModifierBuffTableEntry(_message.Message): 249 | __metaclass__ = _reflection.GeneratedProtocolMessageType 250 | DESCRIPTOR = _CDOTAMODIFIERBUFFTABLEENTRY 251 | 252 | # @@protoc_insertion_point(class_scope:CDOTAModifierBuffTableEntry) 253 | 254 | 255 | # @@protoc_insertion_point(module_scope) 256 | -------------------------------------------------------------------------------- /skadi/protoc/dota_commonmessages_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: dota_commonmessages.proto 3 | 4 | from google.protobuf.internal import enum_type_wrapper 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import descriptor_pb2 9 | # @@protoc_insertion_point(imports) 10 | 11 | 12 | import google.protobuf.descriptor_pb2 13 | import networkbasetypes_pb2 14 | 15 | 16 | DESCRIPTOR = _descriptor.FileDescriptor( 17 | name='dota_commonmessages.proto', 18 | package='', 19 | serialized_pb='\n\x19\x64ota_commonmessages.proto\x1a google/protobuf/descriptor.proto\x1a\x16networkbasetypes.proto\"`\n\x15\x43\x44OTAMsg_LocationPing\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\x12\x0e\n\x06target\x18\x03 \x01(\x05\x12\x13\n\x0b\x64irect_ping\x18\x04 \x01(\x08\x12\x0c\n\x04type\x18\x05 \x01(\x05\":\n\x12\x43\x44OTAMsg_ItemAlert\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\x12\x0e\n\x06itemid\x18\x03 \x01(\x05\"9\n\x10\x43\x44OTAMsg_MapLine\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\x12\x0f\n\x07initial\x18\x03 \x01(\x08\"S\n\x12\x43\x44OTAMsg_WorldLine\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\x12\t\n\x01z\x18\x03 \x01(\x05\x12\x0f\n\x07initial\x18\x04 \x01(\x08\x12\x0b\n\x03\x65nd\x18\x05 \x01(\x08\"~\n\x16\x43\x44OTAMsg_SendStatPopup\x12\x39\n\x05style\x18\x01 \x01(\x0e\x32\x14.EDOTAStatPopupTypes:\x14k_EDOTA_SPT_Textline\x12\x14\n\x0cstat_strings\x18\x02 \x03(\t\x12\x13\n\x0bstat_images\x18\x03 \x03(\x05*\xb7\x02\n\x15\x45\x44OTAChatWheelMessage\x12\x11\n\rk_EDOTA_CW_Ok\x10\x00\x12\x13\n\x0fk_EDOTA_CW_Care\x10\x01\x12\x16\n\x12k_EDOTA_CW_GetBack\x10\x02\x12\x18\n\x14k_EDOTA_CW_NeedWards\x10\x03\x12\x13\n\x0fk_EDOTA_CW_Stun\x10\x04\x12\x13\n\x0fk_EDOTA_CW_Help\x10\x05\x12\x13\n\x0fk_EDOTA_CW_Push\x10\x06\x12\x16\n\x12k_EDOTA_CW_GoodJob\x10\x07\x12\x16\n\x12k_EDOTA_CW_Missing\x10\x08\x12\x1a\n\x16k_EDOTA_CW_Missing_Top\x10\t\x12\x1a\n\x16k_EDOTA_CW_Missing_Mid\x10\n\x12\x1d\n\x19k_EDOTA_CW_Missing_Bottom\x10\x0b*\\\n\x13\x45\x44OTAStatPopupTypes\x12\x18\n\x14k_EDOTA_SPT_Textline\x10\x00\x12\x15\n\x11k_EDOTA_SPT_Basic\x10\x01\x12\x14\n\x10k_EDOTA_SPT_Poll\x10\x02') 20 | 21 | _EDOTACHATWHEELMESSAGE = _descriptor.EnumDescriptor( 22 | name='EDOTAChatWheelMessage', 23 | full_name='EDOTAChatWheelMessage', 24 | filename=None, 25 | file=DESCRIPTOR, 26 | values=[ 27 | _descriptor.EnumValueDescriptor( 28 | name='k_EDOTA_CW_Ok', index=0, number=0, 29 | options=None, 30 | type=None), 31 | _descriptor.EnumValueDescriptor( 32 | name='k_EDOTA_CW_Care', index=1, number=1, 33 | options=None, 34 | type=None), 35 | _descriptor.EnumValueDescriptor( 36 | name='k_EDOTA_CW_GetBack', index=2, number=2, 37 | options=None, 38 | type=None), 39 | _descriptor.EnumValueDescriptor( 40 | name='k_EDOTA_CW_NeedWards', index=3, number=3, 41 | options=None, 42 | type=None), 43 | _descriptor.EnumValueDescriptor( 44 | name='k_EDOTA_CW_Stun', index=4, number=4, 45 | options=None, 46 | type=None), 47 | _descriptor.EnumValueDescriptor( 48 | name='k_EDOTA_CW_Help', index=5, number=5, 49 | options=None, 50 | type=None), 51 | _descriptor.EnumValueDescriptor( 52 | name='k_EDOTA_CW_Push', index=6, number=6, 53 | options=None, 54 | type=None), 55 | _descriptor.EnumValueDescriptor( 56 | name='k_EDOTA_CW_GoodJob', index=7, number=7, 57 | options=None, 58 | type=None), 59 | _descriptor.EnumValueDescriptor( 60 | name='k_EDOTA_CW_Missing', index=8, number=8, 61 | options=None, 62 | type=None), 63 | _descriptor.EnumValueDescriptor( 64 | name='k_EDOTA_CW_Missing_Top', index=9, number=9, 65 | options=None, 66 | type=None), 67 | _descriptor.EnumValueDescriptor( 68 | name='k_EDOTA_CW_Missing_Mid', index=10, number=10, 69 | options=None, 70 | type=None), 71 | _descriptor.EnumValueDescriptor( 72 | name='k_EDOTA_CW_Missing_Bottom', index=11, number=11, 73 | options=None, 74 | type=None), 75 | ], 76 | containing_type=None, 77 | options=None, 78 | serialized_start=518, 79 | serialized_end=829, 80 | ) 81 | 82 | EDOTAChatWheelMessage = enum_type_wrapper.EnumTypeWrapper(_EDOTACHATWHEELMESSAGE) 83 | _EDOTASTATPOPUPTYPES = _descriptor.EnumDescriptor( 84 | name='EDOTAStatPopupTypes', 85 | full_name='EDOTAStatPopupTypes', 86 | filename=None, 87 | file=DESCRIPTOR, 88 | values=[ 89 | _descriptor.EnumValueDescriptor( 90 | name='k_EDOTA_SPT_Textline', index=0, number=0, 91 | options=None, 92 | type=None), 93 | _descriptor.EnumValueDescriptor( 94 | name='k_EDOTA_SPT_Basic', index=1, number=1, 95 | options=None, 96 | type=None), 97 | _descriptor.EnumValueDescriptor( 98 | name='k_EDOTA_SPT_Poll', index=2, number=2, 99 | options=None, 100 | type=None), 101 | ], 102 | containing_type=None, 103 | options=None, 104 | serialized_start=831, 105 | serialized_end=923, 106 | ) 107 | 108 | EDOTAStatPopupTypes = enum_type_wrapper.EnumTypeWrapper(_EDOTASTATPOPUPTYPES) 109 | k_EDOTA_CW_Ok = 0 110 | k_EDOTA_CW_Care = 1 111 | k_EDOTA_CW_GetBack = 2 112 | k_EDOTA_CW_NeedWards = 3 113 | k_EDOTA_CW_Stun = 4 114 | k_EDOTA_CW_Help = 5 115 | k_EDOTA_CW_Push = 6 116 | k_EDOTA_CW_GoodJob = 7 117 | k_EDOTA_CW_Missing = 8 118 | k_EDOTA_CW_Missing_Top = 9 119 | k_EDOTA_CW_Missing_Mid = 10 120 | k_EDOTA_CW_Missing_Bottom = 11 121 | k_EDOTA_SPT_Textline = 0 122 | k_EDOTA_SPT_Basic = 1 123 | k_EDOTA_SPT_Poll = 2 124 | 125 | 126 | 127 | _CDOTAMSG_LOCATIONPING = _descriptor.Descriptor( 128 | name='CDOTAMsg_LocationPing', 129 | full_name='CDOTAMsg_LocationPing', 130 | filename=None, 131 | file=DESCRIPTOR, 132 | containing_type=None, 133 | fields=[ 134 | _descriptor.FieldDescriptor( 135 | name='x', full_name='CDOTAMsg_LocationPing.x', index=0, 136 | number=1, type=5, cpp_type=1, label=1, 137 | has_default_value=False, default_value=0, 138 | message_type=None, enum_type=None, containing_type=None, 139 | is_extension=False, extension_scope=None, 140 | options=None), 141 | _descriptor.FieldDescriptor( 142 | name='y', full_name='CDOTAMsg_LocationPing.y', index=1, 143 | number=2, type=5, cpp_type=1, label=1, 144 | has_default_value=False, default_value=0, 145 | message_type=None, enum_type=None, containing_type=None, 146 | is_extension=False, extension_scope=None, 147 | options=None), 148 | _descriptor.FieldDescriptor( 149 | name='target', full_name='CDOTAMsg_LocationPing.target', index=2, 150 | number=3, type=5, cpp_type=1, label=1, 151 | has_default_value=False, default_value=0, 152 | message_type=None, enum_type=None, containing_type=None, 153 | is_extension=False, extension_scope=None, 154 | options=None), 155 | _descriptor.FieldDescriptor( 156 | name='direct_ping', full_name='CDOTAMsg_LocationPing.direct_ping', index=3, 157 | number=4, type=8, cpp_type=7, label=1, 158 | has_default_value=False, default_value=False, 159 | message_type=None, enum_type=None, containing_type=None, 160 | is_extension=False, extension_scope=None, 161 | options=None), 162 | _descriptor.FieldDescriptor( 163 | name='type', full_name='CDOTAMsg_LocationPing.type', index=4, 164 | number=5, type=5, cpp_type=1, label=1, 165 | has_default_value=False, default_value=0, 166 | message_type=None, enum_type=None, containing_type=None, 167 | is_extension=False, extension_scope=None, 168 | options=None), 169 | ], 170 | extensions=[ 171 | ], 172 | nested_types=[], 173 | enum_types=[ 174 | ], 175 | options=None, 176 | is_extendable=False, 177 | extension_ranges=[], 178 | serialized_start=87, 179 | serialized_end=183, 180 | ) 181 | 182 | 183 | _CDOTAMSG_ITEMALERT = _descriptor.Descriptor( 184 | name='CDOTAMsg_ItemAlert', 185 | full_name='CDOTAMsg_ItemAlert', 186 | filename=None, 187 | file=DESCRIPTOR, 188 | containing_type=None, 189 | fields=[ 190 | _descriptor.FieldDescriptor( 191 | name='x', full_name='CDOTAMsg_ItemAlert.x', index=0, 192 | number=1, type=5, cpp_type=1, label=1, 193 | has_default_value=False, default_value=0, 194 | message_type=None, enum_type=None, containing_type=None, 195 | is_extension=False, extension_scope=None, 196 | options=None), 197 | _descriptor.FieldDescriptor( 198 | name='y', full_name='CDOTAMsg_ItemAlert.y', index=1, 199 | number=2, type=5, cpp_type=1, label=1, 200 | has_default_value=False, default_value=0, 201 | message_type=None, enum_type=None, containing_type=None, 202 | is_extension=False, extension_scope=None, 203 | options=None), 204 | _descriptor.FieldDescriptor( 205 | name='itemid', full_name='CDOTAMsg_ItemAlert.itemid', index=2, 206 | number=3, type=5, cpp_type=1, label=1, 207 | has_default_value=False, default_value=0, 208 | message_type=None, enum_type=None, containing_type=None, 209 | is_extension=False, extension_scope=None, 210 | options=None), 211 | ], 212 | extensions=[ 213 | ], 214 | nested_types=[], 215 | enum_types=[ 216 | ], 217 | options=None, 218 | is_extendable=False, 219 | extension_ranges=[], 220 | serialized_start=185, 221 | serialized_end=243, 222 | ) 223 | 224 | 225 | _CDOTAMSG_MAPLINE = _descriptor.Descriptor( 226 | name='CDOTAMsg_MapLine', 227 | full_name='CDOTAMsg_MapLine', 228 | filename=None, 229 | file=DESCRIPTOR, 230 | containing_type=None, 231 | fields=[ 232 | _descriptor.FieldDescriptor( 233 | name='x', full_name='CDOTAMsg_MapLine.x', index=0, 234 | number=1, type=5, cpp_type=1, label=1, 235 | has_default_value=False, default_value=0, 236 | message_type=None, enum_type=None, containing_type=None, 237 | is_extension=False, extension_scope=None, 238 | options=None), 239 | _descriptor.FieldDescriptor( 240 | name='y', full_name='CDOTAMsg_MapLine.y', index=1, 241 | number=2, type=5, cpp_type=1, label=1, 242 | has_default_value=False, default_value=0, 243 | message_type=None, enum_type=None, containing_type=None, 244 | is_extension=False, extension_scope=None, 245 | options=None), 246 | _descriptor.FieldDescriptor( 247 | name='initial', full_name='CDOTAMsg_MapLine.initial', index=2, 248 | number=3, type=8, cpp_type=7, label=1, 249 | has_default_value=False, default_value=False, 250 | message_type=None, enum_type=None, containing_type=None, 251 | is_extension=False, extension_scope=None, 252 | options=None), 253 | ], 254 | extensions=[ 255 | ], 256 | nested_types=[], 257 | enum_types=[ 258 | ], 259 | options=None, 260 | is_extendable=False, 261 | extension_ranges=[], 262 | serialized_start=245, 263 | serialized_end=302, 264 | ) 265 | 266 | 267 | _CDOTAMSG_WORLDLINE = _descriptor.Descriptor( 268 | name='CDOTAMsg_WorldLine', 269 | full_name='CDOTAMsg_WorldLine', 270 | filename=None, 271 | file=DESCRIPTOR, 272 | containing_type=None, 273 | fields=[ 274 | _descriptor.FieldDescriptor( 275 | name='x', full_name='CDOTAMsg_WorldLine.x', index=0, 276 | number=1, type=5, cpp_type=1, label=1, 277 | has_default_value=False, default_value=0, 278 | message_type=None, enum_type=None, containing_type=None, 279 | is_extension=False, extension_scope=None, 280 | options=None), 281 | _descriptor.FieldDescriptor( 282 | name='y', full_name='CDOTAMsg_WorldLine.y', index=1, 283 | number=2, type=5, cpp_type=1, label=1, 284 | has_default_value=False, default_value=0, 285 | message_type=None, enum_type=None, containing_type=None, 286 | is_extension=False, extension_scope=None, 287 | options=None), 288 | _descriptor.FieldDescriptor( 289 | name='z', full_name='CDOTAMsg_WorldLine.z', index=2, 290 | number=3, type=5, cpp_type=1, label=1, 291 | has_default_value=False, default_value=0, 292 | message_type=None, enum_type=None, containing_type=None, 293 | is_extension=False, extension_scope=None, 294 | options=None), 295 | _descriptor.FieldDescriptor( 296 | name='initial', full_name='CDOTAMsg_WorldLine.initial', index=3, 297 | number=4, type=8, cpp_type=7, label=1, 298 | has_default_value=False, default_value=False, 299 | message_type=None, enum_type=None, containing_type=None, 300 | is_extension=False, extension_scope=None, 301 | options=None), 302 | _descriptor.FieldDescriptor( 303 | name='end', full_name='CDOTAMsg_WorldLine.end', index=4, 304 | number=5, type=8, cpp_type=7, label=1, 305 | has_default_value=False, default_value=False, 306 | message_type=None, enum_type=None, containing_type=None, 307 | is_extension=False, extension_scope=None, 308 | options=None), 309 | ], 310 | extensions=[ 311 | ], 312 | nested_types=[], 313 | enum_types=[ 314 | ], 315 | options=None, 316 | is_extendable=False, 317 | extension_ranges=[], 318 | serialized_start=304, 319 | serialized_end=387, 320 | ) 321 | 322 | 323 | _CDOTAMSG_SENDSTATPOPUP = _descriptor.Descriptor( 324 | name='CDOTAMsg_SendStatPopup', 325 | full_name='CDOTAMsg_SendStatPopup', 326 | filename=None, 327 | file=DESCRIPTOR, 328 | containing_type=None, 329 | fields=[ 330 | _descriptor.FieldDescriptor( 331 | name='style', full_name='CDOTAMsg_SendStatPopup.style', index=0, 332 | number=1, type=14, cpp_type=8, label=1, 333 | has_default_value=True, default_value=0, 334 | message_type=None, enum_type=None, containing_type=None, 335 | is_extension=False, extension_scope=None, 336 | options=None), 337 | _descriptor.FieldDescriptor( 338 | name='stat_strings', full_name='CDOTAMsg_SendStatPopup.stat_strings', index=1, 339 | number=2, type=9, cpp_type=9, label=3, 340 | has_default_value=False, default_value=[], 341 | message_type=None, enum_type=None, containing_type=None, 342 | is_extension=False, extension_scope=None, 343 | options=None), 344 | _descriptor.FieldDescriptor( 345 | name='stat_images', full_name='CDOTAMsg_SendStatPopup.stat_images', index=2, 346 | number=3, type=5, cpp_type=1, label=3, 347 | has_default_value=False, default_value=[], 348 | message_type=None, enum_type=None, containing_type=None, 349 | is_extension=False, extension_scope=None, 350 | options=None), 351 | ], 352 | extensions=[ 353 | ], 354 | nested_types=[], 355 | enum_types=[ 356 | ], 357 | options=None, 358 | is_extendable=False, 359 | extension_ranges=[], 360 | serialized_start=389, 361 | serialized_end=515, 362 | ) 363 | 364 | _CDOTAMSG_SENDSTATPOPUP.fields_by_name['style'].enum_type = _EDOTASTATPOPUPTYPES 365 | DESCRIPTOR.message_types_by_name['CDOTAMsg_LocationPing'] = _CDOTAMSG_LOCATIONPING 366 | DESCRIPTOR.message_types_by_name['CDOTAMsg_ItemAlert'] = _CDOTAMSG_ITEMALERT 367 | DESCRIPTOR.message_types_by_name['CDOTAMsg_MapLine'] = _CDOTAMSG_MAPLINE 368 | DESCRIPTOR.message_types_by_name['CDOTAMsg_WorldLine'] = _CDOTAMSG_WORLDLINE 369 | DESCRIPTOR.message_types_by_name['CDOTAMsg_SendStatPopup'] = _CDOTAMSG_SENDSTATPOPUP 370 | 371 | class CDOTAMsg_LocationPing(_message.Message): 372 | __metaclass__ = _reflection.GeneratedProtocolMessageType 373 | DESCRIPTOR = _CDOTAMSG_LOCATIONPING 374 | 375 | # @@protoc_insertion_point(class_scope:CDOTAMsg_LocationPing) 376 | 377 | class CDOTAMsg_ItemAlert(_message.Message): 378 | __metaclass__ = _reflection.GeneratedProtocolMessageType 379 | DESCRIPTOR = _CDOTAMSG_ITEMALERT 380 | 381 | # @@protoc_insertion_point(class_scope:CDOTAMsg_ItemAlert) 382 | 383 | class CDOTAMsg_MapLine(_message.Message): 384 | __metaclass__ = _reflection.GeneratedProtocolMessageType 385 | DESCRIPTOR = _CDOTAMSG_MAPLINE 386 | 387 | # @@protoc_insertion_point(class_scope:CDOTAMsg_MapLine) 388 | 389 | class CDOTAMsg_WorldLine(_message.Message): 390 | __metaclass__ = _reflection.GeneratedProtocolMessageType 391 | DESCRIPTOR = _CDOTAMSG_WORLDLINE 392 | 393 | # @@protoc_insertion_point(class_scope:CDOTAMsg_WorldLine) 394 | 395 | class CDOTAMsg_SendStatPopup(_message.Message): 396 | __metaclass__ = _reflection.GeneratedProtocolMessageType 397 | DESCRIPTOR = _CDOTAMSG_SENDSTATPOPUP 398 | 399 | # @@protoc_insertion_point(class_scope:CDOTAMsg_SendStatPopup) 400 | 401 | 402 | # @@protoc_insertion_point(module_scope) 403 | -------------------------------------------------------------------------------- /protobuf/dota_usermessages.proto: -------------------------------------------------------------------------------- 1 | import "google/protobuf/descriptor.proto"; 2 | import "networkbasetypes.proto"; 3 | import "ai_activity.proto"; 4 | import "dota_commonmessages.proto"; 5 | 6 | enum EDotaUserMessages { 7 | DOTA_UM_AddUnitToSelection = 64; 8 | DOTA_UM_AIDebugLine = 65; 9 | DOTA_UM_ChatEvent = 66; 10 | DOTA_UM_CombatHeroPositions = 67; 11 | DOTA_UM_CombatLogData = 68; 12 | DOTA_UM_CombatLogShowDeath = 70; 13 | DOTA_UM_CreateLinearProjectile = 71; 14 | DOTA_UM_DestroyLinearProjectile = 72; 15 | DOTA_UM_DodgeTrackingProjectiles = 73; 16 | DOTA_UM_GlobalLightColor = 74; 17 | DOTA_UM_GlobalLightDirection = 75; 18 | DOTA_UM_InvalidCommand = 76; 19 | DOTA_UM_LocationPing = 77; 20 | DOTA_UM_MapLine = 78; 21 | DOTA_UM_MiniKillCamInfo = 79; 22 | DOTA_UM_MinimapDebugPoint = 80; 23 | DOTA_UM_MinimapEvent = 81; 24 | DOTA_UM_NevermoreRequiem = 82; 25 | DOTA_UM_OverheadEvent = 83; 26 | DOTA_UM_SetNextAutobuyItem = 84; 27 | DOTA_UM_SharedCooldown = 85; 28 | DOTA_UM_SpectatorPlayerClick = 86; 29 | DOTA_UM_TutorialTipInfo = 87; 30 | DOTA_UM_UnitEvent = 88; 31 | DOTA_UM_ParticleManager = 89; 32 | DOTA_UM_BotChat = 90; 33 | DOTA_UM_HudError = 91; 34 | DOTA_UM_ItemPurchased = 92; 35 | DOTA_UM_Ping = 93; 36 | DOTA_UM_ItemFound = 94; 37 | DOTA_UM_CharacterSpeakConcept = 95; 38 | DOTA_UM_SwapVerify = 96; 39 | DOTA_UM_WorldLine = 97; 40 | DOTA_UM_TournamentDrop = 98; 41 | DOTA_UM_ItemAlert = 99; 42 | DOTA_UM_HalloweenDrops = 100; 43 | DOTA_UM_ChatWheel = 101; 44 | DOTA_UM_ReceivedXmasGift = 102; 45 | DOTA_UM_UpdateSharedContent = 103; 46 | DOTA_UM_TutorialRequestExp = 104; 47 | DOTA_UM_TutorialPingMinimap = 105; 48 | DOTA_UM_GamerulesStateChanged = 106; 49 | DOTA_UM_ShowSurvey = 107; 50 | DOTA_UM_TutorialFade = 108; 51 | DOTA_UM_AddQuestLogEntry = 109; 52 | DOTA_UM_SendStatPopup = 110; 53 | DOTA_UM_TutorialFinish = 111; 54 | DOTA_UM_SendRoshanPopup = 112; 55 | DOTA_UM_SendGenericToolTip = 113; 56 | DOTA_UM_SendFinalGold = 114; 57 | } 58 | 59 | enum DOTA_CHAT_MESSAGE { 60 | CHAT_MESSAGE_INVALID = -1; 61 | CHAT_MESSAGE_HERO_KILL = 0; 62 | CHAT_MESSAGE_HERO_DENY = 1; 63 | CHAT_MESSAGE_BARRACKS_KILL = 2; 64 | CHAT_MESSAGE_TOWER_KILL = 3; 65 | CHAT_MESSAGE_TOWER_DENY = 4; 66 | CHAT_MESSAGE_FIRSTBLOOD = 5; 67 | CHAT_MESSAGE_STREAK_KILL = 6; 68 | CHAT_MESSAGE_BUYBACK = 7; 69 | CHAT_MESSAGE_AEGIS = 8; 70 | CHAT_MESSAGE_ROSHAN_KILL = 9; 71 | CHAT_MESSAGE_COURIER_LOST = 10; 72 | CHAT_MESSAGE_COURIER_RESPAWNED = 11; 73 | CHAT_MESSAGE_GLYPH_USED = 12; 74 | CHAT_MESSAGE_ITEM_PURCHASE = 13; 75 | CHAT_MESSAGE_CONNECT = 14; 76 | CHAT_MESSAGE_DISCONNECT = 15; 77 | CHAT_MESSAGE_DISCONNECT_WAIT_FOR_RECONNECT = 16; 78 | CHAT_MESSAGE_DISCONNECT_TIME_REMAINING = 17; 79 | CHAT_MESSAGE_DISCONNECT_TIME_REMAINING_PLURAL = 18; 80 | CHAT_MESSAGE_RECONNECT = 19; 81 | CHAT_MESSAGE_ABANDON = 20; 82 | CHAT_MESSAGE_SAFE_TO_LEAVE = 21; 83 | CHAT_MESSAGE_RUNE_PICKUP = 22; 84 | CHAT_MESSAGE_RUNE_BOTTLE = 23; 85 | CHAT_MESSAGE_INTHEBAG = 24; 86 | CHAT_MESSAGE_SECRETSHOP = 25; 87 | CHAT_MESSAGE_ITEM_AUTOPURCHASED = 26; 88 | CHAT_MESSAGE_ITEMS_COMBINED = 27; 89 | CHAT_MESSAGE_SUPER_CREEPS = 28; 90 | CHAT_MESSAGE_CANT_USE_ACTION_ITEM = 29; 91 | CHAT_MESSAGE_CHARGES_EXHAUSTED = 30; 92 | CHAT_MESSAGE_CANTPAUSE = 31; 93 | CHAT_MESSAGE_NOPAUSESLEFT = 32; 94 | CHAT_MESSAGE_CANTPAUSEYET = 33; 95 | CHAT_MESSAGE_PAUSED = 34; 96 | CHAT_MESSAGE_UNPAUSE_COUNTDOWN = 35; 97 | CHAT_MESSAGE_UNPAUSED = 36; 98 | CHAT_MESSAGE_AUTO_UNPAUSED = 37; 99 | CHAT_MESSAGE_YOUPAUSED = 38; 100 | CHAT_MESSAGE_CANTUNPAUSETEAM = 39; 101 | CHAT_MESSAGE_SAFE_TO_LEAVE_ABANDONER = 40; 102 | CHAT_MESSAGE_VOICE_TEXT_BANNED = 41; 103 | CHAT_MESSAGE_SPECTATORS_WATCHING_THIS_GAME = 42; 104 | CHAT_MESSAGE_REPORT_REMINDER = 43; 105 | CHAT_MESSAGE_ECON_ITEM = 44; 106 | CHAT_MESSAGE_TAUNT = 45; 107 | CHAT_MESSAGE_RANDOM = 46; 108 | CHAT_MESSAGE_RD_TURN = 47; 109 | CHAT_MESSAGE_SAFE_TO_LEAVE_ABANDONER_EARLY = 48; 110 | CHAT_MESSAGE_DROP_RATE_BONUS = 49; 111 | CHAT_MESSAGE_NO_BATTLE_POINTS = 50; 112 | CHAT_MESSAGE_DENIED_AEGIS = 51; 113 | CHAT_MESSAGE_INFORMATIONAL = 52; 114 | CHAT_MESSAGE_AEGIS_STOLEN = 53; 115 | CHAT_MESSAGE_ROSHAN_CANDY = 54; 116 | CHAT_MESSAGE_ITEM_GIFTED = 55; 117 | CHAT_MESSAGE_HERO_KILL_WITH_GREEVIL = 56; 118 | } 119 | 120 | enum DOTA_NO_BATTLE_POINTS_REASONS { 121 | NO_BATTLE_POINTS_WRONG_LOBBY_TYPE = 1; 122 | NO_BATTLE_POINTS_PRACTICE_BOTS = 2; 123 | NO_BATTLE_POINTS_CHEATS_ENABLED = 3; 124 | NO_BATTLE_POINTS_LOW_PRIORITY = 4; 125 | } 126 | 127 | enum DOTA_CHAT_INFORMATIONAL { 128 | COOP_BATTLE_POINTS_RULES = 1; 129 | } 130 | 131 | enum DOTA_COMBATLOG_TYPES { 132 | DOTA_COMBATLOG_DAMAGE = 0; 133 | DOTA_COMBATLOG_HEAL = 1; 134 | DOTA_COMBATLOG_MODIFIER_ADD = 2; 135 | DOTA_COMBATLOG_MODIFIER_REMOVE = 3; 136 | DOTA_COMBATLOG_DEATH = 4; 137 | } 138 | 139 | enum EDotaEntityMessages { 140 | DOTA_UNIT_SPEECH = 0; 141 | DOTA_UNIT_SPEECH_MUTE = 1; 142 | DOTA_UNIT_ADD_GESTURE = 2; 143 | DOTA_UNIT_REMOVE_GESTURE = 3; 144 | DOTA_UNIT_REMOVE_ALL_GESTURES = 4; 145 | DOTA_UNIT_FADE_GESTURE = 6; 146 | DOTA_UNIT_SPEECH_CLIENTSIDE_RULES = 7; 147 | } 148 | 149 | enum DOTA_PARTICLE_MESSAGE { 150 | DOTA_PARTICLE_MANAGER_EVENT_CREATE = 0; 151 | DOTA_PARTICLE_MANAGER_EVENT_UPDATE = 1; 152 | DOTA_PARTICLE_MANAGER_EVENT_UPDATE_FORWARD = 2; 153 | DOTA_PARTICLE_MANAGER_EVENT_UPDATE_ORIENTATION = 3; 154 | DOTA_PARTICLE_MANAGER_EVENT_UPDATE_FALLBACK = 4; 155 | DOTA_PARTICLE_MANAGER_EVENT_UPDATE_ENT = 5; 156 | DOTA_PARTICLE_MANAGER_EVENT_UPDATE_OFFSET = 6; 157 | DOTA_PARTICLE_MANAGER_EVENT_DESTROY = 7; 158 | DOTA_PARTICLE_MANAGER_EVENT_DESTROY_INVOLVING = 8; 159 | DOTA_PARTICLE_MANAGER_EVENT_RELEASE = 9; 160 | DOTA_PARTICLE_MANAGER_EVENT_LATENCY = 10; 161 | DOTA_PARTICLE_MANAGER_EVENT_SHOULD_DRAW = 11; 162 | DOTA_PARTICLE_MANAGER_EVENT_FROZEN = 12; 163 | } 164 | 165 | enum DOTA_OVERHEAD_ALERT { 166 | OVERHEAD_ALERT_GOLD = 0; 167 | OVERHEAD_ALERT_DENY = 1; 168 | OVERHEAD_ALERT_CRITICAL = 2; 169 | OVERHEAD_ALERT_XP = 3; 170 | OVERHEAD_ALERT_BONUS_SPELL_DAMAGE = 4; 171 | OVERHEAD_ALERT_MISS = 5; 172 | OVERHEAD_ALERT_DAMAGE = 6; 173 | OVERHEAD_ALERT_EVADE = 7; 174 | OVERHEAD_ALERT_BLOCK = 8; 175 | OVERHEAD_ALERT_BONUS_POISON_DAMAGE = 9; 176 | OVERHEAD_ALERT_HEAL = 10; 177 | OVERHEAD_ALERT_MANA_ADD = 11; 178 | OVERHEAD_ALERT_MANA_LOSS = 12; 179 | OVERHEAD_ALERT_LAST_HIT_EARLY = 13; 180 | OVERHEAD_ALERT_LAST_HIT_CLOSE = 14; 181 | OVERHEAD_ALERT_LAST_HIT_MISS = 15; 182 | } 183 | 184 | message CDOTAUserMsg_AIDebugLine { 185 | optional string message = 1; 186 | } 187 | 188 | message CDOTAUserMsg_Ping { 189 | optional string message = 1; 190 | } 191 | 192 | message CDOTAUserMsg_SwapVerify { 193 | optional uint32 player_id = 1; 194 | } 195 | 196 | message CDOTAUserMsg_ChatEvent { 197 | required .DOTA_CHAT_MESSAGE type = 1 [default = CHAT_MESSAGE_INVALID]; 198 | optional uint32 value = 2; 199 | optional sint32 playerid_1 = 3 [default = -1]; 200 | optional sint32 playerid_2 = 4 [default = -1]; 201 | optional sint32 playerid_3 = 5 [default = -1]; 202 | optional sint32 playerid_4 = 6 [default = -1]; 203 | optional sint32 playerid_5 = 7 [default = -1]; 204 | optional sint32 playerid_6 = 8 [default = -1]; 205 | } 206 | 207 | message CDOTAUserMsg_CombatLogData { 208 | optional .DOTA_COMBATLOG_TYPES type = 1 [default = DOTA_COMBATLOG_DAMAGE]; 209 | optional uint32 target_name = 2; 210 | optional uint32 attacker_name = 3; 211 | optional bool attacker_illusion = 4; 212 | optional bool target_illusion = 5; 213 | optional uint32 inflictor_name = 6; 214 | optional int32 value = 7; 215 | optional int32 health = 8; 216 | optional float time = 9; 217 | } 218 | 219 | message CDOTAUserMsg_CombatLogShowDeath { 220 | } 221 | 222 | message CDOTAUserMsg_BotChat { 223 | optional uint32 player_id = 1; 224 | optional string format = 2; 225 | optional string message = 3; 226 | optional string target = 4; 227 | } 228 | 229 | message CDOTAUserMsg_CombatHeroPositions { 230 | optional uint32 index = 1; 231 | optional int32 time = 2; 232 | optional .CMsgVector2D world_pos = 3; 233 | optional int32 health = 4; 234 | } 235 | 236 | message CDOTAUserMsg_MiniKillCamInfo { 237 | message Attacker { 238 | message Ability { 239 | optional uint32 ability = 1; 240 | optional int32 damage = 2; 241 | } 242 | 243 | optional uint32 attacker = 1; 244 | optional int32 total_damage = 2; 245 | repeated .CDOTAUserMsg_MiniKillCamInfo.Attacker.Ability abilities = 3; 246 | } 247 | 248 | repeated .CDOTAUserMsg_MiniKillCamInfo.Attacker attackers = 1; 249 | } 250 | 251 | message CDOTAUserMsg_GlobalLightColor { 252 | optional uint32 color = 1; 253 | optional float duration = 2; 254 | } 255 | 256 | message CDOTAUserMsg_GlobalLightDirection { 257 | optional .CMsgVector direction = 1; 258 | optional float duration = 2; 259 | } 260 | 261 | message CDOTAUserMsg_LocationPing { 262 | optional uint32 player_id = 1; 263 | optional .CDOTAMsg_LocationPing location_ping = 2; 264 | } 265 | 266 | message CDOTAUserMsg_ItemAlert { 267 | optional uint32 player_id = 1; 268 | optional .CDOTAMsg_ItemAlert item_alert = 2; 269 | } 270 | 271 | message CDOTAUserMsg_MinimapEvent { 272 | optional int32 event_type = 1; 273 | optional int32 entity_handle = 2; 274 | optional int32 x = 3; 275 | optional int32 y = 4; 276 | optional int32 duration = 5; 277 | } 278 | 279 | message CDOTAUserMsg_MapLine { 280 | optional int32 player_id = 1; 281 | optional .CDOTAMsg_MapLine mapline = 2; 282 | } 283 | 284 | message CDOTAUserMsg_MinimapDebugPoint { 285 | optional .CMsgVector location = 1; 286 | optional uint32 color = 2; 287 | optional int32 size = 3; 288 | optional float duration = 4; 289 | } 290 | 291 | message CDOTAUserMsg_CreateLinearProjectile { 292 | optional .CMsgVector origin = 1; 293 | optional .CMsgVector2D velocity = 2; 294 | optional int32 latency = 3; 295 | optional int32 entindex = 4; 296 | optional int32 particle_index = 5; 297 | optional int32 handle = 6; 298 | } 299 | 300 | message CDOTAUserMsg_DestroyLinearProjectile { 301 | optional int32 handle = 1; 302 | } 303 | 304 | message CDOTAUserMsg_DodgeTrackingProjectiles { 305 | required int32 entindex = 1; 306 | } 307 | 308 | message CDOTAUserMsg_SpectatorPlayerClick { 309 | required int32 entindex = 1; 310 | optional int32 order_type = 2; 311 | optional int32 target_index = 3; 312 | } 313 | 314 | message CDOTAUserMsg_NevermoreRequiem { 315 | optional int32 entity_handle = 1; 316 | optional int32 lines = 2; 317 | optional .CMsgVector origin = 3; 318 | } 319 | 320 | message CDOTAUserMsg_InvalidCommand { 321 | optional string message = 1; 322 | } 323 | 324 | message CDOTAUserMsg_HudError { 325 | optional int32 order_id = 1; 326 | } 327 | 328 | message CDOTAUserMsg_SharedCooldown { 329 | optional int32 entindex = 1; 330 | optional string name = 2; 331 | optional float cooldown = 3; 332 | optional int32 name_index = 4; 333 | } 334 | 335 | message CDOTAUserMsg_SetNextAutobuyItem { 336 | optional string name = 1; 337 | } 338 | 339 | message CDOTAUserMsg_HalloweenDrops { 340 | repeated uint32 item_defs = 1; 341 | repeated uint32 player_ids = 2; 342 | optional uint32 prize_list = 3; 343 | } 344 | 345 | message CDOTAResponseQuerySerialized { 346 | message Fact { 347 | enum ValueType { 348 | NUMERIC = 1; 349 | STRING = 2; 350 | } 351 | 352 | required int32 key = 1; 353 | required .CDOTAResponseQuerySerialized.Fact.ValueType valtype = 2 [default = NUMERIC]; 354 | optional float val_numeric = 3; 355 | optional string val_string = 4; 356 | } 357 | 358 | repeated .CDOTAResponseQuerySerialized.Fact facts = 1; 359 | } 360 | 361 | message CDOTASpeechMatchOnClient { 362 | optional int32 concept = 1; 363 | optional int32 recipient_type = 2; 364 | optional .CDOTAResponseQuerySerialized responsequery = 3; 365 | optional sfixed32 randomseed = 4 [default = 0]; 366 | } 367 | 368 | message CDOTAUserMsg_UnitEvent { 369 | message Speech { 370 | optional int32 concept = 1; 371 | optional string response = 2; 372 | optional int32 recipient_type = 3; 373 | optional int32 level = 4; 374 | optional bool muteable = 5 [default = false]; 375 | } 376 | 377 | message SpeechMute { 378 | optional float delay = 1 [default = 0.5]; 379 | } 380 | 381 | message AddGesture { 382 | optional .Activity activity = 1 [default = ACT_INVALID]; 383 | optional int32 slot = 2; 384 | optional float fade_in = 3 [default = 0]; 385 | optional float fade_out = 4 [default = 0.1]; 386 | } 387 | 388 | message RemoveGesture { 389 | optional .Activity activity = 1 [default = ACT_INVALID]; 390 | } 391 | 392 | message BloodImpact { 393 | optional int32 scale = 1; 394 | optional int32 x_normal = 2; 395 | optional int32 y_normal = 3; 396 | } 397 | 398 | message FadeGesture { 399 | optional .Activity activity = 1 [default = ACT_INVALID]; 400 | } 401 | 402 | required .EDotaEntityMessages msg_type = 1 [default = DOTA_UNIT_SPEECH]; 403 | required int32 entity_index = 2; 404 | optional .CDOTAUserMsg_UnitEvent.Speech speech = 3; 405 | optional .CDOTAUserMsg_UnitEvent.SpeechMute speech_mute = 4; 406 | optional .CDOTAUserMsg_UnitEvent.AddGesture add_gesture = 5; 407 | optional .CDOTAUserMsg_UnitEvent.RemoveGesture remove_gesture = 6; 408 | optional .CDOTAUserMsg_UnitEvent.BloodImpact blood_impact = 7; 409 | optional .CDOTAUserMsg_UnitEvent.FadeGesture fade_gesture = 8; 410 | optional .CDOTASpeechMatchOnClient speech_match_on_client = 9; 411 | } 412 | 413 | message CDOTAUserMsg_ItemPurchased { 414 | optional int32 item_index = 1; 415 | } 416 | 417 | message CDOTAUserMsg_ItemFound { 418 | optional int32 player = 1; 419 | optional int32 quality = 2; 420 | optional int32 rarity = 3; 421 | optional int32 method = 4; 422 | optional int32 itemdef = 5; 423 | } 424 | 425 | message CDOTAUserMsg_ParticleManager { 426 | message ReleaseParticleIndex { 427 | } 428 | 429 | message CreateParticle { 430 | optional int32 particle_name_index = 1; 431 | optional int32 attach_type = 2; 432 | optional int32 entity_handle = 3; 433 | } 434 | 435 | message DestroyParticle { 436 | optional bool destroy_immediately = 1; 437 | } 438 | 439 | message DestroyParticleInvolving { 440 | optional bool destroy_immediately = 1; 441 | optional int32 entity_handle = 3; 442 | } 443 | 444 | message UpdateParticle { 445 | optional int32 control_point = 1; 446 | optional .CMsgVector position = 2; 447 | } 448 | 449 | message UpdateParticleFwd { 450 | optional int32 control_point = 1; 451 | optional .CMsgVector forward = 2; 452 | } 453 | 454 | message UpdateParticleOrient { 455 | optional int32 control_point = 1; 456 | optional .CMsgVector forward = 2; 457 | optional .CMsgVector right = 3; 458 | optional .CMsgVector up = 4; 459 | } 460 | 461 | message UpdateParticleFallback { 462 | optional int32 control_point = 1; 463 | optional .CMsgVector position = 2; 464 | } 465 | 466 | message UpdateParticleOffset { 467 | optional int32 control_point = 1; 468 | optional .CMsgVector origin_offset = 2; 469 | } 470 | 471 | message UpdateParticleEnt { 472 | optional int32 control_point = 1; 473 | optional int32 entity_handle = 2; 474 | optional int32 attach_type = 3; 475 | optional int32 attachment = 4; 476 | optional .CMsgVector fallback_position = 5; 477 | } 478 | 479 | message UpdateParticleSetFrozen { 480 | optional bool set_frozen = 1; 481 | } 482 | 483 | message UpdateParticleShouldDraw { 484 | optional bool should_draw = 1; 485 | } 486 | 487 | required .DOTA_PARTICLE_MESSAGE type = 1 [default = DOTA_PARTICLE_MANAGER_EVENT_CREATE]; 488 | required uint32 index = 2; 489 | optional .CDOTAUserMsg_ParticleManager.ReleaseParticleIndex release_particle_index = 3; 490 | optional .CDOTAUserMsg_ParticleManager.CreateParticle create_particle = 4; 491 | optional .CDOTAUserMsg_ParticleManager.DestroyParticle destroy_particle = 5; 492 | optional .CDOTAUserMsg_ParticleManager.DestroyParticleInvolving destroy_particle_involving = 6; 493 | optional .CDOTAUserMsg_ParticleManager.UpdateParticle update_particle = 7; 494 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleFwd update_particle_fwd = 8; 495 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleOrient update_particle_orient = 9; 496 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleFallback update_particle_fallback = 10; 497 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleOffset update_particle_offset = 11; 498 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleEnt update_particle_ent = 12; 499 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleShouldDraw update_particle_should_draw = 14; 500 | optional .CDOTAUserMsg_ParticleManager.UpdateParticleSetFrozen update_particle_set_frozen = 15; 501 | } 502 | 503 | message CDOTAUserMsg_OverheadEvent { 504 | required .DOTA_OVERHEAD_ALERT message_type = 1 [default = OVERHEAD_ALERT_GOLD]; 505 | optional int32 value = 2; 506 | optional int32 target_player_entindex = 3; 507 | optional int32 target_entindex = 4; 508 | optional int32 source_player_entindex = 5; 509 | } 510 | 511 | message CDOTAUserMsg_TutorialTipInfo { 512 | optional string name = 1; 513 | optional int32 progress = 2; 514 | } 515 | 516 | message CDOTAUserMsg_TutorialFinish { 517 | optional string heading = 1; 518 | optional string emblem = 2; 519 | optional string body = 3; 520 | optional bool success = 4; 521 | } 522 | 523 | message CDOTAUserMsg_SendGenericToolTip { 524 | optional string title = 1; 525 | optional string text = 2; 526 | optional int32 entindex = 3; 527 | optional bool close = 4; 528 | } 529 | 530 | message CDOTAUserMsg_WorldLine { 531 | optional int32 player_id = 1; 532 | optional .CDOTAMsg_WorldLine worldline = 2; 533 | } 534 | 535 | message CDOTAUserMsg_TournamentDrop { 536 | optional string winner_name = 1; 537 | optional int32 event_type = 2; 538 | } 539 | 540 | message CDOTAUserMsg_ChatWheel { 541 | optional .EDOTAChatWheelMessage chat_message = 1 [default = k_EDOTA_CW_Ok]; 542 | optional uint32 player_id = 2; 543 | optional uint32 account_id = 3; 544 | } 545 | 546 | message CDOTAUserMsg_ReceivedXmasGift { 547 | optional int32 player_id = 1; 548 | optional string item_name = 2; 549 | optional int32 inventory_slot = 3; 550 | } 551 | 552 | message CDOTAUserMsg_ShowSurvey { 553 | optional int32 survey_id = 1; 554 | } 555 | 556 | message CDOTAUserMsg_UpdateSharedContent { 557 | optional int32 slot_type = 1; 558 | } 559 | 560 | message CDOTAUserMsg_TutorialRequestExp { 561 | } 562 | 563 | message CDOTAUserMsg_TutorialFade { 564 | optional int32 tgt_alpha = 1; 565 | } 566 | 567 | message CDOTAUserMsg_TutorialPingMinimap { 568 | optional uint32 player_id = 1; 569 | optional float pos_x = 2; 570 | optional float pos_y = 3; 571 | optional float pos_z = 4; 572 | optional int32 entity_index = 5; 573 | } 574 | 575 | message CDOTA_UM_GamerulesStateChanged { 576 | optional uint32 state = 1; 577 | } 578 | 579 | message CDOTAUserMsg_AddQuestLogEntry { 580 | optional string npc_name = 1; 581 | optional string npc_dialog = 2; 582 | optional bool quest = 3; 583 | optional int32 quest_type = 4; 584 | } 585 | 586 | message CDOTAUserMsg_SendStatPopup { 587 | optional int32 player_id = 1; 588 | optional .CDOTAMsg_SendStatPopup statpopup = 2; 589 | } 590 | 591 | message CDOTAUserMsg_SendRoshanPopup { 592 | optional bool reclaimed = 1; 593 | optional int32 gametime = 2; 594 | } 595 | 596 | message CDOTAUserMsg_SendFinalGold { 597 | repeated uint32 reliable_gold = 1; 598 | repeated uint32 unreliable_gold = 2; 599 | } 600 | 601 | -------------------------------------------------------------------------------- /protobuf/ai_activity.proto: -------------------------------------------------------------------------------- 1 | enum Activity { 2 | ACT_INVALID = -1; 3 | ACT_RESET = 0; 4 | ACT_IDLE = 1; 5 | ACT_TRANSITION = 2; 6 | ACT_COVER = 3; 7 | ACT_COVER_MED = 4; 8 | ACT_COVER_LOW = 5; 9 | ACT_WALK = 6; 10 | ACT_WALK_AIM = 7; 11 | ACT_WALK_CROUCH = 8; 12 | ACT_WALK_CROUCH_AIM = 9; 13 | ACT_RUN = 10; 14 | ACT_RUN_AIM = 11; 15 | ACT_RUN_CROUCH = 12; 16 | ACT_RUN_CROUCH_AIM = 13; 17 | ACT_RUN_PROTECTED = 14; 18 | ACT_SCRIPT_CUSTOM_MOVE = 15; 19 | ACT_RANGE_ATTACK1 = 16; 20 | ACT_RANGE_ATTACK2 = 17; 21 | ACT_RANGE_ATTACK1_LOW = 18; 22 | ACT_RANGE_ATTACK2_LOW = 19; 23 | ACT_DIESIMPLE = 20; 24 | ACT_DIEBACKWARD = 21; 25 | ACT_DIEFORWARD = 22; 26 | ACT_DIEVIOLENT = 23; 27 | ACT_DIERAGDOLL = 24; 28 | ACT_FLY = 25; 29 | ACT_HOVER = 26; 30 | ACT_GLIDE = 27; 31 | ACT_SWIM = 28; 32 | ACT_JUMP = 29; 33 | ACT_HOP = 30; 34 | ACT_LEAP = 31; 35 | ACT_LAND = 32; 36 | ACT_CLIMB_UP = 33; 37 | ACT_CLIMB_DOWN = 34; 38 | ACT_CLIMB_DISMOUNT = 35; 39 | ACT_SHIPLADDER_UP = 36; 40 | ACT_SHIPLADDER_DOWN = 37; 41 | ACT_STRAFE_LEFT = 38; 42 | ACT_STRAFE_RIGHT = 39; 43 | ACT_ROLL_LEFT = 40; 44 | ACT_ROLL_RIGHT = 41; 45 | ACT_TURN_LEFT = 42; 46 | ACT_TURN_RIGHT = 43; 47 | ACT_CROUCH = 44; 48 | ACT_CROUCHIDLE = 45; 49 | ACT_STAND = 46; 50 | ACT_USE = 47; 51 | ACT_ALIEN_BURROW_IDLE = 48; 52 | ACT_ALIEN_BURROW_OUT = 49; 53 | ACT_SIGNAL1 = 50; 54 | ACT_SIGNAL2 = 51; 55 | ACT_SIGNAL3 = 52; 56 | ACT_SIGNAL_ADVANCE = 53; 57 | ACT_SIGNAL_FORWARD = 54; 58 | ACT_SIGNAL_GROUP = 55; 59 | ACT_SIGNAL_HALT = 56; 60 | ACT_SIGNAL_LEFT = 57; 61 | ACT_SIGNAL_RIGHT = 58; 62 | ACT_SIGNAL_TAKECOVER = 59; 63 | ACT_LOOKBACK_RIGHT = 60; 64 | ACT_LOOKBACK_LEFT = 61; 65 | ACT_COWER = 62; 66 | ACT_SMALL_FLINCH = 63; 67 | ACT_BIG_FLINCH = 64; 68 | ACT_MELEE_ATTACK1 = 65; 69 | ACT_MELEE_ATTACK2 = 66; 70 | ACT_RELOAD = 67; 71 | ACT_RELOAD_START = 68; 72 | ACT_RELOAD_FINISH = 69; 73 | ACT_RELOAD_LOW = 70; 74 | ACT_ARM = 71; 75 | ACT_DISARM = 72; 76 | ACT_DROP_WEAPON = 73; 77 | ACT_DROP_WEAPON_SHOTGUN = 74; 78 | ACT_PICKUP_GROUND = 75; 79 | ACT_PICKUP_RACK = 76; 80 | ACT_IDLE_ANGRY = 77; 81 | ACT_IDLE_RELAXED = 78; 82 | ACT_IDLE_STIMULATED = 79; 83 | ACT_IDLE_AGITATED = 80; 84 | ACT_IDLE_STEALTH = 81; 85 | ACT_IDLE_HURT = 82; 86 | ACT_WALK_RELAXED = 83; 87 | ACT_WALK_STIMULATED = 84; 88 | ACT_WALK_AGITATED = 85; 89 | ACT_WALK_STEALTH = 86; 90 | ACT_RUN_RELAXED = 87; 91 | ACT_RUN_STIMULATED = 88; 92 | ACT_RUN_AGITATED = 89; 93 | ACT_RUN_STEALTH = 90; 94 | ACT_IDLE_AIM_RELAXED = 91; 95 | ACT_IDLE_AIM_STIMULATED = 92; 96 | ACT_IDLE_AIM_AGITATED = 93; 97 | ACT_IDLE_AIM_STEALTH = 94; 98 | ACT_WALK_AIM_RELAXED = 95; 99 | ACT_WALK_AIM_STIMULATED = 96; 100 | ACT_WALK_AIM_AGITATED = 97; 101 | ACT_WALK_AIM_STEALTH = 98; 102 | ACT_RUN_AIM_RELAXED = 99; 103 | ACT_RUN_AIM_STIMULATED = 100; 104 | ACT_RUN_AIM_AGITATED = 101; 105 | ACT_RUN_AIM_STEALTH = 102; 106 | ACT_CROUCHIDLE_STIMULATED = 103; 107 | ACT_CROUCHIDLE_AIM_STIMULATED = 104; 108 | ACT_CROUCHIDLE_AGITATED = 105; 109 | ACT_WALK_HURT = 106; 110 | ACT_RUN_HURT = 107; 111 | ACT_SPECIAL_ATTACK1 = 108; 112 | ACT_SPECIAL_ATTACK2 = 109; 113 | ACT_COMBAT_IDLE = 110; 114 | ACT_WALK_SCARED = 111; 115 | ACT_RUN_SCARED = 112; 116 | ACT_VICTORY_DANCE = 113; 117 | ACT_DIE_HEADSHOT = 114; 118 | ACT_DIE_CHESTSHOT = 115; 119 | ACT_DIE_GUTSHOT = 116; 120 | ACT_DIE_BACKSHOT = 117; 121 | ACT_FLINCH_HEAD = 118; 122 | ACT_FLINCH_CHEST = 119; 123 | ACT_FLINCH_STOMACH = 120; 124 | ACT_FLINCH_LEFTARM = 121; 125 | ACT_FLINCH_RIGHTARM = 122; 126 | ACT_FLINCH_LEFTLEG = 123; 127 | ACT_FLINCH_RIGHTLEG = 124; 128 | ACT_FLINCH_PHYSICS = 125; 129 | ACT_FLINCH_HEAD_BACK = 126; 130 | ACT_FLINCH_CHEST_BACK = 127; 131 | ACT_FLINCH_STOMACH_BACK = 128; 132 | ACT_FLINCH_CROUCH_FRONT = 129; 133 | ACT_FLINCH_CROUCH_BACK = 130; 134 | ACT_FLINCH_CROUCH_LEFT = 131; 135 | ACT_FLINCH_CROUCH_RIGHT = 132; 136 | ACT_IDLE_ON_FIRE = 133; 137 | ACT_WALK_ON_FIRE = 134; 138 | ACT_RUN_ON_FIRE = 135; 139 | ACT_RAPPEL_LOOP = 136; 140 | ACT_180_LEFT = 137; 141 | ACT_180_RIGHT = 138; 142 | ACT_90_LEFT = 139; 143 | ACT_90_RIGHT = 140; 144 | ACT_STEP_LEFT = 141; 145 | ACT_STEP_RIGHT = 142; 146 | ACT_STEP_BACK = 143; 147 | ACT_STEP_FORE = 144; 148 | ACT_GESTURE_RANGE_ATTACK1 = 145; 149 | ACT_GESTURE_RANGE_ATTACK2 = 146; 150 | ACT_GESTURE_MELEE_ATTACK1 = 147; 151 | ACT_GESTURE_MELEE_ATTACK2 = 148; 152 | ACT_GESTURE_RANGE_ATTACK1_LOW = 149; 153 | ACT_GESTURE_RANGE_ATTACK2_LOW = 150; 154 | ACT_MELEE_ATTACK_SWING_GESTURE = 151; 155 | ACT_GESTURE_SMALL_FLINCH = 152; 156 | ACT_GESTURE_BIG_FLINCH = 153; 157 | ACT_GESTURE_FLINCH_BLAST = 154; 158 | ACT_GESTURE_FLINCH_BLAST_SHOTGUN = 155; 159 | ACT_GESTURE_FLINCH_BLAST_DAMAGED = 156; 160 | ACT_GESTURE_FLINCH_BLAST_DAMAGED_SHOTGUN = 157; 161 | ACT_GESTURE_FLINCH_HEAD = 158; 162 | ACT_GESTURE_FLINCH_CHEST = 159; 163 | ACT_GESTURE_FLINCH_STOMACH = 160; 164 | ACT_GESTURE_FLINCH_LEFTARM = 161; 165 | ACT_GESTURE_FLINCH_RIGHTARM = 162; 166 | ACT_GESTURE_FLINCH_LEFTLEG = 163; 167 | ACT_GESTURE_FLINCH_RIGHTLEG = 164; 168 | ACT_GESTURE_TURN_LEFT = 165; 169 | ACT_GESTURE_TURN_RIGHT = 166; 170 | ACT_GESTURE_TURN_LEFT45 = 167; 171 | ACT_GESTURE_TURN_RIGHT45 = 168; 172 | ACT_GESTURE_TURN_LEFT90 = 169; 173 | ACT_GESTURE_TURN_RIGHT90 = 170; 174 | ACT_GESTURE_TURN_LEFT45_FLAT = 171; 175 | ACT_GESTURE_TURN_RIGHT45_FLAT = 172; 176 | ACT_GESTURE_TURN_LEFT90_FLAT = 173; 177 | ACT_GESTURE_TURN_RIGHT90_FLAT = 174; 178 | ACT_BARNACLE_HIT = 175; 179 | ACT_BARNACLE_PULL = 176; 180 | ACT_BARNACLE_CHOMP = 177; 181 | ACT_BARNACLE_CHEW = 178; 182 | ACT_DO_NOT_DISTURB = 179; 183 | ACT_SPECIFIC_SEQUENCE = 180; 184 | ACT_VM_DRAW = 181; 185 | ACT_VM_HOLSTER = 182; 186 | ACT_VM_IDLE = 183; 187 | ACT_VM_FIDGET = 184; 188 | ACT_VM_PULLBACK = 185; 189 | ACT_VM_PULLBACK_HIGH = 186; 190 | ACT_VM_PULLBACK_LOW = 187; 191 | ACT_VM_THROW = 188; 192 | ACT_VM_PULLPIN = 189; 193 | ACT_VM_PRIMARYATTACK = 190; 194 | ACT_VM_SECONDARYATTACK = 191; 195 | ACT_VM_RELOAD = 192; 196 | ACT_VM_DRYFIRE = 193; 197 | ACT_VM_HITLEFT = 194; 198 | ACT_VM_HITLEFT2 = 195; 199 | ACT_VM_HITRIGHT = 196; 200 | ACT_VM_HITRIGHT2 = 197; 201 | ACT_VM_HITCENTER = 198; 202 | ACT_VM_HITCENTER2 = 199; 203 | ACT_VM_MISSLEFT = 200; 204 | ACT_VM_MISSLEFT2 = 201; 205 | ACT_VM_MISSRIGHT = 202; 206 | ACT_VM_MISSRIGHT2 = 203; 207 | ACT_VM_MISSCENTER = 204; 208 | ACT_VM_MISSCENTER2 = 205; 209 | ACT_VM_HAULBACK = 206; 210 | ACT_VM_SWINGHARD = 207; 211 | ACT_VM_SWINGMISS = 208; 212 | ACT_VM_SWINGHIT = 209; 213 | ACT_VM_IDLE_TO_LOWERED = 210; 214 | ACT_VM_IDLE_LOWERED = 211; 215 | ACT_VM_LOWERED_TO_IDLE = 212; 216 | ACT_VM_RECOIL1 = 213; 217 | ACT_VM_RECOIL2 = 214; 218 | ACT_VM_RECOIL3 = 215; 219 | ACT_VM_PICKUP = 216; 220 | ACT_VM_RELEASE = 217; 221 | ACT_VM_ATTACH_SILENCER = 218; 222 | ACT_VM_DETACH_SILENCER = 219; 223 | ACT_SLAM_STICKWALL_IDLE = 220; 224 | ACT_SLAM_STICKWALL_ND_IDLE = 221; 225 | ACT_SLAM_STICKWALL_ATTACH = 222; 226 | ACT_SLAM_STICKWALL_ATTACH2 = 223; 227 | ACT_SLAM_STICKWALL_ND_ATTACH = 224; 228 | ACT_SLAM_STICKWALL_ND_ATTACH2 = 225; 229 | ACT_SLAM_STICKWALL_DETONATE = 226; 230 | ACT_SLAM_STICKWALL_DETONATOR_HOLSTER = 227; 231 | ACT_SLAM_STICKWALL_DRAW = 228; 232 | ACT_SLAM_STICKWALL_ND_DRAW = 229; 233 | ACT_SLAM_STICKWALL_TO_THROW = 230; 234 | ACT_SLAM_STICKWALL_TO_THROW_ND = 231; 235 | ACT_SLAM_STICKWALL_TO_TRIPMINE_ND = 232; 236 | ACT_SLAM_THROW_IDLE = 233; 237 | ACT_SLAM_THROW_ND_IDLE = 234; 238 | ACT_SLAM_THROW_THROW = 235; 239 | ACT_SLAM_THROW_THROW2 = 236; 240 | ACT_SLAM_THROW_THROW_ND = 237; 241 | ACT_SLAM_THROW_THROW_ND2 = 238; 242 | ACT_SLAM_THROW_DRAW = 239; 243 | ACT_SLAM_THROW_ND_DRAW = 240; 244 | ACT_SLAM_THROW_TO_STICKWALL = 241; 245 | ACT_SLAM_THROW_TO_STICKWALL_ND = 242; 246 | ACT_SLAM_THROW_DETONATE = 243; 247 | ACT_SLAM_THROW_DETONATOR_HOLSTER = 244; 248 | ACT_SLAM_THROW_TO_TRIPMINE_ND = 245; 249 | ACT_SLAM_TRIPMINE_IDLE = 246; 250 | ACT_SLAM_TRIPMINE_DRAW = 247; 251 | ACT_SLAM_TRIPMINE_ATTACH = 248; 252 | ACT_SLAM_TRIPMINE_ATTACH2 = 249; 253 | ACT_SLAM_TRIPMINE_TO_STICKWALL_ND = 250; 254 | ACT_SLAM_TRIPMINE_TO_THROW_ND = 251; 255 | ACT_SLAM_DETONATOR_IDLE = 252; 256 | ACT_SLAM_DETONATOR_DRAW = 253; 257 | ACT_SLAM_DETONATOR_DETONATE = 254; 258 | ACT_SLAM_DETONATOR_HOLSTER = 255; 259 | ACT_SLAM_DETONATOR_STICKWALL_DRAW = 256; 260 | ACT_SLAM_DETONATOR_THROW_DRAW = 257; 261 | ACT_SHOTGUN_RELOAD_START = 258; 262 | ACT_SHOTGUN_RELOAD_FINISH = 259; 263 | ACT_SHOTGUN_PUMP = 260; 264 | ACT_SMG2_IDLE2 = 261; 265 | ACT_SMG2_FIRE2 = 262; 266 | ACT_SMG2_DRAW2 = 263; 267 | ACT_SMG2_RELOAD2 = 264; 268 | ACT_SMG2_DRYFIRE2 = 265; 269 | ACT_SMG2_TOAUTO = 266; 270 | ACT_SMG2_TOBURST = 267; 271 | ACT_PHYSCANNON_UPGRADE = 268; 272 | ACT_RANGE_ATTACK_AR1 = 269; 273 | ACT_RANGE_ATTACK_AR2 = 270; 274 | ACT_RANGE_ATTACK_AR2_LOW = 271; 275 | ACT_RANGE_ATTACK_AR2_GRENADE = 272; 276 | ACT_RANGE_ATTACK_HMG1 = 273; 277 | ACT_RANGE_ATTACK_ML = 274; 278 | ACT_RANGE_ATTACK_SMG1 = 275; 279 | ACT_RANGE_ATTACK_SMG1_LOW = 276; 280 | ACT_RANGE_ATTACK_SMG2 = 277; 281 | ACT_RANGE_ATTACK_SHOTGUN = 278; 282 | ACT_RANGE_ATTACK_SHOTGUN_LOW = 279; 283 | ACT_RANGE_ATTACK_PISTOL = 280; 284 | ACT_RANGE_ATTACK_PISTOL_LOW = 281; 285 | ACT_RANGE_ATTACK_SLAM = 282; 286 | ACT_RANGE_ATTACK_TRIPWIRE = 283; 287 | ACT_RANGE_ATTACK_THROW = 284; 288 | ACT_RANGE_ATTACK_SNIPER_RIFLE = 285; 289 | ACT_RANGE_ATTACK_RPG = 286; 290 | ACT_MELEE_ATTACK_SWING = 287; 291 | ACT_RANGE_AIM_LOW = 288; 292 | ACT_RANGE_AIM_SMG1_LOW = 289; 293 | ACT_RANGE_AIM_PISTOL_LOW = 290; 294 | ACT_RANGE_AIM_AR2_LOW = 291; 295 | ACT_COVER_PISTOL_LOW = 292; 296 | ACT_COVER_SMG1_LOW = 293; 297 | ACT_GESTURE_RANGE_ATTACK_AR1 = 294; 298 | ACT_GESTURE_RANGE_ATTACK_AR2 = 295; 299 | ACT_GESTURE_RANGE_ATTACK_AR2_GRENADE = 296; 300 | ACT_GESTURE_RANGE_ATTACK_HMG1 = 297; 301 | ACT_GESTURE_RANGE_ATTACK_ML = 298; 302 | ACT_GESTURE_RANGE_ATTACK_SMG1 = 299; 303 | ACT_GESTURE_RANGE_ATTACK_SMG1_LOW = 300; 304 | ACT_GESTURE_RANGE_ATTACK_SMG2 = 301; 305 | ACT_GESTURE_RANGE_ATTACK_SHOTGUN = 302; 306 | ACT_GESTURE_RANGE_ATTACK_PISTOL = 303; 307 | ACT_GESTURE_RANGE_ATTACK_PISTOL_LOW = 304; 308 | ACT_GESTURE_RANGE_ATTACK_SLAM = 305; 309 | ACT_GESTURE_RANGE_ATTACK_TRIPWIRE = 306; 310 | ACT_GESTURE_RANGE_ATTACK_THROW = 307; 311 | ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE = 308; 312 | ACT_GESTURE_MELEE_ATTACK_SWING = 309; 313 | ACT_IDLE_RIFLE = 310; 314 | ACT_IDLE_SMG1 = 311; 315 | ACT_IDLE_ANGRY_SMG1 = 312; 316 | ACT_IDLE_PISTOL = 313; 317 | ACT_IDLE_ANGRY_PISTOL = 314; 318 | ACT_IDLE_ANGRY_SHOTGUN = 315; 319 | ACT_IDLE_STEALTH_PISTOL = 316; 320 | ACT_IDLE_PACKAGE = 317; 321 | ACT_WALK_PACKAGE = 318; 322 | ACT_IDLE_SUITCASE = 319; 323 | ACT_WALK_SUITCASE = 320; 324 | ACT_IDLE_SMG1_RELAXED = 321; 325 | ACT_IDLE_SMG1_STIMULATED = 322; 326 | ACT_WALK_RIFLE_RELAXED = 323; 327 | ACT_RUN_RIFLE_RELAXED = 324; 328 | ACT_WALK_RIFLE_STIMULATED = 325; 329 | ACT_RUN_RIFLE_STIMULATED = 326; 330 | ACT_IDLE_AIM_RIFLE_STIMULATED = 327; 331 | ACT_WALK_AIM_RIFLE_STIMULATED = 328; 332 | ACT_RUN_AIM_RIFLE_STIMULATED = 329; 333 | ACT_IDLE_SHOTGUN_RELAXED = 330; 334 | ACT_IDLE_SHOTGUN_STIMULATED = 331; 335 | ACT_IDLE_SHOTGUN_AGITATED = 332; 336 | ACT_WALK_ANGRY = 333; 337 | ACT_POLICE_HARASS1 = 334; 338 | ACT_POLICE_HARASS2 = 335; 339 | ACT_IDLE_MANNEDGUN = 336; 340 | ACT_IDLE_MELEE = 337; 341 | ACT_IDLE_ANGRY_MELEE = 338; 342 | ACT_IDLE_RPG_RELAXED = 339; 343 | ACT_IDLE_RPG = 340; 344 | ACT_IDLE_ANGRY_RPG = 341; 345 | ACT_COVER_LOW_RPG = 342; 346 | ACT_WALK_RPG = 343; 347 | ACT_RUN_RPG = 344; 348 | ACT_WALK_CROUCH_RPG = 345; 349 | ACT_RUN_CROUCH_RPG = 346; 350 | ACT_WALK_RPG_RELAXED = 347; 351 | ACT_RUN_RPG_RELAXED = 348; 352 | ACT_WALK_RIFLE = 349; 353 | ACT_WALK_AIM_RIFLE = 350; 354 | ACT_WALK_CROUCH_RIFLE = 351; 355 | ACT_WALK_CROUCH_AIM_RIFLE = 352; 356 | ACT_RUN_RIFLE = 353; 357 | ACT_RUN_AIM_RIFLE = 354; 358 | ACT_RUN_CROUCH_RIFLE = 355; 359 | ACT_RUN_CROUCH_AIM_RIFLE = 356; 360 | ACT_RUN_STEALTH_PISTOL = 357; 361 | ACT_WALK_AIM_SHOTGUN = 358; 362 | ACT_RUN_AIM_SHOTGUN = 359; 363 | ACT_WALK_PISTOL = 360; 364 | ACT_RUN_PISTOL = 361; 365 | ACT_WALK_AIM_PISTOL = 362; 366 | ACT_RUN_AIM_PISTOL = 363; 367 | ACT_WALK_STEALTH_PISTOL = 364; 368 | ACT_WALK_AIM_STEALTH_PISTOL = 365; 369 | ACT_RUN_AIM_STEALTH_PISTOL = 366; 370 | ACT_RELOAD_PISTOL = 367; 371 | ACT_RELOAD_PISTOL_LOW = 368; 372 | ACT_RELOAD_SMG1 = 369; 373 | ACT_RELOAD_SMG1_LOW = 370; 374 | ACT_RELOAD_SHOTGUN = 371; 375 | ACT_RELOAD_SHOTGUN_LOW = 372; 376 | ACT_GESTURE_RELOAD = 373; 377 | ACT_GESTURE_RELOAD_PISTOL = 374; 378 | ACT_GESTURE_RELOAD_SMG1 = 375; 379 | ACT_GESTURE_RELOAD_SHOTGUN = 376; 380 | ACT_BUSY_LEAN_LEFT = 377; 381 | ACT_BUSY_LEAN_LEFT_ENTRY = 378; 382 | ACT_BUSY_LEAN_LEFT_EXIT = 379; 383 | ACT_BUSY_LEAN_BACK = 380; 384 | ACT_BUSY_LEAN_BACK_ENTRY = 381; 385 | ACT_BUSY_LEAN_BACK_EXIT = 382; 386 | ACT_BUSY_SIT_GROUND = 383; 387 | ACT_BUSY_SIT_GROUND_ENTRY = 384; 388 | ACT_BUSY_SIT_GROUND_EXIT = 385; 389 | ACT_BUSY_SIT_CHAIR = 386; 390 | ACT_BUSY_SIT_CHAIR_ENTRY = 387; 391 | ACT_BUSY_SIT_CHAIR_EXIT = 388; 392 | ACT_BUSY_STAND = 389; 393 | ACT_BUSY_QUEUE = 390; 394 | ACT_DUCK_DODGE = 391; 395 | ACT_DIE_BARNACLE_SWALLOW = 392; 396 | ACT_GESTURE_BARNACLE_STRANGLE = 393; 397 | ACT_PHYSCANNON_DETACH = 394; 398 | ACT_PHYSCANNON_ANIMATE = 395; 399 | ACT_PHYSCANNON_ANIMATE_PRE = 396; 400 | ACT_PHYSCANNON_ANIMATE_POST = 397; 401 | ACT_DIE_FRONTSIDE = 398; 402 | ACT_DIE_RIGHTSIDE = 399; 403 | ACT_DIE_BACKSIDE = 400; 404 | ACT_DIE_LEFTSIDE = 401; 405 | ACT_OPEN_DOOR = 402; 406 | ACT_DI_ALYX_ZOMBIE_MELEE = 403; 407 | ACT_DI_ALYX_ZOMBIE_TORSO_MELEE = 404; 408 | ACT_DI_ALYX_HEADCRAB_MELEE = 405; 409 | ACT_DI_ALYX_ANTLION = 406; 410 | ACT_DI_ALYX_ZOMBIE_SHOTGUN64 = 407; 411 | ACT_DI_ALYX_ZOMBIE_SHOTGUN26 = 408; 412 | ACT_READINESS_RELAXED_TO_STIMULATED = 409; 413 | ACT_READINESS_RELAXED_TO_STIMULATED_WALK = 410; 414 | ACT_READINESS_AGITATED_TO_STIMULATED = 411; 415 | ACT_READINESS_STIMULATED_TO_RELAXED = 412; 416 | ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED = 413; 417 | ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK = 414; 418 | ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED = 415; 419 | ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED = 416; 420 | ACT_IDLE_CARRY = 417; 421 | ACT_WALK_CARRY = 418; 422 | ACT_DOTA_IDLE = 419; 423 | ACT_DOTA_IDLE_RARE = 421; 424 | ACT_DOTA_RUN = 422; 425 | ACT_DOTA_ATTACK = 424; 426 | ACT_DOTA_ATTACK2 = 425; 427 | ACT_DOTA_ATTACK_EVENT = 426; 428 | ACT_DOTA_DIE = 427; 429 | ACT_DOTA_FLINCH = 428; 430 | ACT_DOTA_FLAIL = 429; 431 | ACT_DOTA_DISABLED = 430; 432 | ACT_DOTA_CAST_ABILITY_1 = 431; 433 | ACT_DOTA_CAST_ABILITY_2 = 432; 434 | ACT_DOTA_CAST_ABILITY_3 = 433; 435 | ACT_DOTA_CAST_ABILITY_4 = 434; 436 | ACT_DOTA_CAST_ABILITY_5 = 435; 437 | ACT_DOTA_CAST_ABILITY_6 = 436; 438 | ACT_DOTA_OVERRIDE_ABILITY_1 = 437; 439 | ACT_DOTA_OVERRIDE_ABILITY_2 = 438; 440 | ACT_DOTA_OVERRIDE_ABILITY_3 = 439; 441 | ACT_DOTA_OVERRIDE_ABILITY_4 = 440; 442 | ACT_DOTA_CHANNEL_ABILITY_1 = 441; 443 | ACT_DOTA_CHANNEL_ABILITY_2 = 442; 444 | ACT_DOTA_CHANNEL_ABILITY_3 = 443; 445 | ACT_DOTA_CHANNEL_ABILITY_4 = 444; 446 | ACT_DOTA_CHANNEL_ABILITY_5 = 445; 447 | ACT_DOTA_CHANNEL_ABILITY_6 = 446; 448 | ACT_DOTA_CHANNEL_END_ABILITY_1 = 447; 449 | ACT_DOTA_CHANNEL_END_ABILITY_2 = 448; 450 | ACT_DOTA_CHANNEL_END_ABILITY_3 = 449; 451 | ACT_DOTA_CHANNEL_END_ABILITY_4 = 450; 452 | ACT_DOTA_CHANNEL_END_ABILITY_5 = 451; 453 | ACT_DOTA_CHANNEL_END_ABILITY_6 = 452; 454 | ACT_DOTA_CONSTANT_LAYER = 453; 455 | ACT_DOTA_CAPTURE = 454; 456 | ACT_DOTA_SPAWN = 455; 457 | ACT_DOTA_KILLTAUNT = 456; 458 | ACT_DOTA_TAUNT = 457; 459 | ACT_DOTA_THIRST = 458; 460 | ACT_DOTA_CAST_DRAGONBREATH = 459; 461 | ACT_DOTA_ECHO_SLAM = 460; 462 | ACT_DOTA_CAST_ABILITY_1_END = 461; 463 | ACT_DOTA_CAST_ABILITY_2_END = 462; 464 | ACT_DOTA_CAST_ABILITY_3_END = 463; 465 | ACT_DOTA_CAST_ABILITY_4_END = 464; 466 | ACT_MIRANA_LEAP_END = 465; 467 | ACT_WAVEFORM_START = 466; 468 | ACT_WAVEFORM_END = 467; 469 | ACT_DOTA_CAST_ABILITY_ROT = 468; 470 | ACT_DOTA_DIE_SPECIAL = 469; 471 | ACT_DOTA_RATTLETRAP_BATTERYASSAULT = 470; 472 | ACT_DOTA_RATTLETRAP_POWERCOGS = 471; 473 | ACT_DOTA_RATTLETRAP_HOOKSHOT_START = 472; 474 | ACT_DOTA_RATTLETRAP_HOOKSHOT_LOOP = 473; 475 | ACT_DOTA_RATTLETRAP_HOOKSHOT_END = 474; 476 | ACT_STORM_SPIRIT_OVERLOAD_RUN_OVERRIDE = 475; 477 | ACT_DOTA_TINKER_REARM1 = 476; 478 | ACT_DOTA_TINKER_REARM2 = 477; 479 | ACT_DOTA_TINKER_REARM3 = 478; 480 | ACT_TINY_AVALANCHE = 479; 481 | ACT_TINY_TOSS = 480; 482 | ACT_TINY_GROWL = 481; 483 | ACT_DOTA_WEAVERBUG_ATTACH = 482; 484 | ACT_DOTA_CAST_WILD_AXES_END = 483; 485 | ACT_DOTA_CAST_LIFE_BREAK_START = 484; 486 | ACT_DOTA_CAST_LIFE_BREAK_END = 485; 487 | ACT_DOTA_NIGHTSTALKER_TRANSITION = 486; 488 | ACT_DOTA_LIFESTEALER_RAGE = 487; 489 | ACT_DOTA_LIFESTEALER_OPEN_WOUNDS = 488; 490 | ACT_DOTA_SAND_KING_BURROW_IN = 489; 491 | ACT_DOTA_SAND_KING_BURROW_OUT = 490; 492 | ACT_DOTA_EARTHSHAKER_TOTEM_ATTACK = 491; 493 | ACT_DOTA_WHEEL_LAYER = 492; 494 | ACT_DOTA_ALCHEMIST_CHEMICAL_RAGE_START = 493; 495 | ACT_DOTA_ALCHEMIST_CONCOCTION = 494; 496 | ACT_DOTA_JAKIRO_LIQUIDFIRE_START = 495; 497 | ACT_DOTA_JAKIRO_LIQUIDFIRE_LOOP = 496; 498 | ACT_DOTA_LIFESTEALER_INFEST = 497; 499 | ACT_DOTA_LIFESTEALER_INFEST_END = 498; 500 | ACT_DOTA_LASSO_LOOP = 499; 501 | ACT_DOTA_ALCHEMIST_CONCOCTION_THROW = 500; 502 | ACT_DOTA_ALCHEMIST_CHEMICAL_RAGE_END = 501; 503 | ACT_DOTA_CAST_COLD_SNAP = 502; 504 | ACT_DOTA_CAST_GHOST_WALK = 503; 505 | ACT_DOTA_CAST_TORNADO = 504; 506 | ACT_DOTA_CAST_EMP = 505; 507 | ACT_DOTA_CAST_ALACRITY = 506; 508 | ACT_DOTA_CAST_CHAOS_METEOR = 507; 509 | ACT_DOTA_CAST_SUN_STRIKE = 508; 510 | ACT_DOTA_CAST_FORGE_SPIRIT = 509; 511 | ACT_DOTA_CAST_ICE_WALL = 510; 512 | ACT_DOTA_CAST_DEAFENING_BLAST = 511; 513 | ACT_DOTA_VICTORY = 512; 514 | ACT_DOTA_DEFEAT = 513; 515 | ACT_DOTA_SPIRIT_BREAKER_CHARGE_POSE = 514; 516 | ACT_DOTA_SPIRIT_BREAKER_CHARGE_END = 515; 517 | ACT_DOTA_TELEPORT = 516; 518 | ACT_DOTA_TELEPORT_END = 517; 519 | ACT_DOTA_CAST_REFRACTION = 518; 520 | ACT_DOTA_CAST_ABILITY_7 = 519; 521 | ACT_DOTA_CANCEL_SIREN_SONG = 520; 522 | ACT_DOTA_CHANNEL_ABILITY_7 = 521; 523 | ACT_DOTA_LOADOUT = 522; 524 | ACT_DOTA_FORCESTAFF_END = 523; 525 | ACT_DOTA_POOF_END = 524; 526 | ACT_DOTA_SLARK_POUNCE = 525; 527 | ACT_DOTA_MAGNUS_SKEWER_START = 526; 528 | ACT_DOTA_MAGNUS_SKEWER_END = 527; 529 | ACT_DOTA_MEDUSA_STONE_GAZE = 528; 530 | ACT_DOTA_RELAX_START = 529; 531 | ACT_DOTA_RELAX_LOOP = 530; 532 | ACT_DOTA_RELAX_END = 531; 533 | ACT_DOTA_CENTAUR_STAMPEDE = 532; 534 | ACT_DOTA_BELLYACHE_START = 533; 535 | ACT_DOTA_BELLYACHE_LOOP = 534; 536 | ACT_DOTA_BELLYACHE_END = 535; 537 | ACT_DOTA_ROQUELAIRE_LAND = 536; 538 | ACT_DOTA_ROQUELAIRE_LAND_IDLE = 537; 539 | ACT_DOTA_GREEVIL_CAST = 538; 540 | ACT_DOTA_GREEVIL_OVERRIDE_ABILITY = 539; 541 | ACT_DOTA_GREEVIL_HOOK_START = 540; 542 | ACT_DOTA_GREEVIL_HOOK_END = 541; 543 | ACT_DOTA_GREEVIL_BLINK_BONE = 542; 544 | ACT_DOTA_IDLE_SLEEPING = 543; 545 | ACT_DOTA_INTRO = 544; 546 | ACT_DOTA_GESTURE_POINT = 545; 547 | ACT_DOTA_GESTURE_ACCENT = 546; 548 | ACT_DOTA_SLEEPING_END = 547; 549 | ACT_DOTA_AMBUSH = 548; 550 | ACT_DOTA_ITEM_LOOK = 549; 551 | ACT_DOTA_STARTLE = 550; 552 | ACT_DOTA_FRUSTRATION = 551; 553 | ACT_DOTA_TELEPORT_REACT = 552; 554 | ACT_DOTA_TELEPORT_END_REACT = 553; 555 | ACT_DOTA_SHRUG = 554; 556 | ACT_DOTA_RELAX_LOOP_END = 555; 557 | ACT_DOTA_PRESENT_ITEM = 556; 558 | ACT_DOTA_IDLE_IMPATIENT = 557; 559 | ACT_DOTA_SHARPEN_WEAPON = 558; 560 | ACT_DOTA_SHARPEN_WEAPON_OUT = 559; 561 | ACT_DOTA_IDLE_SLEEPING_END = 560; 562 | ACT_DOTA_BRIDGE_DESTROY = 561; 563 | ACT_DOTA_TAUNT_SNIPER = 562; 564 | ACT_DOTA_DEATH_BY_SNIPER = 563; 565 | ACT_DOTA_LOOK_AROUND = 564; 566 | ACT_DOTA_CAGED_CREEP_RAGE = 565; 567 | ACT_DOTA_CAGED_CREEP_RAGE_OUT = 566; 568 | ACT_DOTA_CAGED_CREEP_SMASH = 567; 569 | ACT_DOTA_CAGED_CREEP_SMASH_OUT = 568; 570 | ACT_DOTA_IDLE_IMPATIENT_SWORD_TAP = 569; 571 | ACT_DOTA_INTRO_LOOP = 570; 572 | ACT_DOTA_BRIDGE_THREAT = 571; 573 | } 574 | 575 | -------------------------------------------------------------------------------- /skadi/protoc/networkbasetypes_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: networkbasetypes.proto 3 | 4 | from google.protobuf.internal import enum_type_wrapper 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import descriptor_pb2 9 | # @@protoc_insertion_point(imports) 10 | 11 | 12 | import google.protobuf.descriptor_pb2 13 | 14 | 15 | DESCRIPTOR = _descriptor.FileDescriptor( 16 | name='networkbasetypes.proto', 17 | package='', 18 | serialized_pb='\n\x16networkbasetypes.proto\x1a google/protobuf/descriptor.proto\"-\n\nCMsgVector\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\"$\n\x0c\x43MsgVector2D\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\"-\n\nCMsgQAngle\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\"\xfc\x01\n\x11\x43SVCMsg_GameEvent\x12\x12\n\nevent_name\x18\x01 \x01(\t\x12\x0f\n\x07\x65ventid\x18\x02 \x01(\x05\x12&\n\x04keys\x18\x03 \x03(\x0b\x32\x18.CSVCMsg_GameEvent.key_t\x1a\x99\x01\n\x05key_t\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x12\n\nval_string\x18\x02 \x01(\t\x12\x11\n\tval_float\x18\x03 \x01(\x02\x12\x10\n\x08val_long\x18\x04 \x01(\x05\x12\x11\n\tval_short\x18\x05 \x01(\x05\x12\x10\n\x08val_byte\x18\x06 \x01(\x05\x12\x10\n\x08val_bool\x18\x07 \x01(\x08\x12\x12\n\nval_uint64\x18\x08 \x01(\x04\"\x85\x01\n\x16\x43SVCMsgList_GameEvents\x12/\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x1f.CSVCMsgList_GameEvents.event_t\x1a:\n\x07\x65vent_t\x12\x0c\n\x04tick\x18\x01 \x01(\x05\x12!\n\x05\x65vent\x18\x02 \x01(\x0b\x32\x12.CSVCMsg_GameEvent\"9\n\x13\x43SVCMsg_UserMessage\x12\x10\n\x08msg_type\x18\x01 \x01(\x05\x12\x10\n\x08msg_data\x18\x02 \x01(\x0c\"\x8f\x01\n\x18\x43SVCMsgList_UserMessages\x12\x35\n\x08usermsgs\x18\x01 \x03(\x0b\x32#.CSVCMsgList_UserMessages.usermsg_t\x1a<\n\tusermsg_t\x12\x0c\n\x04tick\x18\x01 \x01(\x05\x12!\n\x03msg\x18\x02 \x01(\x0b\x32\x14.CSVCMsg_UserMessage*\xd2\x01\n\x0bSIGNONSTATE\x12\x14\n\x10SIGNONSTATE_NONE\x10\x00\x12\x19\n\x15SIGNONSTATE_CHALLENGE\x10\x01\x12\x19\n\x15SIGNONSTATE_CONNECTED\x10\x02\x12\x13\n\x0fSIGNONSTATE_NEW\x10\x03\x12\x18\n\x14SIGNONSTATE_PRESPAWN\x10\x04\x12\x15\n\x11SIGNONSTATE_SPAWN\x10\x05\x12\x14\n\x10SIGNONSTATE_FULL\x10\x06\x12\x1b\n\x17SIGNONSTATE_CHANGELEVEL\x10\x07') 19 | 20 | _SIGNONSTATE = _descriptor.EnumDescriptor( 21 | name='SIGNONSTATE', 22 | full_name='SIGNONSTATE', 23 | filename=None, 24 | file=DESCRIPTOR, 25 | values=[ 26 | _descriptor.EnumValueDescriptor( 27 | name='SIGNONSTATE_NONE', index=0, number=0, 28 | options=None, 29 | type=None), 30 | _descriptor.EnumValueDescriptor( 31 | name='SIGNONSTATE_CHALLENGE', index=1, number=1, 32 | options=None, 33 | type=None), 34 | _descriptor.EnumValueDescriptor( 35 | name='SIGNONSTATE_CONNECTED', index=2, number=2, 36 | options=None, 37 | type=None), 38 | _descriptor.EnumValueDescriptor( 39 | name='SIGNONSTATE_NEW', index=3, number=3, 40 | options=None, 41 | type=None), 42 | _descriptor.EnumValueDescriptor( 43 | name='SIGNONSTATE_PRESPAWN', index=4, number=4, 44 | options=None, 45 | type=None), 46 | _descriptor.EnumValueDescriptor( 47 | name='SIGNONSTATE_SPAWN', index=5, number=5, 48 | options=None, 49 | type=None), 50 | _descriptor.EnumValueDescriptor( 51 | name='SIGNONSTATE_FULL', index=6, number=6, 52 | options=None, 53 | type=None), 54 | _descriptor.EnumValueDescriptor( 55 | name='SIGNONSTATE_CHANGELEVEL', index=7, number=7, 56 | options=None, 57 | type=None), 58 | ], 59 | containing_type=None, 60 | options=None, 61 | serialized_start=789, 62 | serialized_end=999, 63 | ) 64 | 65 | SIGNONSTATE = enum_type_wrapper.EnumTypeWrapper(_SIGNONSTATE) 66 | SIGNONSTATE_NONE = 0 67 | SIGNONSTATE_CHALLENGE = 1 68 | SIGNONSTATE_CONNECTED = 2 69 | SIGNONSTATE_NEW = 3 70 | SIGNONSTATE_PRESPAWN = 4 71 | SIGNONSTATE_SPAWN = 5 72 | SIGNONSTATE_FULL = 6 73 | SIGNONSTATE_CHANGELEVEL = 7 74 | 75 | 76 | 77 | _CMSGVECTOR = _descriptor.Descriptor( 78 | name='CMsgVector', 79 | full_name='CMsgVector', 80 | filename=None, 81 | file=DESCRIPTOR, 82 | containing_type=None, 83 | fields=[ 84 | _descriptor.FieldDescriptor( 85 | name='x', full_name='CMsgVector.x', index=0, 86 | number=1, type=2, cpp_type=6, label=1, 87 | has_default_value=False, default_value=0, 88 | message_type=None, enum_type=None, containing_type=None, 89 | is_extension=False, extension_scope=None, 90 | options=None), 91 | _descriptor.FieldDescriptor( 92 | name='y', full_name='CMsgVector.y', index=1, 93 | number=2, type=2, cpp_type=6, label=1, 94 | has_default_value=False, default_value=0, 95 | message_type=None, enum_type=None, containing_type=None, 96 | is_extension=False, extension_scope=None, 97 | options=None), 98 | _descriptor.FieldDescriptor( 99 | name='z', full_name='CMsgVector.z', index=2, 100 | number=3, type=2, cpp_type=6, label=1, 101 | has_default_value=False, default_value=0, 102 | message_type=None, enum_type=None, containing_type=None, 103 | is_extension=False, extension_scope=None, 104 | options=None), 105 | ], 106 | extensions=[ 107 | ], 108 | nested_types=[], 109 | enum_types=[ 110 | ], 111 | options=None, 112 | is_extendable=False, 113 | extension_ranges=[], 114 | serialized_start=60, 115 | serialized_end=105, 116 | ) 117 | 118 | 119 | _CMSGVECTOR2D = _descriptor.Descriptor( 120 | name='CMsgVector2D', 121 | full_name='CMsgVector2D', 122 | filename=None, 123 | file=DESCRIPTOR, 124 | containing_type=None, 125 | fields=[ 126 | _descriptor.FieldDescriptor( 127 | name='x', full_name='CMsgVector2D.x', index=0, 128 | number=1, type=2, cpp_type=6, label=1, 129 | has_default_value=False, default_value=0, 130 | message_type=None, enum_type=None, containing_type=None, 131 | is_extension=False, extension_scope=None, 132 | options=None), 133 | _descriptor.FieldDescriptor( 134 | name='y', full_name='CMsgVector2D.y', index=1, 135 | number=2, type=2, cpp_type=6, label=1, 136 | has_default_value=False, default_value=0, 137 | message_type=None, enum_type=None, containing_type=None, 138 | is_extension=False, extension_scope=None, 139 | options=None), 140 | ], 141 | extensions=[ 142 | ], 143 | nested_types=[], 144 | enum_types=[ 145 | ], 146 | options=None, 147 | is_extendable=False, 148 | extension_ranges=[], 149 | serialized_start=107, 150 | serialized_end=143, 151 | ) 152 | 153 | 154 | _CMSGQANGLE = _descriptor.Descriptor( 155 | name='CMsgQAngle', 156 | full_name='CMsgQAngle', 157 | filename=None, 158 | file=DESCRIPTOR, 159 | containing_type=None, 160 | fields=[ 161 | _descriptor.FieldDescriptor( 162 | name='x', full_name='CMsgQAngle.x', index=0, 163 | number=1, type=2, cpp_type=6, label=1, 164 | has_default_value=False, default_value=0, 165 | message_type=None, enum_type=None, containing_type=None, 166 | is_extension=False, extension_scope=None, 167 | options=None), 168 | _descriptor.FieldDescriptor( 169 | name='y', full_name='CMsgQAngle.y', index=1, 170 | number=2, type=2, cpp_type=6, label=1, 171 | has_default_value=False, default_value=0, 172 | message_type=None, enum_type=None, containing_type=None, 173 | is_extension=False, extension_scope=None, 174 | options=None), 175 | _descriptor.FieldDescriptor( 176 | name='z', full_name='CMsgQAngle.z', index=2, 177 | number=3, type=2, cpp_type=6, label=1, 178 | has_default_value=False, default_value=0, 179 | message_type=None, enum_type=None, containing_type=None, 180 | is_extension=False, extension_scope=None, 181 | options=None), 182 | ], 183 | extensions=[ 184 | ], 185 | nested_types=[], 186 | enum_types=[ 187 | ], 188 | options=None, 189 | is_extendable=False, 190 | extension_ranges=[], 191 | serialized_start=145, 192 | serialized_end=190, 193 | ) 194 | 195 | 196 | _CSVCMSG_GAMEEVENT_KEY_T = _descriptor.Descriptor( 197 | name='key_t', 198 | full_name='CSVCMsg_GameEvent.key_t', 199 | filename=None, 200 | file=DESCRIPTOR, 201 | containing_type=None, 202 | fields=[ 203 | _descriptor.FieldDescriptor( 204 | name='type', full_name='CSVCMsg_GameEvent.key_t.type', index=0, 205 | number=1, type=5, cpp_type=1, label=1, 206 | has_default_value=False, default_value=0, 207 | message_type=None, enum_type=None, containing_type=None, 208 | is_extension=False, extension_scope=None, 209 | options=None), 210 | _descriptor.FieldDescriptor( 211 | name='val_string', full_name='CSVCMsg_GameEvent.key_t.val_string', index=1, 212 | number=2, type=9, cpp_type=9, label=1, 213 | has_default_value=False, default_value=unicode("", "utf-8"), 214 | message_type=None, enum_type=None, containing_type=None, 215 | is_extension=False, extension_scope=None, 216 | options=None), 217 | _descriptor.FieldDescriptor( 218 | name='val_float', full_name='CSVCMsg_GameEvent.key_t.val_float', index=2, 219 | number=3, type=2, cpp_type=6, label=1, 220 | has_default_value=False, default_value=0, 221 | message_type=None, enum_type=None, containing_type=None, 222 | is_extension=False, extension_scope=None, 223 | options=None), 224 | _descriptor.FieldDescriptor( 225 | name='val_long', full_name='CSVCMsg_GameEvent.key_t.val_long', index=3, 226 | number=4, type=5, cpp_type=1, label=1, 227 | has_default_value=False, default_value=0, 228 | message_type=None, enum_type=None, containing_type=None, 229 | is_extension=False, extension_scope=None, 230 | options=None), 231 | _descriptor.FieldDescriptor( 232 | name='val_short', full_name='CSVCMsg_GameEvent.key_t.val_short', index=4, 233 | number=5, type=5, cpp_type=1, label=1, 234 | has_default_value=False, default_value=0, 235 | message_type=None, enum_type=None, containing_type=None, 236 | is_extension=False, extension_scope=None, 237 | options=None), 238 | _descriptor.FieldDescriptor( 239 | name='val_byte', full_name='CSVCMsg_GameEvent.key_t.val_byte', index=5, 240 | number=6, type=5, cpp_type=1, label=1, 241 | has_default_value=False, default_value=0, 242 | message_type=None, enum_type=None, containing_type=None, 243 | is_extension=False, extension_scope=None, 244 | options=None), 245 | _descriptor.FieldDescriptor( 246 | name='val_bool', full_name='CSVCMsg_GameEvent.key_t.val_bool', index=6, 247 | number=7, type=8, cpp_type=7, label=1, 248 | has_default_value=False, default_value=False, 249 | message_type=None, enum_type=None, containing_type=None, 250 | is_extension=False, extension_scope=None, 251 | options=None), 252 | _descriptor.FieldDescriptor( 253 | name='val_uint64', full_name='CSVCMsg_GameEvent.key_t.val_uint64', index=7, 254 | number=8, type=4, cpp_type=4, label=1, 255 | has_default_value=False, default_value=0, 256 | message_type=None, enum_type=None, containing_type=None, 257 | is_extension=False, extension_scope=None, 258 | options=None), 259 | ], 260 | extensions=[ 261 | ], 262 | nested_types=[], 263 | enum_types=[ 264 | ], 265 | options=None, 266 | is_extendable=False, 267 | extension_ranges=[], 268 | serialized_start=292, 269 | serialized_end=445, 270 | ) 271 | 272 | _CSVCMSG_GAMEEVENT = _descriptor.Descriptor( 273 | name='CSVCMsg_GameEvent', 274 | full_name='CSVCMsg_GameEvent', 275 | filename=None, 276 | file=DESCRIPTOR, 277 | containing_type=None, 278 | fields=[ 279 | _descriptor.FieldDescriptor( 280 | name='event_name', full_name='CSVCMsg_GameEvent.event_name', index=0, 281 | number=1, type=9, cpp_type=9, label=1, 282 | has_default_value=False, default_value=unicode("", "utf-8"), 283 | message_type=None, enum_type=None, containing_type=None, 284 | is_extension=False, extension_scope=None, 285 | options=None), 286 | _descriptor.FieldDescriptor( 287 | name='eventid', full_name='CSVCMsg_GameEvent.eventid', index=1, 288 | number=2, type=5, cpp_type=1, label=1, 289 | has_default_value=False, default_value=0, 290 | message_type=None, enum_type=None, containing_type=None, 291 | is_extension=False, extension_scope=None, 292 | options=None), 293 | _descriptor.FieldDescriptor( 294 | name='keys', full_name='CSVCMsg_GameEvent.keys', index=2, 295 | number=3, type=11, cpp_type=10, label=3, 296 | has_default_value=False, default_value=[], 297 | message_type=None, enum_type=None, containing_type=None, 298 | is_extension=False, extension_scope=None, 299 | options=None), 300 | ], 301 | extensions=[ 302 | ], 303 | nested_types=[_CSVCMSG_GAMEEVENT_KEY_T, ], 304 | enum_types=[ 305 | ], 306 | options=None, 307 | is_extendable=False, 308 | extension_ranges=[], 309 | serialized_start=193, 310 | serialized_end=445, 311 | ) 312 | 313 | 314 | _CSVCMSGLIST_GAMEEVENTS_EVENT_T = _descriptor.Descriptor( 315 | name='event_t', 316 | full_name='CSVCMsgList_GameEvents.event_t', 317 | filename=None, 318 | file=DESCRIPTOR, 319 | containing_type=None, 320 | fields=[ 321 | _descriptor.FieldDescriptor( 322 | name='tick', full_name='CSVCMsgList_GameEvents.event_t.tick', index=0, 323 | number=1, type=5, cpp_type=1, label=1, 324 | has_default_value=False, default_value=0, 325 | message_type=None, enum_type=None, containing_type=None, 326 | is_extension=False, extension_scope=None, 327 | options=None), 328 | _descriptor.FieldDescriptor( 329 | name='event', full_name='CSVCMsgList_GameEvents.event_t.event', index=1, 330 | number=2, type=11, cpp_type=10, label=1, 331 | has_default_value=False, default_value=None, 332 | message_type=None, enum_type=None, containing_type=None, 333 | is_extension=False, extension_scope=None, 334 | options=None), 335 | ], 336 | extensions=[ 337 | ], 338 | nested_types=[], 339 | enum_types=[ 340 | ], 341 | options=None, 342 | is_extendable=False, 343 | extension_ranges=[], 344 | serialized_start=523, 345 | serialized_end=581, 346 | ) 347 | 348 | _CSVCMSGLIST_GAMEEVENTS = _descriptor.Descriptor( 349 | name='CSVCMsgList_GameEvents', 350 | full_name='CSVCMsgList_GameEvents', 351 | filename=None, 352 | file=DESCRIPTOR, 353 | containing_type=None, 354 | fields=[ 355 | _descriptor.FieldDescriptor( 356 | name='events', full_name='CSVCMsgList_GameEvents.events', index=0, 357 | number=1, type=11, cpp_type=10, label=3, 358 | has_default_value=False, default_value=[], 359 | message_type=None, enum_type=None, containing_type=None, 360 | is_extension=False, extension_scope=None, 361 | options=None), 362 | ], 363 | extensions=[ 364 | ], 365 | nested_types=[_CSVCMSGLIST_GAMEEVENTS_EVENT_T, ], 366 | enum_types=[ 367 | ], 368 | options=None, 369 | is_extendable=False, 370 | extension_ranges=[], 371 | serialized_start=448, 372 | serialized_end=581, 373 | ) 374 | 375 | 376 | _CSVCMSG_USERMESSAGE = _descriptor.Descriptor( 377 | name='CSVCMsg_UserMessage', 378 | full_name='CSVCMsg_UserMessage', 379 | filename=None, 380 | file=DESCRIPTOR, 381 | containing_type=None, 382 | fields=[ 383 | _descriptor.FieldDescriptor( 384 | name='msg_type', full_name='CSVCMsg_UserMessage.msg_type', index=0, 385 | number=1, type=5, cpp_type=1, label=1, 386 | has_default_value=False, default_value=0, 387 | message_type=None, enum_type=None, containing_type=None, 388 | is_extension=False, extension_scope=None, 389 | options=None), 390 | _descriptor.FieldDescriptor( 391 | name='msg_data', full_name='CSVCMsg_UserMessage.msg_data', index=1, 392 | number=2, type=12, cpp_type=9, label=1, 393 | has_default_value=False, default_value="", 394 | message_type=None, enum_type=None, containing_type=None, 395 | is_extension=False, extension_scope=None, 396 | options=None), 397 | ], 398 | extensions=[ 399 | ], 400 | nested_types=[], 401 | enum_types=[ 402 | ], 403 | options=None, 404 | is_extendable=False, 405 | extension_ranges=[], 406 | serialized_start=583, 407 | serialized_end=640, 408 | ) 409 | 410 | 411 | _CSVCMSGLIST_USERMESSAGES_USERMSG_T = _descriptor.Descriptor( 412 | name='usermsg_t', 413 | full_name='CSVCMsgList_UserMessages.usermsg_t', 414 | filename=None, 415 | file=DESCRIPTOR, 416 | containing_type=None, 417 | fields=[ 418 | _descriptor.FieldDescriptor( 419 | name='tick', full_name='CSVCMsgList_UserMessages.usermsg_t.tick', index=0, 420 | number=1, type=5, cpp_type=1, label=1, 421 | has_default_value=False, default_value=0, 422 | message_type=None, enum_type=None, containing_type=None, 423 | is_extension=False, extension_scope=None, 424 | options=None), 425 | _descriptor.FieldDescriptor( 426 | name='msg', full_name='CSVCMsgList_UserMessages.usermsg_t.msg', index=1, 427 | number=2, type=11, cpp_type=10, label=1, 428 | has_default_value=False, default_value=None, 429 | message_type=None, enum_type=None, containing_type=None, 430 | is_extension=False, extension_scope=None, 431 | options=None), 432 | ], 433 | extensions=[ 434 | ], 435 | nested_types=[], 436 | enum_types=[ 437 | ], 438 | options=None, 439 | is_extendable=False, 440 | extension_ranges=[], 441 | serialized_start=726, 442 | serialized_end=786, 443 | ) 444 | 445 | _CSVCMSGLIST_USERMESSAGES = _descriptor.Descriptor( 446 | name='CSVCMsgList_UserMessages', 447 | full_name='CSVCMsgList_UserMessages', 448 | filename=None, 449 | file=DESCRIPTOR, 450 | containing_type=None, 451 | fields=[ 452 | _descriptor.FieldDescriptor( 453 | name='usermsgs', full_name='CSVCMsgList_UserMessages.usermsgs', index=0, 454 | number=1, type=11, cpp_type=10, label=3, 455 | has_default_value=False, default_value=[], 456 | message_type=None, enum_type=None, containing_type=None, 457 | is_extension=False, extension_scope=None, 458 | options=None), 459 | ], 460 | extensions=[ 461 | ], 462 | nested_types=[_CSVCMSGLIST_USERMESSAGES_USERMSG_T, ], 463 | enum_types=[ 464 | ], 465 | options=None, 466 | is_extendable=False, 467 | extension_ranges=[], 468 | serialized_start=643, 469 | serialized_end=786, 470 | ) 471 | 472 | _CSVCMSG_GAMEEVENT_KEY_T.containing_type = _CSVCMSG_GAMEEVENT; 473 | _CSVCMSG_GAMEEVENT.fields_by_name['keys'].message_type = _CSVCMSG_GAMEEVENT_KEY_T 474 | _CSVCMSGLIST_GAMEEVENTS_EVENT_T.fields_by_name['event'].message_type = _CSVCMSG_GAMEEVENT 475 | _CSVCMSGLIST_GAMEEVENTS_EVENT_T.containing_type = _CSVCMSGLIST_GAMEEVENTS; 476 | _CSVCMSGLIST_GAMEEVENTS.fields_by_name['events'].message_type = _CSVCMSGLIST_GAMEEVENTS_EVENT_T 477 | _CSVCMSGLIST_USERMESSAGES_USERMSG_T.fields_by_name['msg'].message_type = _CSVCMSG_USERMESSAGE 478 | _CSVCMSGLIST_USERMESSAGES_USERMSG_T.containing_type = _CSVCMSGLIST_USERMESSAGES; 479 | _CSVCMSGLIST_USERMESSAGES.fields_by_name['usermsgs'].message_type = _CSVCMSGLIST_USERMESSAGES_USERMSG_T 480 | DESCRIPTOR.message_types_by_name['CMsgVector'] = _CMSGVECTOR 481 | DESCRIPTOR.message_types_by_name['CMsgVector2D'] = _CMSGVECTOR2D 482 | DESCRIPTOR.message_types_by_name['CMsgQAngle'] = _CMSGQANGLE 483 | DESCRIPTOR.message_types_by_name['CSVCMsg_GameEvent'] = _CSVCMSG_GAMEEVENT 484 | DESCRIPTOR.message_types_by_name['CSVCMsgList_GameEvents'] = _CSVCMSGLIST_GAMEEVENTS 485 | DESCRIPTOR.message_types_by_name['CSVCMsg_UserMessage'] = _CSVCMSG_USERMESSAGE 486 | DESCRIPTOR.message_types_by_name['CSVCMsgList_UserMessages'] = _CSVCMSGLIST_USERMESSAGES 487 | 488 | class CMsgVector(_message.Message): 489 | __metaclass__ = _reflection.GeneratedProtocolMessageType 490 | DESCRIPTOR = _CMSGVECTOR 491 | 492 | # @@protoc_insertion_point(class_scope:CMsgVector) 493 | 494 | class CMsgVector2D(_message.Message): 495 | __metaclass__ = _reflection.GeneratedProtocolMessageType 496 | DESCRIPTOR = _CMSGVECTOR2D 497 | 498 | # @@protoc_insertion_point(class_scope:CMsgVector2D) 499 | 500 | class CMsgQAngle(_message.Message): 501 | __metaclass__ = _reflection.GeneratedProtocolMessageType 502 | DESCRIPTOR = _CMSGQANGLE 503 | 504 | # @@protoc_insertion_point(class_scope:CMsgQAngle) 505 | 506 | class CSVCMsg_GameEvent(_message.Message): 507 | __metaclass__ = _reflection.GeneratedProtocolMessageType 508 | 509 | class key_t(_message.Message): 510 | __metaclass__ = _reflection.GeneratedProtocolMessageType 511 | DESCRIPTOR = _CSVCMSG_GAMEEVENT_KEY_T 512 | 513 | # @@protoc_insertion_point(class_scope:CSVCMsg_GameEvent.key_t) 514 | DESCRIPTOR = _CSVCMSG_GAMEEVENT 515 | 516 | # @@protoc_insertion_point(class_scope:CSVCMsg_GameEvent) 517 | 518 | class CSVCMsgList_GameEvents(_message.Message): 519 | __metaclass__ = _reflection.GeneratedProtocolMessageType 520 | 521 | class event_t(_message.Message): 522 | __metaclass__ = _reflection.GeneratedProtocolMessageType 523 | DESCRIPTOR = _CSVCMSGLIST_GAMEEVENTS_EVENT_T 524 | 525 | # @@protoc_insertion_point(class_scope:CSVCMsgList_GameEvents.event_t) 526 | DESCRIPTOR = _CSVCMSGLIST_GAMEEVENTS 527 | 528 | # @@protoc_insertion_point(class_scope:CSVCMsgList_GameEvents) 529 | 530 | class CSVCMsg_UserMessage(_message.Message): 531 | __metaclass__ = _reflection.GeneratedProtocolMessageType 532 | DESCRIPTOR = _CSVCMSG_USERMESSAGE 533 | 534 | # @@protoc_insertion_point(class_scope:CSVCMsg_UserMessage) 535 | 536 | class CSVCMsgList_UserMessages(_message.Message): 537 | __metaclass__ = _reflection.GeneratedProtocolMessageType 538 | 539 | class usermsg_t(_message.Message): 540 | __metaclass__ = _reflection.GeneratedProtocolMessageType 541 | DESCRIPTOR = _CSVCMSGLIST_USERMESSAGES_USERMSG_T 542 | 543 | # @@protoc_insertion_point(class_scope:CSVCMsgList_UserMessages.usermsg_t) 544 | DESCRIPTOR = _CSVCMSGLIST_USERMESSAGES 545 | 546 | # @@protoc_insertion_point(class_scope:CSVCMsgList_UserMessages) 547 | 548 | 549 | # @@protoc_insertion_point(module_scope) 550 | --------------------------------------------------------------------------------