Skip to content

Commit 5c67131

Browse files
committed
Apply experimental player load scheme.
Superficial testing says this works better than the previous method but I still need to make sure. Also, since 24247 is it apparently possible for computer players to not have attributes assigned to them. I have no idea how we are supposed to pick the team they are on without the attributes.
1 parent 7f5512f commit 5c67131

File tree

1 file changed

+64
-59
lines changed

1 file changed

+64
-59
lines changed

sc2reader/resources.py

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import zlib
44
import pprint
55
import hashlib
6+
import collections
67
from datetime import datetime
78
import time
89
from 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

Comments
 (0)