33import zlib
44import pprint
55import hashlib
6+ import collections
67from datetime import datetime
78import time
89from StringIO import StringIO
@@ -332,37 +333,17 @@ def load_players(self):
332333 return
333334 if 'replay.attributes.events' not in self .raw_data :
334335 return
336+ if 'replay.initData' not in self .raw_data :
337+ return
335338
336- # Create and add the players based on attribute and details information
337- player_index , obs_index , default_region = 0 , 0 , ''
338- player_data = self .raw_data ['replay.details' ].players
339- for pid , attributes in sorted (self .attributes .iteritems ()):
340-
341- # We've already processed the global attributes
342- if pid == 16 : continue
343-
344- # Open Slots are skipped because it doesn't seem useful to store
345- # an "Open" player to fill a spot that would otherwise be empty.
346- if attributes ['Player Type' ] == 'Open' : continue
347-
348- # Get the player data from the details file, increment the index to
349- # Keep track of which player we are processing
350- pdata = player_data [player_index ]
351- player_index += 1
352-
353- # If this is a human player, push back the initial observer index in
354- # the list of all human players we gathered from the initdata file.
355- if attributes ['Player Type' ] == 'Human' :
356- obs_index += 1
357-
358- # Create the player using the current pid and the player name from
359- # The details file. This works because players are stored in order
360- # of pid inside of the details file. Attributes and Details must be
361- # processed together because Details doesn't index players by or
362- # store their player ids; Attributes can provide that information
363- # and allow for accurate pid mapping even with computers, observers,
364- # and open open slots.
365- #
339+ # 1. pids are in lobby join order, use initData.player_names
340+ # 2. use the name to get the player_data index
341+ # 2a. if observer, save pid+name for later
342+ # 3. use the player_data index as the attrib_data index...?
343+ # 4. use the player_data and attribute_data to load the player
344+ # 5. after loop, load the computer players and (optionally) their attributes
345+ # 6. then load the observer pid,name using attributes if available
346+ def createPlayer (pid , pdata , attributes ):
366347 # General information re: each player comes from the following files
367348 # * replay.initData
368349 # * replay.details
@@ -373,7 +354,9 @@ def load_players(self):
373354 player = Player (pid ,pdata .name )
374355
375356 # Cross reference the player and team lookups
376- team_number = attributes ['Teams' + self .type ]
357+ # TODO: Players without attribute events, where do we get the team info?
358+ # print pdata.name, attributes, pdata
359+ team_number = attributes .get ('Teams' + self .type ,0 )
377360 if not team_number in self .team :
378361 self .team [team_number ] = Team (team_number )
379362 self .teams .append (self .team [team_number ])
@@ -387,20 +370,19 @@ def load_players(self):
387370 elif pdata .result == 2 :
388371 player .team .result = "Loss"
389372
390- player .pick_race = attributes [ 'Race' ]
373+ player .pick_race = attributes . get ( 'Race' , 'Unknown' )
391374 player .play_race = LOCALIZED_RACES .get (pdata .race , pdata .race )
392- player .difficulty = attributes [ 'Difficulty' ]
393- player .is_human = (attributes [ 'Player Type' ] == 'Human' )
375+ player .difficulty = attributes . get ( 'Difficulty' , 'Unknown' )
376+ player .is_human = (attributes . get ( 'Player Type' , 'Computer' ) == 'Human' )
394377 player .uid = pdata .bnet .uid
395378 player .subregion = pdata .bnet .subregion
396379 player .handicap = pdata .handicap
397380
398381 # We need initData for the gateway portion of the url!
399- if 'replay.initData' in self . raw_data and self .gateway :
382+ if self .gateway :
400383 player .gateway = self .gateway
401384 if player .is_human and player .subregion :
402385 player .region = REGIONS [self .gateway ].get (player .subregion , 'Unknown' )
403- default_region = player .region
404386
405387 # Conversion instructions to the new color object:
406388 # color_rgba is the color object itself
@@ -415,35 +397,58 @@ def load_players(self):
415397 self .player [pid ] = player
416398 self .person [pid ] = player
417399
400+ def createObserver (pid , name , attributes ):
401+ observer = Observer (pid ,name )
402+ self .observers .append (observer )
403+ self .people .append (observer )
404+ self .person [pid ] = observer
405+
406+ observer_data = list ()
407+ unassigned_player_data = collections .OrderedDict ((p .name , (idx ,p )) for idx , p in enumerate (self .raw_data ['replay.details' ].players ))
408+ try :
409+ for pid , name in enumerate (self .raw_data ['replay.initData' ].player_names ):
410+ if name in unassigned_player_data :
411+ idx , pdata = unassigned_player_data [name ]
412+ attributes = self .attributes .get (idx ,dict ())
413+ createPlayer (pid , pdata , attributes )
414+ del unassigned_player_data [name ]
415+ else :
416+ observer_data .append ((pid ,name ))
417+
418+ comp_start_id = len (self .raw_data ['replay.initData' ].player_names )
419+ for name , (idx ,pdata ) in unassigned_player_data .items ():
420+ attributes = self .attributes .get (idx ,dict ())
421+ createPlayer (comp_start_id , pdata , attributes )
422+ comp_start_id += 1
423+
424+ obs_start_idx = len (self .raw_data ['replay.details' ].players )
425+ for pid , name in observer_data :
426+ attributes = self .attributes .get (obs_start_idx ,dict ())
427+ createObserver (pid , name , attributes )
428+ obs_start_idx += 1
429+ except :
430+ print unassigned_player_data
431+ print self .raw_data ['replay.initData' ].player_names
432+ raise
433+
434+
435+ self .humans = filter (lambda p : p .is_human , self .people )
436+
418437 #Create an store an ordered lineup string
419438 for team in self .teams :
420439 team .lineup = '' .join (sorted (player .play_race [0 ].upper () for player in team ))
421440
422441 self .real_type = real_type (self .teams )
423442
424- if 'replay.initData' in self .raw_data :
425- # Assign the default region to computer players for consistency
426- # We know there will be a default region because there must be
427- # at least 1 human player or we wouldn't have a self.
428- for player in self .players :
429- if not player .is_human :
430- player .region = default_region
431-
432- # Create observers out of the leftover names gathered from initData
433- all_players = [p .name for p in self .players ]
434- all_people = self .raw_data ['replay.initData' ].player_names
435- for obs_name in all_people :
436- if obs_name in all_players : continue
437-
438- observer = Observer (obs_index ,obs_name )
439- observer .region = default_region
440- self .observers .append (observer )
441- self .people .append (observer )
442- self .person [obs_index ] = observer
443- obs_index += 1
444-
445- # Miscellaneous people processing
446- self .humans = filter (lambda p : p .is_human , self .people )
443+ # Assign the default region to computer players for consistency
444+ # We know there will be a default region because there must be
445+ # at least 1 human player or we wouldn't have a self.
446+ default_region = self .humans [0 ].region
447+ for player in self .players :
448+ if not player .is_human :
449+ player .region = default_region
450+ for obs in self .observers :
451+ obs .region = default_region
447452
448453 if 'replay.message.events' in self .raw_data :
449454 # Figure out recorder
0 commit comments