Skip to content

Commit b421a7c

Browse files
committed
Initial pass at PTR 2.1 support.
1 parent 03bbdae commit b421a7c

File tree

3 files changed

+131
-37
lines changed

3 files changed

+131
-37
lines changed

sc2reader/events/tracker.py

Lines changed: 86 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,30 @@ def load_context(self, replay):
2727
pass
2828

2929
def _str_prefix(self):
30-
return "{0}\t ".format(Length(seconds=int(self.frame/16)))
30+
return "{0}\t ".format(Length(seconds=int(self.frame / 16)))
3131

3232
def __str__(self):
3333
return self._str_prefix() + self.name
3434

3535

36+
class PlayerSetupEvent(TrackerEvent):
37+
""" Sent during game setup to help us organize players better """
38+
def __init__(self, frames, data, build):
39+
super(PlayerSetupEvent, self).__init__(frames)
40+
41+
#: The player id of the player we are setting up
42+
self.pid = data[0]
43+
44+
#: The type of this player. One of 1=human, 2=cpu, 3=neutral, 4=hostile
45+
self.type = data[1]
46+
47+
#: The user id of the player we are setting up. None of not human
48+
self.uid = data[2]
49+
50+
#: The slot id of the player we are setting up. None if not playing
51+
self.sid = data[3]
52+
53+
3654
class PlayerStatsEvent(TrackerEvent):
3755
"""
3856
Player Stats events are generated for all players that were in the game even if they've since
@@ -181,10 +199,10 @@ def __init__(self, frames, data, build):
181199
self.resources_killed = self.minerals_killed + self.vespene_killed
182200

183201
#: The food supply currently used
184-
self.food_used = clamp(self.stats[29])/4096.0
202+
self.food_used = clamp(self.stats[29]) / 4096.0
185203

186204
#: The food supply currently available
187-
self.food_made = clamp(self.stats[30])/4096.0
205+
self.food_made = clamp(self.stats[30]) / 4096.0
188206

189207
#: The total mineral value of all active forces
190208
self.minerals_used_active_forces = clamp(self.stats[31])
@@ -211,7 +229,7 @@ def __init__(self, frames, data, build):
211229
self.ff_vespene_lost_technology = clamp(self.stats[38]) if build >= 26490 else None
212230

213231
def __str__(self):
214-
return self._str_prefix()+"{0: >15} - Stats Update".format(self.player)
232+
return self._str_prefix() + "{0: >15} - Stats Update".format(self.player)
215233

216234

217235
class UnitBornEvent(TrackerEvent):
@@ -255,19 +273,24 @@ def __init__(self, frames, data, build):
255273
#: The player object that controls this unit. 0 means neutral unit
256274
self.unit_controller = None
257275

258-
#: The x coordinate of the location with 4 point resolution. E.g. 13.75 recorded as 12.
259-
#: Location prior to rounding marks the center of the unit footprint.
260-
self.x = data[5] * 4
276+
#: The x coordinate of the center of the born unit's footprint. Only 4 point resolution
277+
#: prior to Starcraft Patch 2.1.
278+
self.x = data[5]
261279

262-
#: The y coordinate of the location with 4 point resolution. E.g. 13.75 recorded as 12.
263-
#: Location prior to rounding marks the center of the unit footprint.
264-
self.y = data[6] * 4
280+
#: The y coordinate of the center of the born unit's footprint. Only 4 point resolution
281+
#: prior to Starcraft Patch 2.1.
282+
self.y = data[6]
265283

266284
#: The map location of the unit birth
267285
self.location = (self.x, self.y)
268286

287+
if build < 27950:
288+
self.x = self.x * 4
289+
self.y = self.y * 4
290+
self.location = (self.x, self.y)
291+
269292
def __str__(self):
270-
return self._str_prefix()+"{0: >15} - Unit born {1}".format(self.unit_upkeeper, self.unit)
293+
return self._str_prefix() + "{0: >15} - Unit born {1}".format(self.unit_upkeeper, self.unit)
271294

272295

273296
class UnitDiedEvent(TrackerEvent):
@@ -296,19 +319,39 @@ def __init__(self, frames, data, build):
296319
#: The player object of the that killed the unit. Not always available.
297320
self.killer = None
298321

299-
#: The x coordinate of the location with 4 point resolution. E.g. 13.75 recorded as 12.
300-
#: Location prior to rounding marks the center of the unit footprint.
301-
self.x = data[3] * 4
322+
#: The x coordinate of the center of the dying unit's footprint. Only 4 point resolution
323+
#: prior to Starcraft Patch 2.1.
324+
self.x = data[3]
302325

303-
#: The y coordinate of the location with 4 point resolution. E.g. 13.75 recorded as 12.
304-
#: Location prior to rounding marks the center of the unit footprint.
305-
self.y = data[4] * 4
326+
#: The y coordinate of the center of the dying unit's footprint. Only 4 point resolution
327+
#: prior to Starcraft Patch 2.1.
328+
self.y = data[4]
306329

307330
#: The map location the unit was killed at.
308331
self.location = (self.x, self.y)
309332

333+
#: The index portion of the killing unit's id. Available for build 27950+
334+
self.killer_unit_index = None
335+
336+
#: The recycle portion of the killing unit's id. Available for build 27950+
337+
self.killer_unit_recycle = None
338+
339+
#: The unique id of the unit doing the killing. Available for build 27950+
340+
self.killer_unit_id = None
341+
342+
if build < 27950:
343+
self.x = self.x * 4
344+
self.y = self.y * 4
345+
self.location = (self.x, self.y)
346+
else:
347+
# Starcraft patch 2.1 introduced killer unit indexes
348+
self.killer_unit_index = data[5]
349+
self.killer_unit_recycle = data[6]
350+
if self.killer_unit_index:
351+
self.killer_unit_id = self.killer_unit_index << 18 | self.killer_unit_recycle
352+
310353
def __str__(self):
311-
return self._str_prefix()+"{0: >15} - Unit died {1}.".format(self.unit.owner, self.unit)
354+
return self._str_prefix() + "{0: >15} - Unit died {1}.".format(self.unit.owner, self.unit)
312355

313356

314357
class UnitOwnerChangeEvent(TrackerEvent):
@@ -344,7 +387,7 @@ def __init__(self, frames, data, build):
344387
self.unit_controller = None
345388

346389
def __str__(self):
347-
return self._str_prefix()+"{0: >15} took {1}".format(self.unit_upkeeper, self.unit)
390+
return self._str_prefix() + "{0: >15} took {1}".format(self.unit_upkeeper, self.unit)
348391

349392

350393
class UnitTypeChangeEvent(TrackerEvent):
@@ -372,7 +415,7 @@ def __init__(self, frames, data, build):
372415
self.unit_type_name = data[2].decode('utf8')
373416

374417
def __str__(self):
375-
return self._str_prefix()+"{0: >15} - Unit {0} type changed to {1}".format(self.unit.owner, self.unit, self.unit_type_name)
418+
return self._str_prefix() + "{0: >15} - Unit {0} type changed to {1}".format(self.unit.owner, self.unit, self.unit_type_name)
376419

377420

378421
class UpgradeCompleteEvent(TrackerEvent):
@@ -395,7 +438,7 @@ def __init__(self, frames, data, build):
395438
self.count = data[2]
396439

397440
def __str__(self):
398-
return self._str_prefix()+"{0: >15} - {1}upgrade completed".format(self.player, self.upgrade_type_name)
441+
return self._str_prefix() + "{0: >15} - {1}upgrade completed".format(self.player, self.upgrade_type_name)
399442

400443

401444
class UnitInitEvent(TrackerEvent):
@@ -434,19 +477,24 @@ def __init__(self, frames, data, build):
434477
#: The player object that controls this unit. 0 means neutral unit
435478
self.unit_controller = None
436479

437-
#: The x coordinate of the location with 4 point resolution. E.g. 13.75 recorded as 12.
438-
#: Location prior to rounding marks the center of the unit footprint.
439-
self.x = data[5] * 4
480+
#: The x coordinate of the center of the init unit's footprint. Only 4 point resolution
481+
#: prior to Starcraft Patch 2.1.
482+
self.x = data[5]
440483

441-
#: The y coordinate of the location with 4 point resolution. E.g. 13.75 recorded as 12.
442-
#: Location prior to rounding marks the center of the unit footprint.
443-
self.y = data[6] * 4
484+
#: The y coordinate of the center of the init unit's footprint. Only 4 point resolution
485+
#: prior to Starcraft Patch 2.1.
486+
self.y = data[6]
444487

445488
#: The map location the unit was started at
446489
self.location = (self.x, self.y)
447490

491+
if build < 27950:
492+
self.x = self.x * 4
493+
self.y = self.y * 4
494+
self.location = (self.x, self.y)
495+
448496
def __str__(self):
449-
return self._str_prefix()+"{0: >15} - Unit initiated {1}".format(self.unit_upkeeper, self.unit)
497+
return self._str_prefix() + "{0: >15} - Unit initiated {1}".format(self.unit_upkeeper, self.unit)
450498

451499

452500
class UnitDoneEvent(TrackerEvent):
@@ -470,7 +518,7 @@ def __init__(self, frames, data, build):
470518
self.unit = None
471519

472520
def __str__(self):
473-
return self._str_prefix()+"{0: >15} - Unit {1} done".format(self.unit.owner, self.unit)
521+
return self._str_prefix() + "{0: >15} - Unit {1} done".format(self.unit.owner, self.unit)
474522

475523

476524
class UnitPositionsEvent(TrackerEvent):
@@ -491,17 +539,20 @@ def __init__(self, frames, data, build):
491539
#: A dict mapping of units that had their position updated to their positions
492540
self.units = dict()
493541

494-
#: A list of (unit_index, (x,y)) derived from the first_unit_index and items. Like the other
495-
#: tracker events, these coordinates have 4 point resolution. (15,25) recorded as (12,24).
496-
#: Location prior to rounding marks the center of the unit footprint.
542+
#: A list of (unit_index, (x,y)) derived from the first_unit_index and items. Prior to
543+
#: Starcraft Patch 2.1 the coordinates have 4 point resolution. (15,25) recorded as (12,24).
544+
#: Location prior to any rounding marks the center of the unit footprint.
497545
self.positions = list()
498546

499547
unit_index = self.first_unit_index
500548
for i in range(0, len(self.items), 3):
501549
unit_index += self.items[i]
502-
x = self.items[i+1]*4
503-
y = self.items[i+2]*4
550+
x = self.items[i + 1]
551+
y = self.items[i + 2]
552+
if build < 27950:
553+
x = x * 4
554+
y = y * 4
504555
self.positions.append((unit_index, (x, y)))
505556

506557
def __str__(self):
507-
return self._str_prefix()+"Unit positions update"
558+
return self._str_prefix() + "Unit positions update"

sc2reader/readers.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def __call__(self, data, replay):
1919
user_initial_data=[dict(
2020
name=data.read_aligned_string(data.read_uint8()),
2121
clan_tag=data.read_aligned_string(data.read_uint8()) if replay.base_build >= 24764 and data.read_bool() else None,
22+
clan_logo=data.read_aligned_string(40) if replay.base_build >= 27950 and data.read_bool() else None,
2223
highest_league=data.read_uint8() if replay.base_build >= 24764 and data.read_bool() else None,
2324
combined_race_levels=data.read_uint32() if replay.base_build >= 24764 and data.read_bool() else None,
2425
random_seed=data.read_uint32(),
@@ -74,6 +75,7 @@ def __call__(self, data, replay):
7475
default_difficulty=data.read_bits(6),
7576
default_ai_build=data.read_bits(7) if replay.base_build >= 23925 else None,
7677
cache_handles=[DepotFile(data.read_aligned_bytes(40)) for i in range(data.read_bits(6 if replay.base_build >= 21955 else 4))],
78+
has_extension_mod=data.read_bool() if replay.base_build >= 27950 else None,
7779
is_blizzardMap=data.read_bool(),
7880
is_premade_ffa=data.read_bool(),
7981
is_coop_mode=data.read_bool() if replay.base_build >= 23925 else None,
@@ -610,6 +612,7 @@ def camera_update_event(self, data):
610612
distance=data.read_uint16() if data.read_bool() else None,
611613
pitch=data.read_uint16() if data.read_bool() else None,
612614
yaw=data.read_uint16() if data.read_bool() else None,
615+
reason=None,
613616
)
614617

615618
def trigger_abort_mission_event(self, data):
@@ -1361,6 +1364,7 @@ def hijack_replay_game_event(self, data):
13611364
name=data.read_aligned_string(data.read_uint8()),
13621365
toon_handle=data.read_aligned_string(data.read_bits(7)) if data.read_bool() else None,
13631366
clan_tag=data.read_aligned_string(data.read_uint8()) if data.read_bool() else None,
1367+
clan_logo=None,
13641368
) for i in range(data.read_bits(5))],
13651369
method=data.read_bits(1),
13661370
)
@@ -1381,6 +1385,7 @@ def game_user_join_event(self, data):
13811385
name=data.read_aligned_string(data.read_bits(8)),
13821386
toon_handle=data.read_aligned_string(data.read_bits(7)) if data.read_bool() else None,
13831387
clan_tag=data.read_aligned_string(data.read_uint8()) if data.read_bool() else None,
1388+
clan_log=None,
13841389
)
13851390

13861391

@@ -1430,6 +1435,43 @@ def trigger_mouse_moved_event(self, data):
14301435
)
14311436

14321437

1438+
class GameEventsReader_27950(GameEventsReader_26490):
1439+
1440+
def hijack_replay_game_event(self, data):
1441+
return dict(
1442+
user_infos=[dict(
1443+
game_user_id=data.read_bits(4),
1444+
observe=data.read_bits(2),
1445+
name=data.read_aligned_string(data.read_uint8()),
1446+
toon_handle=data.read_aligned_string(data.read_bits(7)) if data.read_bool() else None,
1447+
clan_tag=data.read_aligned_string(data.read_uint8()) if data.read_bool() else None,
1448+
clan_logo=data.read_aligned_string(40) if data.read_bool() else None,
1449+
) for i in range(data.read_bits(5))],
1450+
method=data.read_bits(1),
1451+
)
1452+
1453+
def camera_update_event(self, data):
1454+
return dict(
1455+
target=dict(
1456+
x=data.read_uint16(),
1457+
y=data.read_uint16(),
1458+
),
1459+
distance=data.read_uint16() if data.read_bool() else None,
1460+
pitch=data.read_uint16() if data.read_bool() else None,
1461+
yaw=data.read_uint16() if data.read_bool() else None,
1462+
reason=data.read_uint8() - 128 if data.read_bool() else None,
1463+
)
1464+
1465+
def game_user_join_event(self, data):
1466+
return dict(
1467+
observe=data.read_bits(2),
1468+
name=data.read_aligned_string(data.read_bits(8)),
1469+
toon_handle=data.read_aligned_string(data.read_bits(7)) if data.read_bool() else None,
1470+
clan_tag=data.read_aligned_string(data.read_uint8()) if data.read_bool() else None,
1471+
clan_logo=data.read_aligned_string(40) if data.read_bool() else None,
1472+
)
1473+
1474+
14331475
class TrackerEventsReader(object):
14341476

14351477
def __init__(self):
@@ -1443,6 +1485,7 @@ def __init__(self):
14431485
6: UnitInitEvent,
14441486
7: UnitDoneEvent,
14451487
8: UnitPositionsEvent,
1488+
9: PlayerSetupEvent,
14461489
}
14471490

14481491
def __call__(self, data, replay):

sc2reader/resources.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,10 +564,10 @@ def register_default_readers(self):
564564
self.register_reader('replay.game.events', readers.GameEventsReader_22612(), lambda r: 22612 <= r.base_build < 23260)
565565
self.register_reader('replay.game.events', readers.GameEventsReader_23260(), lambda r: 23260 <= r.base_build < 24247)
566566
self.register_reader('replay.game.events', readers.GameEventsReader_24247(), lambda r: 24247 <= r.base_build < 26490)
567-
self.register_reader('replay.game.events', readers.GameEventsReader_26490(), lambda r: 26490 <= r.base_build)
567+
self.register_reader('replay.game.events', readers.GameEventsReader_26490(), lambda r: 26490 <= r.base_build < 27950)
568+
self.register_reader('replay.game.events', readers.GameEventsReader_27950(), lambda r: 27950 <= r.base_build)
568569
self.register_reader('replay.game.events', readers.GameEventsReader_HotSBeta(), lambda r: r.versions[1] == 2 and r.build < 24247)
569570

570-
571571
def register_default_datapacks(self):
572572
"""Registers factory default datapacks."""
573573
self.register_datapack(datapacks['WoL']['16117'], lambda r: r.expansion == 'WoL' and 16117 <= r.build < 17326)

0 commit comments

Comments
 (0)