Skip to content

Commit b2aac81

Browse files
committed
Initial pass at PTR 2.1 support.
1 parent ec238c9 commit b2aac81

File tree

3 files changed

+131
-29
lines changed

3 files changed

+131
-29
lines changed

sc2reader/events/tracker.py

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

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

2424
def __str__(self):
2525
return self._str_prefix() + self.name
2626

2727

28+
class PlayerSetupEvent(TrackerEvent):
29+
""" Sent during game setup to help us organize players better """
30+
def __init__(self, frames, data, build):
31+
super(PlayerSetupEvent, self).__init__(frames)
32+
33+
#: The player id of the player we are setting up
34+
self.pid = data[0]
35+
36+
#: The type of this player. One of 1=human, 2=cpu, 3=neutral, 4=hostile
37+
self.type = data[1]
38+
39+
#: The user id of the player we are setting up. None of not human
40+
self.uid = data[2]
41+
42+
#: The slot id of the player we are setting up. None if not playing
43+
self.sid = data[3]
44+
45+
2846
class PlayerStatsEvent(TrackerEvent):
2947
"""
3048
Player Stats events are generated for all players that were in the game
@@ -178,10 +196,10 @@ def __init__(self, frames, data, build):
178196
self.resources_killed = self.minerals_killed + self.vespene_killed
179197

180198
#: The food supply currently used
181-
self.food_used = clamp(self.stats[29])/4096.0
199+
self.food_used = clamp(self.stats[29]) / 4096.0
182200

183201
#: The food supply currently available
184-
self.food_made = clamp(self.stats[30])/4096.0
202+
self.food_made = clamp(self.stats[30]) / 4096.0
185203

186204
#: The total mineral value of all active forces
187205
self.minerals_used_active_forces = clamp(self.stats[31])
@@ -208,7 +226,7 @@ def __init__(self, frames, data, build):
208226
self.ff_vespene_lost_technology = clamp(self.stats[38]) if build >= 26490 else None
209227

210228
def __str__(self):
211-
return self._str_prefix()+"{0: >15} - Stats Update".format(self.player)
229+
return self._str_prefix() + "{0: >15} - Stats Update".format(self.player)
212230

213231

214232
class UnitBornEvent(TrackerEvent):
@@ -256,17 +274,24 @@ def __init__(self, frames, data, build):
256274
#: The player object that controls this unit. 0 means neutral unit
257275
self.unit_controller = None
258276

259-
#: The x coordinate of the location
260-
self.x = data[5] * 4
277+
#: The x coordinate of the center of the born unit's footprint. Only 4 point resolution
278+
#: prior to Starcraft Patch 2.1.
279+
self.x = data[5]
261280

262-
#: The y coordinate of the location
263-
self.y = data[6] * 4
281+
#: The y coordinate of the center of the born unit's footprint. Only 4 point resolution
282+
#: prior to Starcraft Patch 2.1.
283+
self.y = data[6]
264284

265285
#: The map location of the unit birth
266286
self.location = (self.x, self.y)
267287

288+
if build < 27950:
289+
self.x = self.x * 4
290+
self.y = self.y * 4
291+
self.location = (self.x, self.y)
292+
268293
def __str__(self):
269-
return self._str_prefix()+"{0: >15} - Unit born {1}".format(self.unit_upkeeper, self.unit)
294+
return self._str_prefix() + "{0: >15} - Unit born {1}".format(self.unit_upkeeper, self.unit)
270295

271296

272297
class UnitDiedEvent(TrackerEvent):
@@ -298,17 +323,39 @@ def __init__(self, frames, data, build):
298323
#: The player object of the that killed the unit. Not always available.
299324
self.killer = None
300325

301-
#: The x coordinate of the location
302-
self.x = data[3] * 4
326+
#: The x coordinate of the center of the dying unit's footprint. Only 4 point resolution
327+
#: prior to Starcraft Patch 2.1.
328+
self.x = data[3]
303329

304-
#: The y coordinate of the location
305-
self.y = data[4] * 4
330+
#: The y coordinate of the center of the dying unit's footprint. Only 4 point resolution
331+
#: prior to Starcraft Patch 2.1.
332+
self.y = data[4]
306333

307334
#: The map location the unit was killed at.
308335
self.location = (self.x, self.y)
309336

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

313360

314361
class UnitOwnerChangeEvent(TrackerEvent):
@@ -342,7 +389,7 @@ def __init__(self, frames, data, build):
342389
self.unit_controller = None
343390

344391
def __str__(self):
345-
return self._str_prefix()+"{0: >15} took {1}".format(self.unit_upkeeper, self.unit)
392+
return self._str_prefix() + "{0: >15} took {1}".format(self.unit_upkeeper, self.unit)
346393

347394

348395
class UnitTypeChangeEvent(TrackerEvent):
@@ -367,7 +414,7 @@ def __init__(self, frames, data, build):
367414
self.unit_type_name = data[2].decode('utf8')
368415

369416
def __str__(self):
370-
return self._str_prefix()+"{0: >15} - Unit {0} type changed to {1}".format(self.unit.owner, self.unit, self.unit_type_name)
417+
return self._str_prefix() + "{0: >15} - Unit {0} type changed to {1}".format(self.unit.owner, self.unit, self.unit_type_name)
371418

372419

373420
class UpgradeCompleteEvent(TrackerEvent):
@@ -389,7 +436,7 @@ def __init__(self, frames, data, build):
389436
self.count = data[2]
390437

391438
def __str__(self):
392-
return self._str_prefix()+"{0: >15} - {1}upgrade completed".format(self.player, self.upgrade_type_name)
439+
return self._str_prefix() + "{0: >15} - {1}upgrade completed".format(self.player, self.upgrade_type_name)
393440

394441

395442
class UnitInitEvent(TrackerEvent):
@@ -432,17 +479,24 @@ def __init__(self, frames, data, build):
432479
#: The player object that controls this unit. 0 means neutral unit
433480
self.unit_controller = None
434481

435-
#: The x coordinate of the location
436-
self.x = data[5] * 4
482+
#: The x coordinate of the center of the init unit's footprint. Only 4 point resolution
483+
#: prior to Starcraft Patch 2.1.
484+
self.x = data[5]
437485

438-
#: The y coordinate of the location
439-
self.y = data[6] * 4
486+
#: The y coordinate of the center of the init unit's footprint. Only 4 point resolution
487+
#: prior to Starcraft Patch 2.1.
488+
self.y = data[6]
440489

441490
#: The map location the unit was started at
442491
self.location = (self.x, self.y)
443492

493+
if build < 27950:
494+
self.x = self.x * 4
495+
self.y = self.y * 4
496+
self.location = (self.x, self.y)
497+
444498
def __str__(self):
445-
return self._str_prefix()+"{0: >15} - Unit initiated {1}".format(self.unit_upkeeper, self.unit)
499+
return self._str_prefix() + "{0: >15} - Unit initiated {1}".format(self.unit_upkeeper, self.unit)
446500

447501

448502
class UnitDoneEvent(TrackerEvent):
@@ -470,7 +524,7 @@ def __init__(self, frames, data, build):
470524
self.unit = None
471525

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

475529

476530
class UnitPositionsEvent(TrackerEvent):
@@ -488,15 +542,20 @@ def __init__(self, frames, data, build):
488542
#: A dict mapping of units that had their position updated to their positions
489543
self.units = dict()
490544

491-
#: A list of (unit_index, (x,y)) derived from the first_unit_index and items
545+
#: A list of (unit_index, (x,y)) derived from the first_unit_index and items. Prior to
546+
#: Starcraft Patch 2.1 the coordinates have 4 point resolution. (15,25) recorded as (12,24).
547+
#: Location prior to any rounding marks the center of the unit footprint.
492548
self.positions = list()
493549

494550
unit_index = self.first_unit_index
495551
for i in range(0, len(self.items), 3):
496552
unit_index += self.items[i]
497-
x = self.items[i+1]*4
498-
y = self.items[i+2]*4
553+
x = self.items[i + 1]
554+
y = self.items[i + 2]
555+
if build < 27950:
556+
x = x * 4
557+
y = y * 4
499558
self.positions.append((unit_index, (x, y)))
500559

501560
def __str__(self):
502-
return self._str_prefix()+"Unit positions update"
561+
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
@@ -553,10 +553,10 @@ def register_default_readers(self):
553553
self.register_reader('replay.game.events', readers.GameEventsReader_22612(), lambda r: 22612 <= r.base_build < 23260)
554554
self.register_reader('replay.game.events', readers.GameEventsReader_23260(), lambda r: 23260 <= r.base_build < 24247)
555555
self.register_reader('replay.game.events', readers.GameEventsReader_24247(), lambda r: 24247 <= r.base_build < 26490)
556-
self.register_reader('replay.game.events', readers.GameEventsReader_26490(), lambda r: 26490 <= r.base_build)
556+
self.register_reader('replay.game.events', readers.GameEventsReader_26490(), lambda r: 26490 <= r.base_build < 27950)
557+
self.register_reader('replay.game.events', readers.GameEventsReader_27950(), lambda r: 27950 <= r.base_build)
557558
self.register_reader('replay.game.events', readers.GameEventsReader_HotSBeta(), lambda r: r.versions[1] == 2 and r.build < 24247)
558559

559-
560560
def register_default_datapacks(self):
561561
"""Registers factory default datapacks."""
562562
self.register_datapack(datapacks['WoL']['16117'], lambda r: r.expansion == 'WoL' and 16117 <= r.build < 17326)

0 commit comments

Comments
 (0)