2015-06-22 19:23:38 +00:00
import configparser
2015-10-12 17:33:34 +00:00
import math
2017-08-18 13:11:35 +00:00
import glob
import os . path
import pickle
2016-07-23 09:39:00 +00:00
import pprint
2017-02-09 09:30:51 +00:00
import struct
2015-06-08 19:22:58 +00:00
import sqlite3
2015-11-19 20:25:16 +00:00
import sys
2015-06-08 19:22:58 +00:00
import tkinter . filedialog as filedialog
2015-11-19 20:25:16 +00:00
import tkinter . messagebox as messagebox
2015-06-08 19:22:58 +00:00
import zipfile
2016-07-23 09:39:29 +00:00
import zlib
2015-06-08 19:22:58 +00:00
from collections import OrderedDict
2015-08-09 11:05:21 +00:00
from tkinter import BooleanVar , END , Menu
2015-06-08 19:22:58 +00:00
2015-10-22 16:30:15 +00:00
import amf3
import viewer
2016-07-23 09:39:29 +00:00
import ldf
2017-08-12 11:06:59 +00:00
from structparser import StructParser
2017-12-25 12:43:33 +00:00
from pyraknet . bitstream import c_bit , c_bool , c_float , c_int , c_int64 , c_ubyte , c_uint , c_uint64 , c_ushort , ReadStream
2016-07-23 09:39:29 +00:00
2015-06-08 19:22:58 +00:00
component_name = OrderedDict ( )
2015-12-15 17:46:30 +00:00
component_name [ 108 ] = " Component 108 " ,
component_name [ 61 ] = " ModuleAssembly " ,
component_name [ 1 ] = " ControllablePhysics " ,
component_name [ 3 ] = " SimplePhysics " ,
component_name [ 20 ] = " RigidBodyPhantomPhysics " ,
component_name [ 30 ] = " VehiclePhysics 30 " ,
component_name [ 40 ] = " PhantomPhysics " ,
component_name [ 7 ] = " Destructible " , " Stats "
component_name [ 23 ] = " Stats " , " Collectible "
component_name [ 26 ] = " Pet " ,
component_name [ 4 ] = " Character " ,
component_name [ 17 ] = " Inventory " ,
component_name [ 5 ] = " Script " ,
component_name [ 9 ] = " Skill " ,
2016-10-22 12:02:58 +00:00
component_name [ 11 ] = " Item " ,
2015-12-15 17:46:30 +00:00
component_name [ 60 ] = " BaseCombatAI " ,
component_name [ 48 ] = " Stats " , " Rebuild "
2016-06-21 19:19:50 +00:00
component_name [ 25 ] = " MovingPlatform " ,
2015-12-15 17:46:30 +00:00
component_name [ 49 ] = " Switch " ,
component_name [ 16 ] = " Vendor " ,
component_name [ 6 ] = " Bouncer " ,
component_name [ 39 ] = " ScriptedActivity " ,
component_name [ 71 ] = " RacingControl " ,
2016-10-22 12:02:58 +00:00
component_name [ 75 ] = " Exhibit " ,
2017-06-10 10:29:37 +00:00
component_name [ 42 ] = " Model " ,
2015-12-15 17:46:30 +00:00
component_name [ 2 ] = " Render " ,
component_name [ 107 ] = " Component 107 " ,
2016-10-22 12:04:59 +00:00
component_name [ 69 ] = " Trigger " ,
2015-10-12 17:33:34 +00:00
component_name [ 12 ] = None
2016-06-21 19:19:50 +00:00
component_name [ 27 ] = None
2015-06-08 19:22:58 +00:00
component_name [ 31 ] = None
component_name [ 35 ] = None
2015-10-12 17:33:34 +00:00
component_name [ 36 ] = None
component_name [ 45 ] = None
component_name [ 55 ] = None
2015-06-08 19:22:58 +00:00
component_name [ 56 ] = None
2016-10-22 12:02:58 +00:00
component_name [ 57 ] = None
2015-06-08 19:22:58 +00:00
component_name [ 64 ] = None
2015-10-12 17:33:34 +00:00
component_name [ 65 ] = None
component_name [ 68 ] = None
2015-06-08 19:22:58 +00:00
component_name [ 73 ] = None
2017-06-10 10:29:37 +00:00
component_name [ 74 ] = None
component_name [ 95 ] = None
2015-12-15 17:46:30 +00:00
component_name [ 104 ] = None
2015-10-12 17:33:34 +00:00
component_name [ 113 ] = None
2015-07-31 20:16:48 +00:00
component_name [ 114 ] = None
2015-06-08 19:22:58 +00:00
comp_ids = list ( component_name . keys ( ) )
2015-06-14 10:16:57 +00:00
class ParserOutput :
def __init__ ( self ) :
self . text = " "
2015-08-10 10:09:54 +00:00
self . tags = [ ]
2015-06-14 10:16:57 +00:00
def __enter__ ( self ) :
pass
2015-08-10 10:09:54 +00:00
def __exit__ ( self , exc_type , exc_value , tb ) :
2015-06-14 10:16:57 +00:00
if exc_type is not None :
if exc_type == AssertionError :
exc_name = " ASSERTION FAILED "
2015-08-10 10:09:54 +00:00
self . tags . append ( " assertfail " )
2015-06-14 10:16:57 +00:00
elif exc_type == IndexError :
exc_name = " READ ERROR "
2015-08-10 10:09:54 +00:00
self . tags . append ( " readerror " )
else :
exc_name = " ERROR "
self . tags . append ( " error " )
import traceback
traceback . print_tb ( tb )
2016-07-23 09:39:29 +00:00
self . text = exc_name + " " + str ( exc_type . __name__ ) + " : " + str ( exc_value ) + " \n " + self . text
2015-06-14 10:16:57 +00:00
return True
def append ( self , structs ) :
for level , description , value , unexpected in structs :
if unexpected :
self . text + = " UNEXPECTED: "
2015-08-10 10:09:54 +00:00
self . tags . append ( " unexpected " )
2015-06-14 10:16:57 +00:00
self . text + = " \t " * level + description + " : " + str ( value ) + " \n "
2015-06-08 19:22:58 +00:00
class CaptureObject :
2015-06-14 10:16:57 +00:00
def __init__ ( self , network_id = None , object_id = None , lot = None ) :
2015-06-08 19:22:58 +00:00
self . network_id = network_id
self . object_id = object_id
2015-06-14 10:16:57 +00:00
self . lot = lot
2015-06-08 19:22:58 +00:00
self . entry = None
2015-08-09 11:05:21 +00:00
class CaptureViewer ( viewer . Viewer ) :
2015-06-22 19:23:38 +00:00
def __init__ ( self ) :
super ( ) . __init__ ( )
config = configparser . ConfigParser ( )
2015-08-09 11:05:21 +00:00
config . read ( " captureviewer.ini " )
2015-11-19 20:25:16 +00:00
try :
self . db = sqlite3 . connect ( config [ " paths " ] [ " db_path " ] )
except :
messagebox . showerror ( " Can not open database " , " Make sure db_path in the INI is set correctly. " )
sys . exit ( )
2017-08-12 11:06:59 +00:00
self . create_parsers ( )
2017-08-18 13:11:35 +00:00
with open ( " packetdefinitions/gm " , " rb " ) as file :
self . gamemsgs = pickle . loads ( zlib . decompress ( file . read ( ) ) )
2015-06-08 19:22:58 +00:00
self . objects = [ ]
self . lot_data = { }
2015-11-19 20:25:16 +00:00
self . parse_creations = BooleanVar ( value = config [ " parse " ] [ " creations " ] )
self . parse_serializations = BooleanVar ( value = config [ " parse " ] [ " serializations " ] )
2017-02-09 09:30:51 +00:00
self . parse_game_messages = BooleanVar ( value = config [ " parse " ] [ " game_messages " ] )
2015-11-19 20:25:16 +00:00
self . parse_normal_packets = BooleanVar ( value = config [ " parse " ] [ " normal_packets " ] )
2016-08-30 08:32:09 +00:00
self . retry_with_script_component = BooleanVar ( value = config [ " parse " ] [ " retry_with_script_component " ] )
2016-10-22 12:04:59 +00:00
self . retry_with_trigger_component = BooleanVar ( value = config [ " parse " ] [ " retry_with_trigger_component " ] )
2017-04-07 20:21:49 +00:00
self . retry_with_phantom_component = BooleanVar ( value = config [ " parse " ] [ " retry_with_phantom_component " ] )
2015-06-08 19:22:58 +00:00
self . create_widgets ( )
2017-08-12 11:06:59 +00:00
def create_parsers ( self ) :
type_handlers = { }
type_handlers [ " object_id " ] = self . object_id_handler
type_handlers [ " lot " ] = self . lot_handler
type_handlers [ " compressed_ldf " ] = self . compressed_ldf_handler
with open ( __file__ + " /../packetdefinitions/replica/creation_header.structs " , encoding = " utf-8 " ) as file :
self . creation_header_parser = StructParser ( file . read ( ) , type_handlers )
with open ( __file__ + " /../packetdefinitions/replica/serialization_header.structs " , encoding = " utf-8 " ) as file :
self . serialization_header_parser = StructParser ( file . read ( ) , type_handlers )
self . comp_parser = { }
for comp_id , indices in component_name . items ( ) :
if indices is not None :
self . comp_parser [ comp_id ] = [ ]
for index in indices :
with open ( __file__ + " /../packetdefinitions/replica/components/ " + index + " .structs " ) as file :
self . comp_parser [ comp_id ] . append ( StructParser ( file . read ( ) , type_handlers ) )
self . norm_parser = { }
2017-08-18 13:11:35 +00:00
for path in glob . glob ( __file__ + " /../packetdefinitions/*.structs " ) :
2017-12-25 12:25:53 +00:00
with open ( path , encoding = " utf-8 " ) as file :
2017-08-18 13:11:35 +00:00
self . norm_parser [ os . path . splitext ( os . path . basename ( path ) ) ] = StructParser ( file . read ( ) , type_handlers )
2017-08-12 11:06:59 +00:00
2015-06-08 19:22:58 +00:00
def create_widgets ( self ) :
2015-08-09 11:05:21 +00:00
super ( ) . create_widgets ( )
2015-06-08 19:22:58 +00:00
menubar = Menu ( )
menubar . add_command ( label = " Open " , command = self . askopenfiles )
parse_menu = Menu ( menubar )
parse_menu . add_checkbutton ( label = " Parse Creations " , variable = self . parse_creations )
parse_menu . add_checkbutton ( label = " Parse Serializations " , variable = self . parse_serializations )
2017-02-09 09:30:51 +00:00
parse_menu . add_checkbutton ( label = " Parse Game Messages " , variable = self . parse_game_messages )
2015-06-14 10:16:57 +00:00
parse_menu . add_checkbutton ( label = " Parse Normal Packets " , variable = self . parse_normal_packets )
2016-08-30 08:32:09 +00:00
parse_menu . add_checkbutton ( label = " Retry parsing with script component if failed " , variable = self . retry_with_script_component )
2016-10-22 12:04:59 +00:00
parse_menu . add_checkbutton ( label = " Retry parsing with trigger component if failed " , variable = self . retry_with_trigger_component )
2017-04-07 20:21:49 +00:00
parse_menu . add_checkbutton ( label = " Retry parsing with phantom component if failed " , variable = self . retry_with_phantom_component )
2015-06-08 19:22:58 +00:00
menubar . add_cascade ( label = " Parse " , menu = parse_menu )
self . master . config ( menu = menubar )
2015-08-10 10:09:54 +00:00
columns = " id " ,
2015-08-09 11:05:21 +00:00
self . tree . configure ( columns = columns )
2015-06-08 19:22:58 +00:00
for col in columns :
self . tree . heading ( col , text = col , command = ( lambda col : lambda : self . sort_column ( col , False ) ) ( col ) )
2015-06-14 10:16:57 +00:00
self . tree . tag_configure ( " unexpected " , foreground = " medium blue " )
self . tree . tag_configure ( " assertfail " , foreground = " orange " )
self . tree . tag_configure ( " readerror " , background = " medium purple " )
self . tree . tag_configure ( " error " , foreground = " red " )
2015-06-08 19:22:58 +00:00
def askopenfiles ( self ) :
2015-08-09 11:05:21 +00:00
paths = filedialog . askopenfilenames ( filetypes = [ ( " Zip " , " *.zip " ) ] )
if paths :
self . load_captures ( paths )
2015-06-08 19:22:58 +00:00
def load_captures ( self , captures ) :
self . tree . set_children ( " " )
2015-12-15 17:46:30 +00:00
self . detached_items . clear ( )
2015-06-08 19:22:58 +00:00
self . objects = [ ]
print ( " Loading captures, this might take a while " )
2015-12-15 17:46:30 +00:00
for i , capture in enumerate ( captures ) :
print ( " Loading " , capture , " [ %i / %i ] " % ( i + 1 , len ( captures ) ) )
2015-06-08 19:22:58 +00:00
with zipfile . ZipFile ( capture ) as capture :
files = [ i for i in capture . namelist ( ) if " of " not in i ]
if self . parse_creations . get ( ) :
print ( " Parsing creations " )
creations = [ i for i in files if " [24] " in i ]
for packet_name in creations :
2018-01-12 22:41:25 +00:00
packet = ReadStream ( capture . read ( packet_name ) , unlocked = True )
2015-06-14 10:16:57 +00:00
self . parse_creation ( packet_name , packet )
2015-06-08 19:22:58 +00:00
if self . parse_serializations . get ( ) :
print ( " Parsing serializations " )
serializations = [ i for i in files if " [27] " in i ]
for packet_name in serializations :
2017-12-25 12:43:33 +00:00
packet = ReadStream ( capture . read ( packet_name ) [ 1 : ] )
2015-06-14 10:16:57 +00:00
self . parse_serialization_packet ( packet_name , packet )
2015-06-08 19:22:58 +00:00
if self . parse_game_messages . get ( ) :
print ( " Parsing game messages " )
2015-06-14 10:16:57 +00:00
game_messages = [ i for i in files if " [53-05-00-0c] " in i or " [53-04-00-05] " in i ]
2015-06-08 19:22:58 +00:00
for packet_name in game_messages :
2017-12-25 12:43:33 +00:00
packet = ReadStream ( capture . read ( packet_name ) [ 8 : ] )
2015-06-08 19:22:58 +00:00
self . parse_game_message ( packet_name , packet )
2015-06-14 10:16:57 +00:00
if self . parse_normal_packets . get ( ) :
print ( " Parsing normal packets " )
packets = [ i for i in files if " [24] " not in i and " [27] " not in i and " [53-05-00-0c] " not in i and " [53-04-00-05] " not in i ]
for packet_name in packets :
2017-12-25 12:43:33 +00:00
packet = ReadStream ( capture . read ( packet_name ) )
2015-06-14 10:16:57 +00:00
self . parse_normal_packet ( packet_name , packet )
2017-08-12 11:06:59 +00:00
def object_id_handler ( self , stream ) :
object_id = stream . read ( c_int64 )
for obj in self . objects :
if object_id == obj . object_id :
return str ( object_id ) + " < " + self . tree . item ( obj . entry , " values " ) [ 0 ] + " > "
return str ( object_id )
def lot_handler ( self , stream ) :
lot = stream . read ( c_int )
if lot not in self . lot_data :
try :
lot_name = self . db . execute ( " select name from Objects where id == " + str ( lot ) ) . fetchone ( ) [ 0 ]
except TypeError :
print ( " Name for lot " , lot , " not found " )
lot_name = str ( lot )
else :
lot_name = self . lot_data [ lot ] [ 0 ]
return " %s - %s " % ( lot , lot_name )
def compressed_ldf_handler ( self , stream ) :
size = stream . read ( c_uint )
is_compressed = stream . read ( c_bool )
if is_compressed :
uncompressed_size = stream . read ( c_uint )
uncompressed = zlib . decompress ( stream . read ( bytes , length_type = c_uint ) )
assert len ( uncompressed ) == uncompressed_size
else :
uncompressed = stream . read ( bytes , length = size )
2017-12-25 12:43:33 +00:00
return ldf . from_ldf ( ReadStream ( uncompressed ) )
2017-08-12 11:06:59 +00:00
2016-10-22 12:04:59 +00:00
def parse_creation ( self , packet_name , packet , retry_with_components = [ ] ) :
2015-06-08 19:22:58 +00:00
packet . skip_read ( 1 )
has_network_id = packet . read ( c_bit )
assert has_network_id
network_id = packet . read ( c_ushort )
object_id = packet . read ( c_int64 )
for obj in self . objects :
if obj . object_id == object_id : # We've already parsed this object (can happen due to ghosting)
return
2015-06-14 10:16:57 +00:00
lot = packet . read ( c_int )
if lot not in self . lot_data :
try :
2015-08-09 11:05:21 +00:00
lot_name = self . db . execute ( " select name from Objects where id == " + str ( lot ) ) . fetchone ( ) [ 0 ]
2015-06-14 10:16:57 +00:00
except TypeError :
print ( " Name for lot " , lot , " not found " )
lot_name = str ( lot )
2015-08-09 11:05:21 +00:00
component_types = [ i [ 0 ] for i in self . db . execute ( " select component_type from ComponentsRegistry where id == " + str ( lot ) ) . fetchall ( ) ]
2016-10-22 12:04:59 +00:00
component_types . extend ( retry_with_components )
2017-04-07 20:21:49 +00:00
if 40 in retry_with_components :
if 3 in component_types :
component_types . remove ( 3 )
2016-10-22 12:04:59 +00:00
2015-12-15 17:46:30 +00:00
parsers = OrderedDict ( )
2015-06-14 10:16:57 +00:00
try :
component_types . sort ( key = comp_ids . index )
for comp_type in component_types :
if component_name [ comp_type ] is not None :
2017-08-12 11:06:59 +00:00
for name , parser in zip ( component_name [ comp_type ] , self . comp_parser [ comp_type ] ) :
2015-12-15 17:46:30 +00:00
if name not in parsers :
parsers [ name ] = parser
2015-06-14 10:16:57 +00:00
except ValueError as e :
error = " ERROR: Unknown component " + str ( e . args [ 0 ] . split ( ) [ 0 ] ) + " " + str ( component_types )
else :
error = None
self . lot_data [ lot ] = lot_name , parsers , error
else :
lot_name , parsers , error = self . lot_data [ lot ]
2015-06-08 19:22:58 +00:00
id_ = packet . read ( str , length_type = c_ubyte ) + " " + lot_name
2017-12-25 12:43:33 +00:00
packet . read_offset = 0
2015-06-14 10:16:57 +00:00
parser_output = ParserOutput ( )
with parser_output :
2017-08-12 11:06:59 +00:00
parser_output . append ( self . creation_header_parser . parse ( packet ) )
2015-06-14 10:16:57 +00:00
if error is not None :
parser_output . text = error + " \n " + parser_output . text
2015-08-10 10:09:54 +00:00
parser_output . tags . append ( " error " )
2015-06-08 19:22:58 +00:00
else :
2016-08-30 08:32:09 +00:00
try :
self . parse_serialization ( packet , parser_output , parsers , is_creation = True )
2017-02-09 09:30:51 +00:00
except ( AssertionError , IndexError , struct . error ) :
2016-10-22 12:04:59 +00:00
if retry_with_components :
print ( " retry was not able to resolve parsing error " )
raise
retry_with_components = [ ]
if self . retry_with_script_component . get ( ) :
retry_with_components . append ( 5 )
elif self . retry_with_trigger_component . get ( ) :
retry_with_components . append ( 69 )
2017-04-07 20:21:49 +00:00
elif self . retry_with_phantom_component . get ( ) :
retry_with_components . append ( 40 )
2016-10-22 12:04:59 +00:00
if retry_with_components :
print ( " retrying with " , retry_with_components , packet_name )
2016-08-30 08:32:09 +00:00
del self . lot_data [ lot ]
2017-12-25 12:43:33 +00:00
packet . read_offset = 0
2016-10-22 12:04:59 +00:00
self . parse_creation ( packet_name , packet , retry_with_components )
2016-08-30 08:32:09 +00:00
return
2015-06-08 19:22:58 +00:00
2015-06-14 10:16:57 +00:00
obj = CaptureObject ( network_id = network_id , object_id = object_id , lot = lot )
self . objects . append ( obj )
2016-07-23 09:39:29 +00:00
obj . entry = self . tree . insert ( " " , END , text = packet_name , values = ( id_ , parser_output . text . replace ( " { " , " <crlbrktopen> " ) . replace ( " } " , " <crlbrktclose> " ) . replace ( " \\ " , " <backslash> " ) ) , tags = parser_output . tags )
2015-06-14 10:16:57 +00:00
2017-08-12 11:06:59 +00:00
def parse_serialization ( self , packet , parser_output , parsers , is_creation = False ) :
parser_output . append ( self . serialization_header_parser . parse ( packet ) )
2015-12-15 17:46:30 +00:00
for name , parser in parsers . items ( ) :
2015-06-14 10:16:57 +00:00
parser_output . text + = " \n " + name + " \n \n "
parser_output . append ( parser . parse ( packet , { " creation " : is_creation } ) )
if not packet . all_read ( ) :
2018-01-12 22:41:25 +00:00
raise IndexError ( " Not completely read, %i bytes unread " % len ( packet . read_remaining ( ) ) )
2015-06-14 10:16:57 +00:00
def parse_serialization_packet ( self , packet_name , packet ) :
2015-06-08 19:22:58 +00:00
network_id = packet . read ( c_ushort )
obj = None
2015-12-15 17:46:30 +00:00
for i in self . objects :
if i . network_id == network_id :
obj = i
2015-06-08 19:22:58 +00:00
break
if obj is None :
obj = CaptureObject ( network_id = network_id )
self . objects . append ( obj )
2015-08-09 11:05:21 +00:00
obj . entry = self . tree . insert ( " " , END , text = " Unknown " , values = ( " network_id= " + str ( network_id ) , " " ) )
2015-06-08 19:22:58 +00:00
2015-06-14 10:16:57 +00:00
if obj . lot is None :
2015-12-15 17:46:30 +00:00
parsers = { }
2015-06-14 10:16:57 +00:00
error = " Unknown object "
else :
_ , parsers , error = self . lot_data [ obj . lot ]
parser_output = ParserOutput ( )
with parser_output :
self . parse_serialization ( packet , parser_output , parsers )
if error is not None :
2015-08-10 10:09:54 +00:00
parser_output . tags . append ( " error " )
2015-06-14 10:16:57 +00:00
else :
error = " "
2016-07-23 09:39:29 +00:00
self . tree . insert ( obj . entry , END , text = packet_name , values = ( error , parser_output . text . replace ( " { " , " <crlbrktopen> " ) . replace ( " } " , " <crlbrktclose> " ) . replace ( " \\ " , " <backslash> " ) ) , tags = parser_output . tags )
2015-06-08 19:22:58 +00:00
def parse_game_message ( self , packet_name , packet ) :
object_id = packet . read ( c_int64 )
for i in self . objects :
if i . object_id == object_id :
entry = i . entry
break
else :
obj = CaptureObject ( object_id = object_id )
self . objects . append ( obj )
2015-08-09 11:05:21 +00:00
obj . entry = entry = self . tree . insert ( " " , END , text = " Unknown " , values = ( " object_id= " + str ( object_id ) , " " ) )
2015-06-08 19:22:58 +00:00
msg_id = packet . read ( c_ushort )
2017-02-09 09:30:51 +00:00
tags = [ ]
2015-06-08 19:22:58 +00:00
try :
2017-08-18 13:11:35 +00:00
message = self . gamemsgs [ " messages " ] [ msg_id ]
msg_name = message [ " name " ]
network = message [ " network " ]
param_values = OrderedDict ( )
if network is None or ( ( ( " [53-05-00-0c] " in packet_name and " client " not in network ) or ( " [53-04-00-05] " in packet_name and " server " not in network ) ) and network != " dup " ) :
2015-06-08 19:22:58 +00:00
raise ValueError
2017-08-18 13:11:35 +00:00
params = message [ " params " ]
if " custom " in message :
2015-06-08 19:22:58 +00:00
# Custom serializations
if msg_name == " NotifyMissionTask " :
2017-08-18 13:11:35 +00:00
param_values [ " missionID " ] = packet . read ( c_int )
param_values [ " taskMask " ] = packet . read ( c_int )
2015-06-08 19:22:58 +00:00
updates = [ ]
for _ in range ( packet . read ( c_ubyte ) ) :
updates . append ( packet . read ( c_float ) )
2017-02-09 09:30:51 +00:00
if len ( updates ) != 1 :
tags . append ( " unexpected " )
2017-08-18 13:11:35 +00:00
param_values [ " updates " ] = updates
2015-08-09 11:05:21 +00:00
elif msg_name == " VendorStatusUpdate " :
2017-08-18 13:11:35 +00:00
param_values [ " bUpdateOnly " ] = packet . read ( c_bit )
2015-08-09 11:05:21 +00:00
inv = { }
for _ in range ( packet . read ( c_uint ) ) :
inv [ packet . read ( c_int ) ] = packet . read ( c_int )
2017-08-18 13:11:35 +00:00
param_values [ " inventoryList " ] = inv
2015-06-08 19:22:58 +00:00
elif msg_name == " RequestLinkedMission " :
2017-08-18 13:11:35 +00:00
param_values [ " playerID " ] = packet . read ( c_int64 )
param_values [ " missionID " ] = packet . read ( c_int )
param_values [ " bMissionOffered " ] = packet . read ( c_bit )
2015-10-12 17:33:34 +00:00
elif msg_name == " FetchModelMetadataResponse " :
2017-08-18 13:11:35 +00:00
param_values [ " ugID " ] = packet . read ( c_int64 )
param_values [ " objectID " ] = packet . read ( c_int64 )
param_values [ " requestorID " ] = packet . read ( c_int64 )
param_values [ " context " ] = packet . read ( c_int )
param_values [ " bHasUGData " ] = packet . read ( c_bit )
param_values [ " bHasBPData " ] = packet . read ( c_bit )
if param_values [ " bHasUGData " ] :
param_values [ " UGM_unknown1 " ] = packet . read ( c_int64 )
param_values [ " UGM_unknown2 " ] = packet . read ( c_int64 )
param_values [ " UGM_unknown_str_1 " ] = packet . read ( str , length_type = c_uint )
param_values [ " UGM_unknown_str_2 " ] = packet . read ( str , length_type = c_uint )
param_values [ " UGM_unknown3 " ] = packet . read ( c_int64 )
param_values [ " UGM_unknown4 " ] = packet . read ( c_int64 )
param_values [ " UGM_unknown_str_3 " ] = packet . read ( str , length_type = c_uint )
2015-10-12 17:33:34 +00:00
unknown_list = [ ]
for _ in range ( packet . read ( c_ubyte ) ) :
unknown_list . append ( packet . read ( c_int64 ) )
2017-08-18 13:11:35 +00:00
param_values [ " UGM_unknown_list " ] = unknown_list
if param_values [ " bHasBPData " ] :
param_values [ " BPM_unknown1 " ] = packet . read ( c_int64 )
param_values [ " BPM_some_timestamp " ] = packet . read ( c_uint64 )
param_values [ " BPM_unknown2 " ] = packet . read ( c_uint )
param_values [ " BPM_unknown3 " ] = packet . read ( c_float ) , packet . read ( c_float ) , packet . read ( c_float )
param_values [ " BPM_unknown4 " ] = packet . read ( c_float ) , packet . read ( c_float ) , packet . read ( c_float )
param_values [ " BPM_unknown_bool_1 " ] = packet . read ( c_bit )
param_values [ " BPM_unknown_bool_2 " ] = packet . read ( c_bit )
param_values [ " BPM_unknown_str_1 " ] = packet . read ( str , length_type = c_uint )
param_values [ " BPM_unknown_bool_3 " ] = packet . read ( c_bit )
param_values [ " BPM_unknown5 " ] = packet . read ( c_uint )
2015-10-12 17:33:34 +00:00
elif msg_name == " NotifyPetTamingPuzzleSelected " :
bricks = [ ]
for _ in range ( packet . read ( c_uint ) ) :
bricks . append ( ( packet . read ( c_uint ) , packet . read ( c_uint ) ) )
2017-08-18 13:11:35 +00:00
param_values [ " randBrickIDList " ] = bricks
2015-10-12 17:33:34 +00:00
elif msg_name == " DownloadPropertyData " :
2017-08-18 13:11:35 +00:00
param_values [ " object_id " ] = packet . read ( c_int64 )
param_values [ " component_id " ] = packet . read ( c_int )
param_values [ " mapID " ] = packet . read ( c_ushort )
param_values [ " vendorMapID " ] = packet . read ( c_ushort )
param_values [ " unknown1 " ] = packet . read ( c_uint )
param_values [ " property_name " ] = packet . read ( str , length_type = c_uint )
param_values [ " property_description " ] = packet . read ( str , length_type = c_uint )
param_values [ " owner_name " ] = packet . read ( str , length_type = c_uint )
param_values [ " owner_object_id " ] = packet . read ( c_int64 )
param_values [ " type " ] = packet . read ( c_uint )
param_values [ " sizecode " ] = packet . read ( c_uint )
param_values [ " minimumPrice " ] = packet . read ( c_uint )
param_values [ " rentDuration " ] = packet . read ( c_uint )
param_values [ " timestamp1 " ] = packet . read ( c_uint64 )
param_values [ " unknown2 " ] = packet . read ( c_uint )
param_values [ " unknown3 " ] = packet . read ( c_uint64 )
param_values [ " spawnName " ] = packet . read ( str , length_type = c_uint )
param_values [ " unknown_str_1 " ] = packet . read ( str , length_type = c_uint )
param_values [ " unknown_str_2 " ] = packet . read ( str , length_type = c_uint )
param_values [ " durationType " ] = packet . read ( c_uint )
param_values [ " unknown4 " ] = packet . read ( c_uint )
param_values [ " unknown5 " ] = packet . read ( c_uint )
param_values [ " unknown6 " ] = packet . read ( c_ubyte )
param_values [ " unknown7 " ] = packet . read ( c_uint64 )
param_values [ " unknown8 " ] = packet . read ( c_uint )
param_values [ " unknown_str_3 " ] = packet . read ( str , length_type = c_uint )
param_values [ " unknown9 " ] = packet . read ( c_uint64 )
param_values [ " unknown10 " ] = packet . read ( c_uint )
param_values [ " unknown11 " ] = packet . read ( c_uint )
param_values [ " zoneX " ] = packet . read ( c_float )
param_values [ " zoneY " ] = packet . read ( c_float )
param_values [ " zoneZ " ] = packet . read ( c_float )
param_values [ " maxBuildHeight " ] = packet . read ( c_float )
param_values [ " timestamp2 " ] = packet . read ( c_uint64 )
param_values [ " unknown12 " ] = packet . read ( c_ubyte )
2015-10-12 17:33:34 +00:00
path = [ ]
for _ in range ( packet . read ( c_uint ) ) :
path . append ( ( packet . read ( c_float ) , packet . read ( c_float ) , packet . read ( c_float ) ) )
2017-08-18 13:11:35 +00:00
param_values [ " path " ] = path
2016-07-23 09:39:00 +00:00
elif msg_name == " PropertySelectQuery " :
2017-08-18 13:11:35 +00:00
param_values [ " navOffset " ] = packet . read ( c_int )
param_values [ " bThereAreMore " ] = packet . read ( c_bit )
param_values [ " myCloneID " ] = packet . read ( c_int )
param_values [ " bHasFeaturedProperty " ] = packet . read ( c_bit )
param_values [ " bWasFriends " ] = packet . read ( c_bit )
2016-07-23 09:39:00 +00:00
properties = [ ]
2017-08-18 13:11:35 +00:00
param_values [ " properties " ] = properties
2016-07-23 09:39:00 +00:00
for _ in range ( packet . read ( c_uint ) ) :
property = OrderedDict ( )
property [ " cloneID " ] = packet . read ( c_int )
property [ " ownerName " ] = packet . read ( str , length_type = c_uint )
property [ " name " ] = packet . read ( str , length_type = c_uint )
property [ " description " ] = packet . read ( str , length_type = c_uint )
property [ " reputation " ] = packet . read ( c_uint )
property [ " isBff " ] = packet . read ( c_bit )
property [ " isFriend " ] = packet . read ( c_bit )
property [ " isModeratedApproved " ] = packet . read ( c_bit )
property [ " isAlt " ] = packet . read ( c_bit )
property [ " isOwned " ] = packet . read ( c_bit )
property [ " accessType " ] = packet . read ( c_uint )
property [ " dateLastPublished " ] = packet . read ( c_uint )
property [ " performanceCost " ] = packet . read ( c_uint64 )
properties . append ( property )
2017-06-10 10:29:37 +00:00
elif msg_name == " ClientTradeUpdate " :
2017-08-18 13:11:35 +00:00
param_values [ " currency " ] = packet . read ( c_uint64 )
2017-06-10 10:29:37 +00:00
items = [ ]
for _ in range ( packet . read ( c_uint ) ) :
item = { }
item [ " object_id " ] = packet . read ( c_int64 )
item_obj_id_again = packet . read ( c_int64 )
assert item [ " object_id " ] == item_obj_id_again
item [ " lot " ] = packet . read ( c_int )
if packet . read ( c_bit ) :
item [ " unknown1 " ] = packet . read ( c_int64 )
if packet . read ( c_bit ) :
item [ " unknown2 " ] = packet . read ( c_uint )
if packet . read ( c_bit ) :
item [ " slot " ] = packet . read ( c_ushort )
if packet . read ( c_bit ) :
item [ " unknown3 " ] = packet . read ( c_uint )
if packet . read ( c_bit ) :
2017-08-12 11:06:59 +00:00
item [ " extra_info " ] = self . compressed_ldf_handler ( packet )
2017-06-10 10:29:37 +00:00
item [ " unknown4 " ] = packet . read ( c_bit )
items . append ( item )
2017-08-18 13:11:35 +00:00
param_values [ " items " ] = items
2017-06-10 10:29:37 +00:00
elif msg_name == " ServerTradeUpdate " :
2017-08-18 13:11:35 +00:00
param_values [ " aboutToPerform " ] = packet . read ( c_bit )
param_values [ " currency " ] = packet . read ( c_uint64 )
2017-06-10 10:29:37 +00:00
items = [ ]
for _ in range ( packet . read ( c_uint ) ) :
item = { }
item [ " object_id " ] = packet . read ( c_int64 )
item_obj_id_again = packet . read ( c_int64 )
assert item [ " object_id " ] == item_obj_id_again
item [ " lot " ] = packet . read ( c_int )
if packet . read ( c_bit ) :
item [ " unknown1 " ] = packet . read ( c_int64 )
if packet . read ( c_bit ) :
item [ " amount " ] = packet . read ( c_uint )
if packet . read ( c_bit ) :
item [ " slot " ] = packet . read ( c_ushort )
if packet . read ( c_bit ) :
item [ " unknown2 " ] = packet . read ( c_uint )
if packet . read ( c_bit ) :
2017-08-12 11:06:59 +00:00
item [ " extra_info " ] = self . compressed_ldf_handler ( packet )
2017-06-10 10:29:37 +00:00
item [ " unknown3 " ] = packet . read ( c_bit )
items . append ( item )
2017-08-18 13:11:35 +00:00
param_values [ " items " ] = items
2017-06-10 10:29:37 +00:00
elif msg_name == " PropertyBuildModeUpdate " :
2017-08-18 13:11:35 +00:00
param_values [ " start " ] = packet . read ( c_bit )
param_values [ " friends " ] = { }
2017-06-10 10:29:37 +00:00
for _ in range ( packet . read ( c_uint ) ) :
2017-08-18 13:11:35 +00:00
param_values [ " friends " ] [ packet . read ( c_int64 ) ] = packet . read ( c_bit )
param_values [ " numSent " ] = packet . read ( c_int )
2017-06-10 10:29:37 +00:00
2015-07-31 20:16:48 +00:00
elif msg_name == " ModularBuildFinish " :
lots = [ ]
for _ in range ( packet . read ( c_ubyte ) ) :
lots . append ( packet . read ( c_int ) )
2017-08-18 13:11:35 +00:00
param_values [ " moduleTemplateIDs " ] = lots
2015-10-12 17:33:34 +00:00
elif msg_name == " PetTamingTryBuild " :
selections = [ ]
for _ in range ( packet . read ( c_uint ) ) :
selections . append ( ( packet . read ( c_uint ) , packet . read ( c_uint ) ) )
2017-08-18 13:11:35 +00:00
param_values [ " currentSelections " ] = selections
param_values [ " clientFailed " ] = packet . read ( c_bit )
2016-07-23 09:39:00 +00:00
elif msg_name == " GetModelsOnProperty " :
models = [ ]
for _ in range ( packet . read ( c_uint ) ) :
models . append ( ( packet . read ( c_int64 ) , packet . read ( c_int64 ) ) )
2017-08-18 13:11:35 +00:00
param_values [ " models " ] = models
2016-07-23 09:39:00 +00:00
elif msg_name == " MatchRequest " :
2017-08-18 13:11:35 +00:00
param_values [ " activator " ] = packet . read ( c_int64 )
2016-07-23 09:39:00 +00:00
choices = packet . read ( str , length_type = c_uint )
if choices :
assert packet . read ( c_ushort ) == 0 # for some reason has a null terminator
2017-08-18 13:11:35 +00:00
param_values [ " playerChoices " ] = choices
param_values [ " type " ] = packet . read ( c_int )
param_values [ " value " ] = packet . read ( c_int )
2016-07-23 09:39:00 +00:00
elif msg_name == " TeamCreateLocal " :
team_members = [ ]
for _ in range ( packet . read ( c_uint ) ) :
team_members . append ( ( packet . read ( c_int64 ) , packet . read ( c_bit ) ) )
2017-08-18 13:11:35 +00:00
param_values [ " team_members " ] = team_members
2015-06-08 19:22:58 +00:00
else :
raise NotImplementedError ( " Custom serialization " )
2017-08-18 13:11:35 +00:00
values = " \n " . join ( [ " %s = %s " % ( a , b ) for a , b in param_values . items ( ) ] )
2015-06-08 19:22:58 +00:00
else :
2017-08-18 13:11:35 +00:00
for param in params :
type_ = param [ " type " ]
2015-06-08 19:22:58 +00:00
if type_ == " bool " : # bools don't have default-flags
2017-08-18 13:11:35 +00:00
param_values [ param [ " name " ] ] = packet . read ( c_bit )
2015-06-08 19:22:58 +00:00
continue
2017-08-18 13:11:35 +00:00
if " default " in param :
2015-06-08 19:22:58 +00:00
is_not_default = packet . read ( c_bit )
if not is_not_default :
2017-08-18 13:11:35 +00:00
param_values [ param [ " name " ] ] = param [ " default " ]
2015-06-08 19:22:58 +00:00
continue
if type_ == " unsigned char " :
value = packet . read ( c_ubyte )
2017-08-18 13:11:35 +00:00
elif type_ == " mapid " :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_ushort )
elif type_ in ( " int " , " LOT " ) :
value = packet . read ( c_int )
2017-08-18 13:11:35 +00:00
elif type_ in ( " unsigned int " , " cloneid " , " TSkillID " ) :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_uint )
elif type_ == " __int64 " :
value = packet . read ( c_int64 )
2017-08-18 13:11:35 +00:00
elif type_ == " objectid " :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_int64 )
2015-06-14 10:16:57 +00:00
if value == object_id :
value = str ( value ) + " <self> "
else :
for obj in self . objects :
if value == obj . object_id :
value = str ( value ) + " < " + self . tree . item ( obj . entry , " values " ) [ 0 ] + " > "
break
2017-08-18 13:11:35 +00:00
elif type_ == " zoneid " :
2016-07-23 09:39:00 +00:00
value = packet . read ( c_ushort ) , packet . read ( c_ushort ) , packet . read ( c_uint )
2015-06-08 19:22:58 +00:00
elif type_ == " float " :
value = packet . read ( c_float )
2015-10-12 17:33:34 +00:00
elif type_ == " BinaryBuffer " :
2017-06-10 10:29:37 +00:00
value = packet . read ( bytes , length_type = c_uint )
2017-08-18 13:11:35 +00:00
elif type_ == " str " :
2017-06-10 10:29:37 +00:00
value = packet . read ( bytes , length_type = c_uint )
2017-08-18 13:11:35 +00:00
elif type_ == " wstr " :
2017-06-10 10:29:37 +00:00
value = packet . read ( str , length_type = c_uint )
2017-08-18 13:11:35 +00:00
elif type_ == " Vector3 " :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_float ) , packet . read ( c_float ) , packet . read ( c_float )
2017-08-18 13:11:35 +00:00
elif type_ == " Quaternion " :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_float ) , packet . read ( c_float ) , packet . read ( c_float ) , packet . read ( c_float )
2017-08-18 13:11:35 +00:00
elif type_ == " LDF " :
2015-06-08 19:22:58 +00:00
value = packet . read ( str , length_type = c_uint )
2015-08-09 11:05:21 +00:00
if value :
2015-06-08 19:22:58 +00:00
assert packet . read ( c_ushort ) == 0 # for some reason has a null terminator
2017-08-18 13:11:35 +00:00
elif type_ == " AMF3 " :
2015-10-22 16:30:15 +00:00
value = amf3 . read ( packet )
2017-08-18 13:11:35 +00:00
elif " enums " in message and type_ in message [ " enums " ] :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_uint )
2017-08-18 13:11:35 +00:00
value = message [ " enums " ] [ type_ ] [ value ] + " ( " + str ( value ) + " ) "
elif type_ in self . gamemsgs [ " enums " ] :
2015-06-08 19:22:58 +00:00
value = packet . read ( c_uint )
2017-08-18 13:11:35 +00:00
value = self . gamemsgs [ " enums " ] [ type_ ] [ value ] + " ( " + str ( value ) + " ) "
2015-06-08 19:22:58 +00:00
else :
2016-07-23 09:39:00 +00:00
raise NotImplementedError ( " Unknown type " , type_ )
2017-08-18 13:11:35 +00:00
param_values [ param [ " name " ] ] = value
2015-10-12 17:33:34 +00:00
if not packet . all_read ( ) :
raise ValueError
2015-06-08 19:22:58 +00:00
except NotImplementedError as e :
2017-08-18 13:11:35 +00:00
values = ( msg_name , str ( e ) + " \n len: " + str ( len ( packet ) - 10 ) + " \n " + " \n " . join ( [ " %s = %s " % ( a , b ) for a , b in param_values . items ( ) ] ) )
2017-02-09 09:30:51 +00:00
tags . append ( " error " )
2015-10-12 17:33:34 +00:00
except Exception as e :
2015-06-08 19:22:58 +00:00
print ( packet_name , msg_name )
import traceback
traceback . print_exc ( )
2017-08-18 13:11:35 +00:00
values = ( " likely not " + msg_name , " Error while parsing, likely not this message! \n " + str ( e ) + " \n len: " + str ( len ( packet ) - 10 ) + " \n " + " \n " . join ( [ " %s = %s " % ( a , b ) for a , b in param_values . items ( ) ] ) )
2017-02-09 09:30:51 +00:00
tags . append ( " error " )
2015-06-08 19:22:58 +00:00
else :
2017-08-18 13:11:35 +00:00
values = ( msg_name , " \n " . join ( [ " %s = %s " % ( a , pprint . pformat ( b ) ) for a , b in param_values . items ( ) ] ) )
2015-08-10 10:09:54 +00:00
self . tree . insert ( entry , END , text = packet_name , values = values , tags = tags )
2015-06-08 19:22:58 +00:00
2015-06-14 10:16:57 +00:00
def parse_normal_packet ( self , packet_name , packet ) :
id_ = packet_name [ packet_name . index ( " [ " ) + 1 : packet_name . index ( " ] " ) ]
2017-08-12 11:06:59 +00:00
if id_ not in self . norm_parser :
2015-08-10 10:09:54 +00:00
self . tree . insert ( " " , END , text = packet_name , values = ( id_ , " Add the struct definition file packetdefinitions/ " + id_ + " .structs to enable parsing of this packet. " ) , tags = [ " error " ] )
2015-06-14 10:16:57 +00:00
return
if id_ . startswith ( " 53 " ) :
packet . skip_read ( 8 )
else :
packet . skip_read ( 1 )
parser_output = ParserOutput ( )
2015-10-12 17:33:34 +00:00
with parser_output :
2017-08-12 11:06:59 +00:00
parser_output . append ( self . norm_parser [ id_ ] . parse ( packet ) )
2015-08-10 10:09:54 +00:00
self . tree . insert ( " " , END , text = packet_name , values = ( id_ , parser_output . text ) , tags = parser_output . tags )
2015-08-09 11:05:21 +00:00
2015-10-12 17:33:34 +00:00
def on_item_select ( self , _ ) :
2015-06-08 19:22:58 +00:00
item = self . tree . selection ( ) [ 0 ]
self . item_inspector . delete ( 1.0 , END )
self . item_inspector . insert ( END , self . tree . item ( item , " values " ) [ 1 ] )
2015-06-14 10:16:57 +00:00
if __name__ == " __main__ " :
2015-08-09 11:05:21 +00:00
app = CaptureViewer ( )
app . mainloop ( )