Skip to content

Commit 1395627

Browse files
committed
Add defaults, improve documentation, add fields.
Now supports all tracker events except UpgradeComplete events.
1 parent 6821e46 commit 1395627

File tree

1 file changed

+63
-20
lines changed

1 file changed

+63
-20
lines changed

sc2reader/events/tracker.py

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44
class TrackerEvent(object):
55
def __init__(self, frames):
6+
#: The frame of the game this event was applied
67
self.frame = frames
78

89
def __str__(self):
10+
""" Dumps the event data to a json string. """
911
return json.dumps(self.__dict__)
1012

1113
def load_context(self, replay):
@@ -21,6 +23,9 @@ def __init__(self, frames, data):
2123
#: Id of the player the stats are for
2224
self.pid = data[0]
2325

26+
#: The Player object that these stats apply to
27+
self.player = None
28+
2429
#: An ordered list of all the available stats
2530
self.stats = data[1]
2631

@@ -142,6 +147,9 @@ def __init__(self, frames, data):
142147
#: The unique id of the unit being born
143148
self.unit_id = self.unit_id_index << 16 | self.unit_id_recycle
144149

150+
#: The unit object that was born
151+
self.unit = None
152+
145153
#: The unit type name of the unit being born
146154
self.unit_type_name = data[2]
147155

@@ -151,6 +159,12 @@ def __init__(self, frames, data):
151159
#: The id of the player that pays upkeep for this unit.
152160
self.upkeep_pid = data[4]
153161

162+
#: The player object that pays upkeep for this one. 0 means neutral unit
163+
self.unit_upkeeper = None
164+
165+
#: The player object that controls this unit. 0 means neutral unit
166+
self.unit_controller = None
167+
154168
#: The x coordinate of the location
155169
self.x = data[5]
156170

@@ -168,14 +182,18 @@ def load_context(self, replay):
168182
self.unit_upkeeper = replay.player[self.upkeep_pid]
169183

170184
if self.unit_id in replay.objects:
185+
# This can happen because game events are done first
171186
self.unit = replay.objects[self.unit_id]
172187
else:
173188
# TODO: How to tell if something is hallucination?
174189
self.unit = replay.datapack.create_unit(self.unit_id, self.unit_type_name, 0, self.frame)
175-
self.unit.location = self.location
176190
replay.objects[self.unit_id] = self.unit
177191
replay.active_units[self.unit_id_index] = self.unit
178192

193+
self.unit.location = self.location
194+
self.unit.birth = self.frame
195+
self.unit.owner = self.unit_upkeeper
196+
179197

180198
class UnitDiedEvent(TrackerEvent):
181199
name = 'UnitDiedEvent'
@@ -192,9 +210,15 @@ def __init__(self, frames, data):
192210
#: The unique id of the unit being killed
193211
self.unit_id = self.unit_id_index << 16 | self.unit_id_recycle
194212

213+
#: The unit object that died
214+
self.unit = None
215+
195216
#: The id of the player that killed this unit. None when not available.
196217
self.killer_pid = data[2]
197218

219+
#: The player object of the that killed the unit. Not always available.
220+
self.killer = None
221+
198222
#: The x coordinate of the location
199223
self.x = data[3]
200224

@@ -207,12 +231,11 @@ def __init__(self, frames, data):
207231
def load_context(self, replay):
208232
if self.unit_id in replay.objects:
209233
self.unit = replay.objects[self.unit_id]
234+
self.unit.death = self.frame
210235
self.unit.location = self.location
211236
del replay.active_units[self.unit_id_index]
212237
else:
213-
# Create a new unit, but we don't have a type name map yet!
214238
print "Unit died before it was born!"
215-
self.unit = None
216239

217240
if self.killer_pid: # This field isn't always available
218241
self.killer = replay.player[self.killer_pid]
@@ -233,26 +256,33 @@ def __init__(self, frames, data):
233256
#: The unique id of the unit changing ownership
234257
self.unit_id = self.unit_id_index << 16 | self.unit_id_recycle
235258

259+
#: The unit object that is affected by this event
260+
self.unit = None
261+
236262
#: The new id of the player that controls this unit.
237263
self.control_pid = data[2]
238264

239265
#: The new id of the player that pays upkeep for this unit.
240266
self.upkeep_pid = data[3]
241267

268+
#: The player object that pays upkeep for this one. 0 means neutral unit
269+
self.unit_upkeeper = None
270+
271+
#: The player object that controls this unit. 0 means neutral unit
272+
self.unit_controller = None
242273

243274
def load_context(self, replay):
244-
if self.control_pid: # 0 means neutral unit
275+
if self.control_pid:
245276
self.unit_controller = replay.player[self.control_pid]
246277

247-
if self.upkeep_pid: # 0 means neutral unit
278+
if self.upkeep_pid:
248279
self.unit_upkeeper = replay.player[self.upkeep_pid]
249280

250281
if self.unit_id in replay.objects:
251282
self.unit = replay.objects[self.unit_id]
283+
self.unit.owner = self.unit_upkeeper
252284
else:
253-
# Create a new unit, but we don't have a type name map yet!
254285
print "Unit owner changed before it was born!"
255-
self.unit = None
256286

257287

258288
class UnitTypeChangeEvent(TrackerEvent):
@@ -270,6 +300,9 @@ def __init__(self, frames, data):
270300
#: The unique id of the unit changing type
271301
self.unit_id = self.unit_id_index << 16 | self.unit_id_recycle
272302

303+
#: The unit object that was changed
304+
self.unit = None
305+
273306
#: The the new unit type name
274307
self.unit_type_name = data[2]
275308

@@ -279,7 +312,6 @@ def load_context(self, replay):
279312
replay.datapack.change_type(self.unit, self.unit_type_name, self.frame)
280313
else:
281314
print "Unit type changed before it was born!"
282-
self.unit = None
283315

284316

285317
class UpgradeCompleteEvent(TrackerEvent):
@@ -291,6 +323,9 @@ def __init__(self, frames, data):
291323
#: The player that completed the upgrade
292324
self.pid = data[0]
293325

326+
#: The Player object that completed the upgrade
327+
self.player = None
328+
294329
#: The name of the upgrade
295330
self.upgrade_type_name = data[1]
296331

@@ -319,6 +354,9 @@ def __init__(self, frames, data):
319354
#: The unique id of the stated unit
320355
self.unit_id = self.unit_id_index << 16 | self.unit_id_recycle
321356

357+
#: The unit object that was started (e.g. started to warp in)
358+
self.unit = None
359+
322360
#: The the new unit type name
323361
self.unit_type_name = data[2]
324362

@@ -328,6 +366,12 @@ def __init__(self, frames, data):
328366
#: The id of the player that pays upkeep for this unit.
329367
self.upkeep_pid = data[4]
330368

369+
#: The player object that pays upkeep for this one. 0 means neutral unit
370+
self.unit_upkeeper = None
371+
372+
#: The player object that controls this unit. 0 means neutral unit
373+
self.unit_controller = None
374+
331375
#: The x coordinate of the location
332376
self.x = data[5]
333377

@@ -345,14 +389,17 @@ def load_context(self, replay):
345389
self.unit_upkeeper = replay.player[self.upkeep_pid]
346390

347391
if self.unit_id in replay.objects:
392+
# This can happen because game events are done first
348393
self.unit = replay.objects[self.unit_id]
349394
else:
350395
# TODO: How to tell if something is hallucination?
351396
self.unit = replay.datapack.create_unit(self.unit_id, self.unit_type_name, 0, self.frame)
352397
replay.objects[self.unit_id] = self.unit
353398
replay.active_units[self.unit_id_index] = self.unit
354399

400+
self.unit.owner = self.unit_upkeeper
355401
self.unit.location = self.location
402+
self.unit.birth = self.frame
356403

357404

358405
class UnitDoneEvent(TrackerEvent):
@@ -370,12 +417,14 @@ def __init__(self, frames, data):
370417
#: The unique id of the finished unit
371418
self.unit_id = self.unit_id_index << 16 | self.unit_id_recycle
372419

420+
#: The unit object that was finished
421+
self.unit = None
422+
373423
def load_context(self, replay):
374424
if self.unit_id in replay.objects:
375425
self.unit = replay.objects[self.unit_id]
376426
else:
377427
print "Unit done before it was started!"
378-
self.unit = None
379428

380429

381430
class UnitPositionsEvent(TrackerEvent):
@@ -384,30 +433,24 @@ class UnitPositionsEvent(TrackerEvent):
384433
def __init__(self, frames, data):
385434
super(UnitPositionsEvent, self).__init__(frames)
386435

387-
#: ???
436+
#: The starting unit index point.
388437
self.first_unit_index = data[0]
389438

390-
#: ???
439+
#: An ordered list of unit/point data interpreted as below.
391440
self.items = data[1]
392441

393-
442+
#: A list of units that had their position updated by this event
394443
self.units = list()
395444

445+
#: A list of (unit_index, (x,y)) derived from the first_unit_index and items
396446
self.positions = list()
447+
397448
unit_index = self.first_unit_index
398449
for i in range(0, len(self.items), 3):
399450
unit_index += self.items[i]
400451
x = self.items[i+1]*4
401452
y = self.items[i+2]*4
402453
self.positions.append((unit_index, (x,y)))
403-
""" We need to be able to find units without the recycle id, can't do this yet!
404-
unitTagIndex = event['m_firstUnitIndex']
405-
for i in xrange(len(event['m_items']) / 3):
406-
unitTagIndex += event['m_items'][i * 3 + 0]
407-
x = event['m_items'][i * 3 + 1] * 4
408-
y = event['m_items'][i * 3 + 2] * 4
409-
# the unit with unitTagIndex is now at coordinate (x, y)
410-
"""
411454

412455
def load_context(self, replay):
413456
for unit_index, (x,y) in self.positions:

0 commit comments

Comments
 (0)