def fast_forward(prologue, demo_io, tick=None): full_packets, remaining_packets = [], [] world = w.construct(prologue.recv_tables) string_tables = copy.deepcopy(prologue.string_tables) if tick: iter_bootstrap = iter(demo_io) try: while True: p, m = next(iter_bootstrap) if p.kind == pb_d.DEM_FullPacket: full_packets.append((p, m)) remaining_packets = [] else: remaining_packets.append((p, m)) if p.tick > tick - 2: # hack? break except StopIteration: raise EOFError() if full_packets: for peek, message in full_packets: full_packet = d_io.parse(peek.kind, peek.compressed, message) for table in full_packet.string_table.tables: assert not table.items_clientside entries = [(_i, e.str, e.data) for _i, e in enumerate(table.items)] string_tables[table.table_name].update_all(entries) peek, message = full_packets[-1] pbmsg = d_io.parse(peek.kind, peek.compressed, message) packet = i.construct(p_io.construct(pbmsg.packet.data)) peek, message = packet.find(pb_n.svc_PacketEntities) pe = p_io.parse(peek.kind, message) ct = pe.updated_entries bs = b_io.construct(pe.entity_data) unpacker = u_ent.construct(bs, -1, ct, False, prologue.class_bits, world) for index, mode, (cls, serial, diff) in unpacker: data = string_tables['instancebaseline'].get(cls)[1] bs = b_io.construct(data) unpacker = u_ent.construct(bs, -1, 1, False, prologue.class_bits, world) state = unpacker.unpack_baseline(prologue.recv_tables[cls]) state.update(diff) try: world.create(cls, index, serial, state) except AssertionError, e: # TODO: log here. pass
def advance(self, tick, pbmsg): packet = i.construct(p_io.construct(pbmsg.data)) all_ust = packet.find_all(pb_n.svc_UpdateStringTable) for _pbmsg in [p_io.parse(p.kind, m) for p, m in all_ust]: key = self.string_tables.keys()[_pbmsg.table_id] _st = self.string_tables[key] bs = b_io.construct(_pbmsg.string_data) ne = _pbmsg.num_changed_entries eb, sf, sb = _st.entry_bits, _st.size_fixed, _st.size_bits for entry in u_st.construct(bs, ne, eb, sf, sb): _st.update(entry) p, m = packet.find(pb_n.svc_PacketEntities) pe = p_io.parse(p.kind, m) ct = pe.updated_entries bs = b_io.construct(pe.entity_data) class_bits = self.prologue.class_bits recv_tables = self.prologue.recv_tables unpacker = u_ent.construct(bs, -1, ct, False, class_bits, self.world) for index, mode, context in unpacker: if mode & u_ent.PVS.Entering: cls, serial, diff = context data = self.string_tables['instancebaseline'].get(cls)[1] bs = b_io.construct(data) unpacker = u_ent.construct(bs, -1, 1, False, class_bits, self.world) state = unpacker.unpack_baseline(self.prologue.recv_tables[cls]) state.update(diff) self.world.create(cls, index, serial, state) elif mode & u_ent.PVS.Deleting: self.world.delete(index) elif mode ^ u_ent.PVS.Leaving: state = {} if self.sparse else dict(self.world.find_index(index)) state.update(context) self.world.update(index, state) all_um = packet.find_all(pb_n.svc_UserMessage) user_messages = [e_um.parse(p_io.parse(p.kind, m)) for p, m in all_um] all_ge = packet.find_all(pb_n.svc_GameEvent) gel = self.prologue.game_event_list game_events = [e_ge.parse(p_io.parse(p.kind, m), gel) for p, m in all_ge] modifiers = self.string_tables['ActiveModifiers'].observer _, gamerules = self.world.find_by_dt('DT_DOTAGamerulesProxy') modifiers.expire(gamerules[('DT_DOTAGamerules', 'm_fGameTime')]) return tick, user_messages, game_events, self.world, modifiers
def reconstitute(full_packets, class_bits, recv_tables, string_tables): w = e_w.construct(recv_tables) st = string_tables st_mn = st['ModifierNames'] st_am = st['ActiveModifiers'] m = e_m.construct(st_mn, baseline=st_am) for _, fp in full_packets: for table in fp.string_table.tables: assert not table.items_clientside entries = [(_i, e.str, e.data) for _i, e in enumerate(table.items)] st[table.table_name].update_all(entries) if table.table_name == 'ActiveModifiers': m.reset() [m.note(e) for e in entries] if full_packets: _, fp = full_packets[-1] packet = ie_packet.construct(p_io.construct(fp.packet.data)) _, pe = packet.svc_packet_entities ct = pe.updated_entries bs = b_io.construct(pe.entity_data) unpacker = u_ent.construct(bs, -1, ct, False, class_bits, w) for index, mode, (cls, serial, diff) in unpacker: data = st['instancebaseline'].get(cls)[1] bs = b_io.construct(data) unpacker = u_ent.construct(bs, -1, 1, False, class_bits, w) state = unpacker.unpack_baseline(recv_tables[cls]) state.update(diff) w.create(cls, index, serial, state, dict(diff)) return w, m, st
def advance(self, tick, pbmsg): self.tick = tick packet = ie_packet.construct(p_io.construct(pbmsg.data)) am_entries = [] for _, _pbmsg in packet.all_svc_update_string_table: key = self.string_tables.keys()[_pbmsg.table_id] _st = self.string_tables[key] bs = b_io.construct(_pbmsg.string_data) ne = _pbmsg.num_changed_entries eb, sf, sb = _st.entry_bits, _st.size_fixed, _st.size_bits entries = u_st.construct(bs, ne, eb, sf, sb) if key == 'ActiveModifiers': am_entries = list(entries) else: [_st.update(e) for e in entries] um = packet.find_all(pb_n.svc_UserMessage) self.user_messages = [e_um.parse(p_io.parse(p.kind, m)) for p, m in um] ge = packet.find_all(pb_n.svc_GameEvent) gel = self.prologue.game_event_list self.game_events = [ e_ge.parse(p_io.parse(p.kind, m), gel) for p, m in ge ] p, m = packet.find(pb_n.svc_PacketEntities) pe = p_io.parse(p.kind, m) ct = pe.updated_entries bs = b_io.construct(pe.entity_data) class_bits = self.prologue.class_bits recv_tables = self.prologue.recv_tables unpacker = u_ent.construct(bs, -1, ct, False, class_bits, self.world) for index, mode, context in unpacker: if mode & u_ent.PVS.Entering: cls, serial, diff = context data = self.string_tables['instancebaseline'].get(cls)[1] bs = b_io.construct(data) unpacker = u_ent.construct(bs, -1, 1, False, class_bits, self.world) state = unpacker.unpack_baseline( self.prologue.recv_tables[cls]) state.update(diff) self.world.create(cls, index, serial, state, dict(diff)) elif mode & u_ent.PVS.Deleting: self.world.delete(index) elif mode ^ u_ent.PVS.Leaving: state = dict(context) if self.sparse else dict( self.world.find_index(index), **context) diff = state if self.sparse else dict(context) self.world.update(index, state, diff) [self.modifiers.note(e) for e in am_entries] self.modifiers.limit(self.world) _, gamerules = self.world.find_by_dt('DT_DOTAGamerulesProxy') game_time_key = ('DT_DOTAGamerulesProxy', 'DT_DOTAGamerules.m_fGameTime') self.modifiers.expire(gamerules[game_time_key])
def advance(self, tick, pbmsg): self.tick = tick packet = ie_packet.construct(p_io.construct(pbmsg.data)) am_entries = [] for _, _pbmsg in packet.all_svc_update_string_table: key = self.string_tables.keys()[_pbmsg.table_id] _st = self.string_tables[key] bs = b_io.construct(_pbmsg.string_data) ne = _pbmsg.num_changed_entries eb, sf, sb = _st.entry_bits, _st.size_fixed, _st.size_bits entries = u_st.construct(bs, ne, eb, sf, sb) if key == 'ActiveModifiers': am_entries = list(entries) else: [_st.update(e) for e in entries] um = packet.find_all(pb_n.svc_UserMessage) self.user_messages = [e_um.parse(p_io.parse(p.kind, m)) for p, m in um] ge = packet.find_all(pb_n.svc_GameEvent) gel = self.prologue.game_event_list self.game_events = [e_ge.parse(p_io.parse(p.kind, m), gel) for p, m in ge] p, m = packet.find(pb_n.svc_PacketEntities) pe = p_io.parse(p.kind, m) ct = pe.updated_entries bs = b_io.construct(pe.entity_data) class_bits = self.prologue.class_bits recv_tables = self.prologue.recv_tables unpacker = u_ent.construct(bs, -1, ct, False, class_bits, self.world) for index, mode, context in unpacker: if mode & u_ent.PVS.Entering: cls, serial, diff = context data = self.string_tables['instancebaseline'].get(cls)[1] bs = b_io.construct(data) unpacker = u_ent.construct(bs, -1, 1, False, class_bits, self.world) state = unpacker.unpack_baseline(self.prologue.recv_tables[cls]) state.update(diff) self.world.create(cls, index, serial, state, dict(diff)) elif mode & u_ent.PVS.Deleting: self.world.delete(index) elif mode ^ u_ent.PVS.Leaving: state = dict(context) if self.sparse else dict(self.world.find_index(index), **context) diff = state if self.sparse else dict(context) self.world.update(index, state, diff) [self.modifiers.note(e) for e in am_entries] self.modifiers.limit(self.world) _, gamerules = self.world.find_by_dt('DT_DOTAGamerulesProxy') game_time_key = ('DT_DOTAGamerulesProxy', 'DT_DOTAGamerules.m_fGameTime') self.modifiers.expire(gamerules[game_time_key])
def advance(self, tick, pbmsg): packet = i.construct(p_io.construct(pbmsg.data)) all_ust = packet.find_all(pb_n.svc_UpdateStringTable) for _pbmsg in [p_io.parse(p.kind, m) for p, m in all_ust]: key = self.string_tables.keys()[_pbmsg.table_id] _st = self.string_tables[key] bs = b_io.construct(_pbmsg.string_data) ne = _pbmsg.num_changed_entries eb, sf, sb = _st.entry_bits, _st.size_fixed, _st.size_bits for entry in u_st.construct(bs, ne, eb, sf, sb): _st.update(entry) p, m = packet.find(pb_n.svc_PacketEntities) pe = p_io.parse(p.kind, m) ct = pe.updated_entries bs = b_io.construct(pe.entity_data) class_bits = self.prologue.class_bits recv_tables = self.prologue.recv_tables unpacker = u_ent.construct(bs, -1, ct, False, class_bits, self.world) for index, mode, context in unpacker: if mode & u_ent.PVS.Entering: cls, serial, diff = context data = self.string_tables['instancebaseline'].get(cls)[1] bs = b_io.construct(data) unpacker = u_ent.construct(bs, -1, 1, False, class_bits, self.world) state = unpacker.unpack_baseline( self.prologue.recv_tables[cls]) state.update(diff) self.world.create(cls, index, serial, state) elif mode & u_ent.PVS.Deleting: self.world.delete(index) elif mode ^ u_ent.PVS.Leaving: state = {} if self.sparse else dict( self.world.find_index(index)) state.update(context) self.world.update(index, state) all_um = packet.find_all(pb_n.svc_UserMessage) user_messages = [e_um.parse(p_io.parse(p.kind, m)) for p, m in all_um] all_ge = packet.find_all(pb_n.svc_GameEvent) gel = self.prologue.game_event_list game_events = [ e_ge.parse(p_io.parse(p.kind, m), gel) for p, m in all_ge ] modifiers = self.string_tables['ActiveModifiers'].observer _, gamerules = self.world.find_by_dt('DT_DOTAGamerulesProxy') modifiers.expire(gamerules[('DT_DOTAGamerules', 'm_fGameTime')]) return tick, user_messages, game_events, self.world, modifiers
def load(io, tick=0): demo_io = d_io.construct(io) prologue = id_prologue.construct(demo_io) # mash all packet svc messages together, then index them signon_packets = list(prologue.all_dem_signon_packet) data = ''.join([pb.data for _, pb in signon_packets]) packet = ie_packet.construct(p_io.construct(data)) # meta: file header _, pbmsg = prologue.dem_file_header file_header = FileHeader(*[getattr(pbmsg, a) for a in FileHeader._fields]) # meta: server info _, pbmsg = packet.svc_server_info server_info = ServerInfo(*[getattr(pbmsg, a) for a in ServerInfo._fields]) # meta: voice init _, pbmsg = packet.svc_voice_init voice_init = VoiceInit(*[getattr(pbmsg, a) for a in VoiceInit._fields]) # prologue: meta meta = Meta(file_header, server_info, voice_init) # prologue: send tables _, pbmsg = prologue.dem_send_tables _send_tables = ie_send_tables.construct(p_io.construct(pbmsg.data)) send_tables = c.OrderedDict() for pbmsg in [pb for _, pb in _send_tables.all_svc_send_table]: if pbmsg.is_end: break send_table = _parse_cdemo_send_table(pbmsg) send_tables[send_table.dt] = send_table # prologue: recv tables flattener = Flattener(send_tables) recv_tables = c.OrderedDict() _, pbmsg = prologue.dem_class_info class_info = c.OrderedDict() for cls in pbmsg.classes: _id, dt, name = str(cls.class_id), cls.table_name, cls.network_name class_info[_id] = (dt, name) for st in filter(test_needs_decoder, send_tables.values()): props = flattener.flatten(st) cls = next(_id for _id, (dt, _) in class_info.items() if dt == st.dt) recv_tables[cls] = dt_r.construct(st.dt, props) # prologue: string tables pbmsgs = [pb for _, pb in packet.all_svc_create_string_table] string_tables = _parse_all_csvc_create_string_tables(pbmsgs) # prologue: game event list _, pbmsg = packet.svc_game_event_list game_event_list = c.OrderedDict() for desc in pbmsg.descriptors: _id, name = desc.eventid, desc.name keys = [(k.type, k.name) for k in desc.keys] game_event_list[_id] = (name, keys) # prologue: class bits class_bits = server_info.max_classes.bit_length() return Prologue(meta, recv_tables, string_tables, game_event_list, class_bits)
def load(io, tick=0): demo_io = d_io.construct(io) prologue = i_p.construct(demo_io) # mash all packet svc messages together, then index them signon_packets = list(prologue.signon_packets) pbmsgs = [d_io.parse(p.kind, p.compressed, m) for p, m in signon_packets] data = ''.join([p.data for p in pbmsgs]) packet_io = p_io.construct(data) packet = i.construct(packet_io) # class info peek, message = prologue.class_info pbmsg = d_io.parse(peek.kind, peek.compressed, message) class_info = c.OrderedDict() for _c in pbmsg.classes: _id, dt, name = str(_c.class_id), _c.table_name, _c.network_name class_info[_id] = (dt, name) # send tables peek, message = prologue.send_tables pbmsg = d_io.parse(peek.kind, peek.compressed, message) send_tables = c.OrderedDict() for peek, message in p_io.construct(pbmsg.data): pbmsg = p_io.parse(peek.kind, message) if pbmsg.is_end: break send_table = _parse_cdemo_send_table(pbmsg) send_tables[send_table.dt] = send_table # recv tables flattener = Flattener(send_tables) recv_tables = c.OrderedDict() for st in filter(test_needs_decoder, send_tables.values()): props = flattener.flatten(st) cls = next(_id for _id, (dt, _) in class_info.items() if dt == st.dt) recv_tables[cls] = dt_r.construct(st.dt, props) # game event list peek, message = packet.find(pb_n.svc_GameEventList) pbmsg = p_io.parse(peek.kind, message) game_event_list = c.OrderedDict() for desc in pbmsg.descriptors: _id, name = desc.eventid, desc.name keys = [(k.type, k.name) for k in desc.keys] game_event_list[_id] = (name, keys) # string tables entries = packet.find_all(pb_n.svc_CreateStringTable) pbmsgs = [p_io.parse(p.kind, m) for p, m in entries] string_tables = _parse_all_csvc_create_string_tables(pbmsgs) # meta: file header peek, message = prologue.file_header pbmsg = d_io.parse(peek.kind, peek.compressed, message) file_header = FileHeader(*[getattr(pbmsg, a) for a in FileHeader._fields]) # meta: server_info peek, message = packet.find(pb_n.svc_ServerInfo) pbmsg = p_io.parse(peek.kind, message) server_info = ServerInfo(*[getattr(pbmsg, a) for a in ServerInfo._fields]) # meta: class bits class_bits = server_info.max_classes.bit_length() # meta: voice init peek, message = packet.find(pb_n.svc_VoiceInit) pbmsg = p_io.parse(peek.kind, message) voice_init = VoiceInit(*[getattr(pbmsg, a) for a in VoiceInit._fields]) meta = Meta(file_header, server_info, voice_init) return Prologue(meta, recv_tables, string_tables, game_event_list, class_bits)