Skip to content

Commit 2a67200

Browse files
committed
Improve reference docs for resources/objects.
1 parent a312310 commit 2a67200

File tree

2 files changed

+134
-50
lines changed

2 files changed

+134
-50
lines changed

sc2reader/objects.py

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class Person(object):
116116
#: Really just a shortcut for isinstance(obj, Observer).
117117
is_observer = bool()
118118

119+
#: A flag indicating if the person is a human or computer
120+
is_human = bool()
121+
119122
#: A list of :class:`ChatEvent` objects representing all of the chat
120123
#: messages the person sent during the game
121124
messages = list()
@@ -130,13 +133,17 @@ class Person(object):
130133
#: A flag indicating if the person is a computer or human
131134
is_human = bool()
132135

136+
#: The player's region.
137+
region = str()
138+
133139
def __init__(self, pid, name):
134140
self.pid = pid
135141
self.name = name
136-
self.is_observer = None
142+
self.is_observer = bool()
137143
self.messages = list()
138144
self.events = list()
139145
self.is_human = bool()
146+
self.region = str()
140147
self.recorder = False # Actual recorder will be determined using the replay.message.events file
141148

142149
class Observer(Person):
@@ -146,6 +153,7 @@ class Observer(Person):
146153
147154
All Observers are human.
148155
"""
156+
149157
def __init__(self, pid, name):
150158
super(Observer,self).__init__(pid, name)
151159
self.is_observer = True
@@ -179,12 +187,13 @@ class Player(Person):
179187
#: The player's handicap as set prior to game start, ranges from 50-100
180188
handicap = int()
181189

182-
#: The player's region
183-
region = str()
184-
185190
#: The subregion with in the player's region
186191
subregion = int()
187192

193+
#: The player's bnet uid for his region/subregion.
194+
#: Used to construct the bnet profile url.
195+
uid = int()
196+
188197
def __init__(self, pid, name):
189198
super(Player,self).__init__(pid, name)
190199
self.is_observer = False
@@ -199,43 +208,15 @@ def __str__(self):
199208

200209
@property
201210
def result(self):
202-
"""The game result for this player"""
203-
return self.team.result
211+
"""The game result for this player: Win, Loss, Unknown"""
212+
return self.team.result if self.team else "Unknown"
204213

205214
def format(self, format_string):
206215
return format_string.format(**self.__dict__)
207216

208217
def __repr__(self):
209218
return str(self)
210219

211-
class Graph():
212-
"""
213-
A class to represent a graph on the score screen
214-
"""
215-
#: Times in seconds on the x-axis of the graph
216-
times = list()
217-
218-
#: Values on the y-axis of the graph
219-
values = list()
220-
221-
def __init__(self, x, y, xy_list=None):
222-
self.times = list()
223-
self.values = list()
224-
225-
if xy_list:
226-
for x, y in xy_list:
227-
self.times.append(x)
228-
self.values.append(y)
229-
else:
230-
self.times = x
231-
self.values = y
232-
233-
def as_points(self):
234-
""" Get the graph as a list of (x, y) tuples """
235-
return zip(self.times, self.values)
236-
237-
def __str__(self):
238-
return "Graph with {0} values".format(len(self.times))
239220

240221
class PlayerSummary():
241222
"""
@@ -257,7 +238,7 @@ class PlayerSummary():
257238

258239
#: The index of the player in the game
259240
pid = int()
260-
241+
261242
#: The index of the players team in the game
262243
teamid = int()
263244

@@ -278,13 +259,13 @@ class PlayerSummary():
278259

279260
#: unknown1
280261
unknown1 = int()
281-
262+
282263
#: unknown2
283264
unknown2 = dict()
284265

285266
#: :class:`Graph` of player army values over time (seconds)
286267
army_graph = None
287-
268+
288269
#: :class:`Graph` of player income over time (seconds)
289270
income_graph = None
290271

@@ -294,17 +275,46 @@ class PlayerSummary():
294275
def __init__(self, pid):
295276
unknown2 = dict()
296277
stats = dict()
297-
278+
298279
self.pid = pid
299-
280+
300281
def __str__(self):
301282
if not self.is_ai:
302283
return '{} - {} - {}/{}/'.format(self.teamid, self.race, self.subregion, self.bnetid)
303284
else:
304-
return '{} - {} - AI'.format(self.teamid, self.race)
305-
285+
return '{} - {} - AI'.format(self.teamid, self.race)
286+
306287
def get_stats(self):
307288
s = ''
308289
for k in self.stats:
309290
s += '{}: {}\n'.format(self.stats_pretty_names[k], self.stats[k])
310291
return s.strip()
292+
293+
# TODO: Are there libraries with classes like this in them
294+
class Graph():
295+
"""A class to represent a graph on the score screen."""
296+
297+
#: Times in seconds on the x-axis of the graph
298+
times = list()
299+
300+
#: Values on the y-axis of the graph
301+
values = list()
302+
303+
def __init__(self, x, y, xy_list=None):
304+
self.times = list()
305+
self.values = list()
306+
307+
if xy_list:
308+
for x, y in xy_list:
309+
self.times.append(x)
310+
self.values.append(y)
311+
else:
312+
self.times = x
313+
self.values = y
314+
315+
def as_points(self):
316+
""" Get the graph as a list of (x, y) tuples """
317+
return zip(self.times, self.values)
318+
319+
def __str__(self):
320+
return "Graph with {0} values".format(len(self.times))

sc2reader/resources.py

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ def __init__(self, file_object, filename=None, **options):
3030

3131
class Replay(Resource):
3232

33+
#: A nested dictionary of player => { attr_name : attr_value } for
34+
#: known attributes. Player 16 represents the global context and
35+
#: contains attributes like game speed.
36+
attributes = defaultdict(dict)
37+
3338
#: Fully qualified filename of the replay file represented.
3439
filename = str()
3540

@@ -42,10 +47,10 @@ class Replay(Resource):
4247
#: The full version release string as seen on Battle.net
4348
release_string = str()
4449

45-
#: The :class:`Length` of the replay as an alternative to :attr:`frames`
46-
length = utils.Length()
50+
#: A tuple of the individual pieces of the release string
51+
versions = tuple()
4752

48-
#: The effective game speed when the game was played.
53+
#: The game speed: Slower, Slow, Normal, Fast, Faster
4954
speed = str()
5055

5156
#: The game type: 1v1, 2v2, 3v3, 4v4, FFA
@@ -60,9 +65,42 @@ class Replay(Resource):
6065
#: A flag for private non-ladder games
6166
is_private = bool()
6267

68+
#: The raw hash name of the s2ma resource as hosted on bnet depots
69+
map_hash = str()
70+
6371
#: The name of the map the game was played on
72+
map_name = str()
73+
74+
#: A reference to the loaded :class:`Map` resource.
6475
map = None
6576

77+
#: The UTC time the game was ended as represented by the Windows OS
78+
windows_timestamp = int()
79+
80+
#: The UTC time the game was ended as represented by the Unix OS
81+
unix_timestamp = int()
82+
83+
#: The time zone adjustment for the location the replay was recorded at
84+
time_zone= int()
85+
86+
#: Deprecated: See `end_time` below.
87+
date = None
88+
89+
#: A datetime object representing the local time at the end of the game.
90+
end_time = None
91+
92+
#: A datetime object representing the local time at the start of the game
93+
start_time = None
94+
95+
#: Deprecated: See `game_length` below.
96+
length = None
97+
98+
#: The :class:`Length` of the replay as an alternative to :attr:`frames`
99+
game_length = None
100+
101+
#: The :class:`Length` of the replay in real time adjusted for the game speed
102+
self.real_length = None
103+
66104
#: The gateway the game was played on: us, eu, sea, etc
67105
gateway = str()
68106

@@ -103,12 +141,27 @@ class Replay(Resource):
103141
#: A list of all the chat message events from the game
104142
messages = list()
105143

144+
#: A list of pings sent by all the different people in the game
145+
pings = list()
146+
147+
#: A list of packets sent between the various game clients
148+
packets = list()
149+
106150
#: A reference to the :class:`Person` that recorded the game
107151
recorder = None
108152

109153
#: If there is a valid winning team this will contain a :class:`Team` otherwise it will be :class:`None`
110154
winner = None
111155

156+
#: A dictionary mapping unit unique ids to their corresponding classes
157+
objects = dict()
158+
159+
#: A sha256 hash uniquely representing the combination of people in the game.
160+
#: Can be used in conjunction with date times to match different replays
161+
#: of the game game.
162+
people_hash = str()
163+
164+
112165
def __init__(self, replay_file, filename=None, load_level=4, **options):
113166
super(Replay, self).__init__(replay_file, filename, **options)
114167
self.datapack = None
@@ -123,23 +176,20 @@ def __init__(self, replay_file, filename=None, load_level=4, **options):
123176
self.is_ladder = False
124177
self.is_private = False
125178
self.map = ""
179+
self.map_hash = ""
126180
self.gateway = ""
127181
self.events = list()
128182
self.events_by_type = defaultdict(list)
129183
self.results = dict()
130-
131184
self.teams, self.team = list(), dict()
132185
self.players, self.player = list(), utils.PersonDict()
133186
self.observers = list() #Unordered list of Observer
134-
135187
self.people, self.humans = list(), list() #Unordered list of Players+Observers
136-
137188
self.person = utils.PersonDict() #Maps pid to Player/Observer
138-
self.attributes = list()
189+
self.attributes = defaultdict(dict)
139190
self.messages = list()
140191
self.recorder = None # Player object
141192
self.packets = list()
142-
143193
self.objects = {}
144194

145195
# Bootstrap the readers.
@@ -152,6 +202,7 @@ def __init__(self, replay_file, filename=None, load_level=4, **options):
152202

153203
# Unpack the MPQ and read header data if requested
154204
if load_level >= 0:
205+
# Set ('versions', 'frames', 'build', 'release_string', 'length')
155206
self.__dict__.update(utils.read_header(replay_file))
156207
self.archive = utils.open_archive(replay_file)
157208

@@ -331,7 +382,7 @@ def load_players(self):
331382
if obs_name in all_players: continue
332383

333384
observer = Observer(obs_index,obs_name)
334-
observer.gateway = self.gateway
385+
observer.region = default_region
335386
self.observers.append(observer)
336387
self.people.append(observer)
337388
self.person[obs_index] = observer
@@ -372,6 +423,7 @@ def load_events(self):
372423

373424
for event in self.events:
374425
event.load_context(self)
426+
# TODO: Should this be documented or removed? I don't like it.
375427
self.events_by_type[event.name].append(event)
376428
if event.pid != 16:
377429
self.person[event.pid].events.append(event)
@@ -462,6 +514,28 @@ def _read_data(self, data_file, reader):
462514
class Map(Resource):
463515
url_template = 'http://{0}.depot.battle.net:1119/{1}.s2ma'
464516

517+
#: The unique hash used to identify this map on bnet's depots.
518+
hash = str()
519+
520+
#: The gateway this map was posted to.
521+
#: Maps must be posted individually to each gateway.
522+
gateway = str()
523+
524+
#: A URL reference to the location of this map on bnet's depots.
525+
url = str()
526+
527+
#: The localized (only enUS supported right now) map name
528+
name = str()
529+
530+
#: The map's author
531+
author = str()
532+
533+
#: The map description as written by author
534+
description = str()
535+
536+
#: A byte string representing the minimap in tga format.
537+
minimap = str()
538+
465539
def __init__(self, map_file, filename=None, gateway=None, map_hash=None, **options):
466540
super(Map, self).__init__(map_file, filename, **options)
467541
self.hash = map_hash

0 commit comments

Comments
 (0)