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 scan(prologue, demo_io, tick=None): full_packets, remaining_packets = [], [] if tick is not None: iter_bootstrap = iter(demo_io) try: p, m = next(iter_bootstrap) item = (p, d_io.parse(p.kind, p.compressed, m)) while True: if p.kind == pb_d.DEM_FullPacket: full_packets.append(item) remaining_packets = [] else: remaining_packets.append(item) if p.tick >= tick: break p, m = next(iter_bootstrap) item = (p, d_io.parse(p.kind, p.compressed, m)) except StopIteration: raise EOFError() return full_packets, remaining_packets
def __init__(self, abspath): if hasattr(abspath, "read"): infile = abspath elif abspath.lower().endswith(".bz2"): infile = bz2.BZ2File(abspath, "r") else: infile = _io.open(abspath, 'r+b') if infile.read(8) != "PBUFDEM\0": raise InvalidDemo('malformed header') gio = bytearray(infile.read(4)) # LE uint file offset gio = sum(gio[i] << (i * 8) for i in range(4)) try: tell = infile.tell() infile.seek(gio) p, m = d_io.construct(infile).read() self.file_info = d_io.parse(p.kind, p.compressed, m) assert p.kind == pb_d.DEM_FileInfo infile.seek(tell) except EOFError: raise InvalidDemo('no end game summary') self.prologue = load(infile) self.io = infile self._tell = infile.tell()
def iterfullticks(self): iter_entries = iter(self.demo_io) while True: peek, message = next(iter_entries) if peek.kind == pb_d.DEM_Stop: raise StopIteration() elif peek.kind != pb_d.DEM_FullPacket: continue pro = self.prologue full_packet = (peek, d_io.parse(peek.kind, peek.compressed, message)) self.world, self.modifiers, self.string_tables = reconstitute( [full_packet], pro.class_bits, pro.recv_tables, self.string_tables) self.tick = peek.tick self.user_messages = [] self.game_events = [] yield [ self.tick, self.user_messages, self.game_events, self.world, self.modifiers ]
def __init__(self, prologue, io, world, string_tables, rem, sparse=False): self.prologue = prologue self.demo_io = d_io.construct(io) self.world = world self.string_tables = string_tables self.sparse = sparse for peek, message in rem: pbmsg = d_io.parse(peek.kind, peek.compressed, message) self.advance(peek.tick, pbmsg)
def advance(): try: peek, message = next(iter_entries) if peek.kind == pb_d.DEM_FullPacket: return advance() # skip elif peek.kind == pb_d.DEM_Stop: raise StopIteration() pbmsg = d_io.parse(peek.kind, peek.compressed, message) return self.advance(peek.tick, pbmsg) except StopIteration: return None
def __init__(self, abspath): infile = _io.open(abspath, 'r+b') if infile.read(8) != "PBUFDEM\0": raise InvalidDemo('malformed header') gio = bytearray(infile.read(4)) # LE uint file offset gio = sum(gio[i] << (i * 8) for i in range(4)) try: tell = infile.tell() infile.seek(gio) p, m = d_io.construct(infile).read() self.file_info = d_io.parse(p.kind, p.compressed, m) assert p.kind == pb_d.DEM_FileInfo infile.seek(tell) except EOFError: raise InvalidDemo('no end game summary') self.prologue = load(infile) self.io = infile self._tell = infile.tell()
def iterfullticks(self): iter_entries = iter(self.demo_io) while True: peek, message = next(iter_entries) if peek.kind == pb_d.DEM_Stop: raise StopIteration() elif peek.kind != pb_d.DEM_FullPacket: continue pro = self.prologue full_packet = (peek, d_io.parse(peek.kind, peek.compressed, message)) self.world, self.modifiers, self.string_tables = reconstitute( [full_packet], pro.class_bits, pro.recv_tables, self.string_tables) self.tick = peek.tick self.user_messages = [] self.game_events = [] yield [self.tick, self.user_messages, self.game_events, self.world, self.modifiers]
def __iter__(self): iter_entries = iter(self.demo_io) if self.tick is not None: t = self.tick um, ge = self.user_messages, self.game_events w, m = self.world, self.modifiers yield [t, um, ge, w, m] while True: peek, message = next(iter_entries) if peek.kind == pb_d.DEM_FullPacket: continue elif peek.kind == pb_d.DEM_Stop: raise StopIteration() else: pbmsg = d_io.parse(peek.kind, peek.compressed, message) self.advance(peek.tick, pbmsg) t = self.tick um, ge = self.user_messages, self.game_events w, m = self.world, self.modifiers yield [t, um, ge, w, m]
def all_dem_signon_packet(self): kind = pb_d.DEM_SignonPacket ee = self.find_all(kind) return ((p, d_io.parse(kind, p.compressed, m)) for p, m in ee)
def dem_send_tables(self): kind = pb_d.DEM_SendTables p, m = self.find(kind) return p, d_io.parse(kind, p.compressed, m)
def dem_class_info(self): kind = pb_d.DEM_ClassInfo p, m = self.find(kind) return p, d_io.parse(kind, p.compressed, m)
def dem_file_header(self): kind = pb_d.DEM_FileHeader p, m = self.find(kind) return p, d_io.parse(kind, p.compressed, m)
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)