예제 #1
0
 def open(self, filename):
     '''
     Opens the demo file.
     '''
     self.demofile = DemoFile()
     return self.demofile.open(filename)
예제 #2
0
 def open(self, filename):
     '''
     Opens the demo file.
     '''
     self.demofile = DemoFile()
     return self.demofile.open(filename)
예제 #3
0
class DemoDump(object):
    '''
    Dumps a CSGO demo
    '''
    def __init__(self):
        '''
        Constructor
        '''
        self.NET_MSG = {
                        net_NOP: [],
                        net_Disconnect: [],
                        net_File: [],
                        net_Tick: [],
                        net_StringCmd: [],
                        net_SetConVar: [],
                        net_SignonState: [],
                        svc_ServerInfo: [],
                        svc_SendTable: [],
                        svc_ClassInfo: [],
                        svc_SetPause: [],
                        svc_CreateStringTable: [],
                        svc_UpdateStringTable: [],
                        svc_VoiceInit: [],
                        svc_VoiceData: [],
                        svc_Print: [],
                        svc_Sounds: [],
                        svc_SetView: [],
                        svc_FixAngle: [],
                        svc_CrosshairAngle: [],
                        svc_BSPDecal: [],
                        svc_UserMessage: [],
                        svc_GameEvent: [],
                        svc_PacketEntities: [],
                        svc_TempEntities: [],
                        svc_Prefetch: [],
                        svc_Menu: [],
                        svc_GameEventList: [],
                        svc_GetCvarValue: []
                        }
        self.USER_MESSAGES = {}
        self.GAME_EVENTS = {}
        self.current_tick = 0
        self.descriptors = {}
        self.register_on_netmsg(svc_GameEvent, self._handle_gameevent)
        self.register_on_netmsg(svc_GameEventList, self._handle_gameeventlist)
        self.register_on_netmsg(svc_UserMessage, self._handle_usermessage)
        self.register_on_netmsg(svc_ServerInfo, self._server_info_update)
        self.register_on_netmsg(svc_CreateStringTable, self._server_create_stringtable)
        self.register_on_netmsg(svc_SendTable, self._send_table)
        self.register_on_netmsg(svc_UpdateStringTable, self._update_stringtable)
        self.register_on_netmsg(svc_ClassInfo, self._handle_classinfo)
        self.register_on_netmsg(net_Tick, self._handle_tick)
        
    def open(self, filename):
        '''
        Opens the demo file.
        '''
        self.demofile = DemoFile()
        return self.demofile.open(filename)
    
    
    def register_on_netmsg(self, msg, callback):
        '''
        Will register a callback to call when the given netmessage is received.
        Will throw an exception if the netmessage doesn't exist. For all netmessages see: netmessages_public.proto SVC_Messages
        '''
        if msg not in self.NET_MSG:
            raise "Net message not found"
        self.NET_MSG[msg].append(callback)
    
    def register_on_gameevent(self, msg, callback):
        '''
        Will register a callback to call when the given game event is called.
        Can give ID or name, SHOULD USE NAME, BECAUSE IDS CHANGE (?)
        Game events can be found in data/game_events.txt
        '''
        if msg not in self.GAME_EVENTS:
            self.GAME_EVENTS[msg] = []
        self.GAME_EVENTS[msg].append(callback)
    
    def register_on_usermessage(self, msg, callback):
        '''
        Not yet implemented.
        '''
        if not msg in self.USER_MESSAGES:
            self.USER_MESSAGES[msg] = []
        self.USER_MESSAGES[msg].append(callback)
    
    def dump(self):
        '''
        Will start analyzing the demo and executing the necessary game events
        '''
        finished = False
        while not finished:
            cmd, tick, playerslot = self.demofile.read_cmd_header()
            # print "%i - %i - % i " % (cmd, tick, playerslot)
            if cmd == DemoMessage.SYNCTICK:
                continue
            elif cmd == DemoMessage.STOP:
                finished = True
                break
            elif cmd == DemoMessage.CONSOLECMD:
                self.demofile.read_raw_data()
            elif cmd == DemoMessage.DATATABLES:
                self.demofile.read_raw_data()

            elif cmd == DemoMessage.STRINGTABLES:
                self.demofile.read_raw_data()
            elif cmd == DemoMessage.USERCMD:
                self.demofile.read_user_cmd()
            elif cmd == DemoMessage.SIGNON or cmd == DemoMessage.PACKET:
                self._handle_demo_packet()
    
    def _handle_usermessage(self, cmd, data):
        umsg = CSVCMsg_UserMessage()
        umsg.ParseFromString(data)
        name = ECstrike15UserMessages.Name(umsg.msg_type)
        callback_name = name.replace("CS_UM_", "")
        if callback_name in self.USER_MESSAGES:
            name = name.replace("CS_UM_", "CCSUsrMsg_")
            item = eval(name)()
            item.ParseFromString(umsg.msg_data)
            for callback in self.USER_MESSAGES[callback_name]:
                callback(item)
                
    def _handle_tick(self, cmd, data):
        tickinfo = CNETMsg_Tick()
        tickinfo.ParseFromString(data)
        self.current_tick = tickinfo.tick
    
    def _server_info_update(self, cmd, data):
        info = CSVCMsg_ServerInfo()
        info.ParseFromString(data)
        self.server_info = info
    
    def _handle_gameeventlist(self, cmd, data):
        '''
        Parses the list of given game events by the server
        '''
        gameeventlist = CSVCMsg_GameEventList()
        gameeventlist.ParseFromString(data)
        for desc in gameeventlist.descriptors:
            self.descriptors[desc.eventid] = (desc.eventid, desc.name, desc.keys, [])
            for key in desc.keys:
                self.descriptors[desc.eventid][3].append([key.type, key.name])
    
    def _handle_gameevent(self, cmd, data):
        '''
        handles the game events and fires the callback
        '''
        gameevent = CSVCMsg_GameEvent()
        gameevent.ParseFromString(data)
        name = self.descriptors[gameevent.eventid][1]
        if gameevent.eventid in self.GAME_EVENTS :
            event = GameEvent(gameevent, self.descriptors[gameevent.eventid], name)
            for callback in self.GAME_EVENTS[event.raw.eventid]:
                callback(event)
                
        
        if name in self.GAME_EVENTS:
            event = GameEvent(gameevent, self.descriptors[gameevent.eventid], name)
            for callback in self.GAME_EVENTS[name]:
                callback(event)
         
    stringtable_data = {}
    def _server_create_stringtable(self, cmd, data):
        '''
        Creates a string table from the given data.
        TO BE IMPLEMENTED
        '''
        table = CSVCMsg_CreateStringTable()
        # table_data = CSVCMsg_SendTable()
        table.ParseFromString(data)
        if table.name != "userinfo":
            return
        # table_data.ParseFromString(table.string_data)
        self.stringtable_data[table.name] = {'entries': table.num_entries,
                                             'user_data_fixed_size': table.user_data_fixed_size,
                                             'user_data_size': table.user_data_size,
                                             'user_data_size_bits': table.user_data_size_bits,
                                             'flags': table.flags,
                                             # 'data': table_data
                                             }
        '''
                int *pStringIndex = (int *)fieldInfo.pField;
        int nLen = pRestore->ReadInt();
        char *pTemp = (char *)stackalloc( nLen );
        pRestore->ReadString( pTemp, nLen, nLen );
        *pStringIndex = m_pStringTable->AddString( CBaseEntity::IsServer(), pTemp );
        '''
        
    def _update_stringtable(self, cmd, data):
        '''
        Updates a stringtable with the given data
        TO BE IMPLEMENTED
        '''
        update = CSVCMsg_UpdateStringTable()
        update.ParseFromString(data)
        
    def _send_table(self, cmd, data):
        table = CSVCMsg_SendTable()
        table.ParseFromString(data)
        print "%s: is end: %r, needs_decoder: %r" % (table.net_table_name, table.is_end, table.needs_decoder)
        for prop in table.props:
            print "Name: %s type: %i" % (prop.var_name, prop.type)
        print "-------------------------------"
        
    def _handle_classinfo(self, cmd, data):
        info = CSVCMsg_ClassInfo()
        info.ParseFromString(data)
        #print "CLASS INFO COUNT: %s, CREATE ON CLIENT: %r" % (len(info.classes), info.create_on_client)
        #for c in info.classes:
        #    print "%i: %s, %s" % (c.class_id, c.data_table_name, c.class_name)
                
    def _handle_demo_packet(self):
        info = self.demofile.read_cmd_info()
        self.demofile.read_sequence_info()  # ignore result
        length, buf = self.demofile.read_raw_data()
        
        if length > 0:
            self._dump_packet(buf, length)
         
            
    def _dump_packet(self, buf, length):
        index = 0
        while index < length:
            cmd, index = self.__read_int32(buf, index)
            size, index = self.__read_int32(buf, index)
            data = buf[index:index + size]
            if cmd in self.NET_MSG:
                for callback in self.NET_MSG[cmd]:
                    
                    callback(cmd, data);
                    
            index = index + size
        
    def __read_int32(self, buf, index):
        '''
        Reads an int32 from a binary buffer.
        '''
        b = 0
        count = 0
        result = 0
        
        cont = True
        while cont:
            if count == 5:
                return result
            b = struct.unpack_from("B", buf, index)
            b = b[0]
            index = index + 1
            result |= (b & 0x7F) << (7 * count)
            count = count + 1
            cont = b & 0x80
        return result, index
            
예제 #4
0
class DemoDump(object):
    '''
    Dumps a CSGO demo
    '''
    def __init__(self):
        '''
        Constructor
        '''
        self.NET_MSG = {
                        net_NOP: [],
                        net_Disconnect: [],
                        net_File: [],
                        net_Tick: [],
                        net_StringCmd: [],
                        net_SetConVar: [],
                        net_SignonState: [],
                        svc_ServerInfo: [],
                        svc_SendTable: [],
                        svc_ClassInfo: [],
                        svc_SetPause: [],
                        svc_CreateStringTable: [],
                        svc_UpdateStringTable: [],
                        svc_VoiceInit: [],
                        svc_VoiceData: [],
                        svc_Print: [],
                        svc_Sounds: [],
                        svc_SetView: [],
                        svc_FixAngle: [],
                        svc_CrosshairAngle: [],
                        svc_BSPDecal: [],
                        svc_UserMessage: [],
                        svc_GameEvent: [],
                        svc_PacketEntities: [],
                        svc_TempEntities: [],
                        svc_Prefetch: [],
                        svc_Menu: [],
                        svc_GameEventList: [],
                        svc_GetCvarValue: []
                        }
        self.USER_MESSAGES = {}
        self.GAME_EVENTS = {}
        self.current_tick = 0
        self.descriptors = {}
        self.register_on_netmsg(svc_GameEvent, self._handle_gameevent)
        self.register_on_netmsg(svc_GameEventList, self._handle_gameeventlist)
        self.register_on_netmsg(svc_UserMessage, self._handle_usermessage)
        self.register_on_netmsg(svc_ServerInfo, self._server_info_update)
        self.register_on_netmsg(svc_CreateStringTable, self._server_create_stringtable)
        self.register_on_netmsg(svc_SendTable, self._send_table)
        self.register_on_netmsg(svc_UpdateStringTable, self._update_stringtable)
        self.register_on_netmsg(svc_ClassInfo, self._handle_classinfo)
        self.register_on_netmsg(net_Tick, self._handle_tick)

    def open(self, filename):
        '''
        Opens the demo file.
        '''
        self.demofile = DemoFile()
        return self.demofile.open(filename)


    def register_on_netmsg(self, msg, callback):
        '''
        Will register a callback to call when the given netmessage is received.
        Will throw an exception if the netmessage doesn't exist. For all netmessages see: netmessages_public.proto SVC_Messages
        '''
        if msg not in self.NET_MSG:
            raise "Net message not found"
        self.NET_MSG[msg].append(callback)

    def register_on_gameevent(self, msg, callback):
        '''
        Will register a callback to call when the given game event is called.
        Can give ID or name, SHOULD USE NAME, BECAUSE IDS CHANGE (?)
        Game events can be found in data/game_events.txt
        '''
        if msg not in self.GAME_EVENTS:
            self.GAME_EVENTS[msg] = []
        self.GAME_EVENTS[msg].append(callback)

    def register_on_usermessage(self, msg, callback):
        '''
        Not yet implemented.
        '''
        if not msg in self.USER_MESSAGES:
            self.USER_MESSAGES[msg] = []
        self.USER_MESSAGES[msg].append(callback)

    def dump(self):
        '''
        Will start analyzing the demo and executing the necessary game events
        '''
        finished = False
        while not finished:
            cmd, tick, playerslot = self.demofile.read_cmd_header()
            # print "%i - %i - % i " % (cmd, tick, playerslot)
            if cmd == DemoMessage.SYNCTICK:
                continue
            elif cmd == DemoMessage.STOP:
                finished = True
                break
            elif cmd == DemoMessage.CONSOLECMD:
                self.demofile.read_raw_data()
            elif cmd == DemoMessage.DATATABLES:
                self.demofile.read_raw_data()
            elif cmd == DemoMessage.STRINGTABLES:
                self.demofile.read_raw_data()
            elif cmd == DemoMessage.USERCMD:
                self.demofile.read_user_cmd()
            elif cmd == DemoMessage.SIGNON or cmd == DemoMessage.PACKET:
                self._handle_demo_packet()

    def _handle_usermessage(self, cmd, data):
        umsg = CSVCMsg_UserMessage()
        umsg.ParseFromString(data)
        if umsg.msg_type not in ECstrike15UserMessages.DESCRIPTOR.values_by_number:
            return # TODO: Find out what to do with this
        name = ECstrike15UserMessages.Name(umsg.msg_type)
        callback_name = name.replace("CS_UM_", "")
        if callback_name in self.USER_MESSAGES:
            name = name.replace("CS_UM_", "CCSUsrMsg_")
            item = eval(name)()
            item.ParseFromString(umsg.msg_data)
            for callback in self.USER_MESSAGES[callback_name]:
                callback(item)

    def _handle_tick(self, cmd, data):
        tickinfo = CNETMsg_Tick()
        tickinfo.ParseFromString(data)
        self.current_tick = tickinfo.tick

    def _server_info_update(self, cmd, data):
        info = CSVCMsg_ServerInfo()
        info.ParseFromString(data)
        self.server_info = info

    def _handle_gameeventlist(self, cmd, data):
        '''
        Parses the list of given game events by the server
        '''
        gameeventlist = CSVCMsg_GameEventList()
        gameeventlist.ParseFromString(data)
        for desc in gameeventlist.descriptors:
            self.descriptors[desc.eventid] = (desc.eventid, desc.name, desc.keys, [])
            for key in desc.keys:
                self.descriptors[desc.eventid][3].append([key.type, key.name])

    def _handle_gameevent(self, cmd, data):
        '''
        handles the game events and fires the callback
        '''
        gameevent = CSVCMsg_GameEvent()
        gameevent.ParseFromString(data)
        name = self.descriptors[gameevent.eventid][1]
        if gameevent.eventid in self.GAME_EVENTS :
            event = GameEvent(gameevent, self.descriptors[gameevent.eventid], name)
            for callback in self.GAME_EVENTS[event.raw.eventid]:
                callback(event)


        if name in self.GAME_EVENTS:
            event = GameEvent(gameevent, self.descriptors[gameevent.eventid], name)
            for callback in self.GAME_EVENTS[name]:
                callback(event)

    stringtable_data = {}
    def _server_create_stringtable(self, cmd, data):
        '''
        Creates a string table from the given data.
        TO BE IMPLEMENTED
        '''
        table = CSVCMsg_CreateStringTable()
        # table_data = CSVCMsg_SendTable()
        table.ParseFromString(data)
        if table.name != "userinfo":
            return
        # table_data.ParseFromString(table.string_data)
        self.stringtable_data[table.name] = {'entries': table.num_entries,
                                             'user_data_fixed_size': table.user_data_fixed_size,
                                             'user_data_size': table.user_data_size,
                                             'user_data_size_bits': table.user_data_size_bits,
                                             'flags': table.flags,
                                             # 'data': table_data
                                             }
        '''
                int *pStringIndex = (int *)fieldInfo.pField;
        int nLen = pRestore->ReadInt();
        char *pTemp = (char *)stackalloc( nLen );
        pRestore->ReadString( pTemp, nLen, nLen );
        *pStringIndex = m_pStringTable->AddString( CBaseEntity::IsServer(), pTemp );
        '''

    def _update_stringtable(self, cmd, data):
        '''
        Updates a stringtable with the given data
        TO BE IMPLEMENTED
        '''
        update = CSVCMsg_UpdateStringTable()
        update.ParseFromString(data)

    def _send_table(self, cmd, data):
        table = CSVCMsg_SendTable()
        table.ParseFromString(data)
        print "%s: is end: %r, needs_decoder: %r" % (table.net_table_name, table.is_end, table.needs_decoder)
        for prop in table.props:
            print "Name: %s type: %i" % (prop.var_name, prop.type)
        print "-------------------------------"

    def _handle_classinfo(self, cmd, data):
        info = CSVCMsg_ClassInfo()
        info.ParseFromString(data)
        #print "CLASS INFO COUNT: %s, CREATE ON CLIENT: %r" % (len(info.classes), info.create_on_client)
        #for c in info.classes:
        #    print "%i: %s, %s" % (c.class_id, c.data_table_name, c.class_name)

    def _handle_demo_packet(self):
        info = self.demofile.read_cmd_info()
        self.demofile.read_sequence_info()  # ignore result
        length, buf = self.demofile.read_raw_data()

        if length > 0:
            self._dump_packet(buf, length)


    def _dump_packet(self, buf, length):
        index = 0
        while index < length:
            cmd, index = self.__read_int32(buf, index)
            size, index = self.__read_int32(buf, index)
            data = buf[index:index + size]
            if cmd in self.NET_MSG:
                for callback in self.NET_MSG[cmd]:

                    callback(cmd, data);

            index = index + size

    def __read_int32(self, buf, index):
        '''
        Reads an int32 from a binary buffer.
        '''
        b = 0
        count = 0
        result = 0

        cont = True
        while cont:
            if count == 5:
                return result
            b = struct.unpack_from("B", buf, index)
            b = b[0]
            index = index + 1
            result |= (b & 0x7F) << (7 * count)
            count = count + 1
            cont = b & 0x80
        return result, index