Skip to content

Commit 6fdaf29

Browse files
authored
Merge pull request #14 from gravelweb/update-target
Add handler for command_update_target_unit_event
2 parents bdf3bc2 + 9fd95ac commit 6fdaf29

File tree

6 files changed

+67
-14
lines changed

6 files changed

+67
-14
lines changed

sc2reader/engine/plugins/context.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ def handleInitGame(self, event, replay):
1414
replay.units = set()
1515
replay.unit = dict()
1616

17+
# keep track of last TargetAbilityEvent for UpdateTargetAbilityEvent
18+
self.last_target_ability_event = {}
19+
1720
def handleGameEvent(self, event, replay):
1821
self.load_message_game_player(event, replay)
1922

@@ -25,6 +28,10 @@ def handleAbilityEvent(self, event, replay):
2528
return
2629

2730
if event.ability_id not in replay.datapack.abilities:
31+
# safeguard against missing abilities
32+
if event.player.pid in self.last_target_ability_event:
33+
del self.last_target_ability_event[event.player.pid]
34+
2835
if not getattr(replay, 'marked_error', None):
2936
replay.marked_error = True
3037
event.logger.error(replay.filename)
@@ -47,6 +54,8 @@ def handleAbilityEvent(self, event, replay):
4754
self.logger.error("Other unit {0} not found".format(event.other_unit_id))
4855

4956
def handleTargetAbilityEvent(self, event, replay):
57+
self.last_target_ability_event[event.player.pid] = event
58+
5059
if not replay.datapack:
5160
return
5261

@@ -62,6 +71,17 @@ def handleTargetAbilityEvent(self, event, replay):
6271
event.target = unit
6372
replay.objects[event.target_unit_id] = unit
6473

74+
def handleUpdateTargetAbilityEvent(self, event, replay):
75+
# We may not find a TargetAbilityEvent before finding an
76+
# UpdateTargetAbilityEvent, perhaps due to Missing Abilities in the
77+
# datapack
78+
if event.player.pid in self.last_target_ability_event:
79+
# store corresponding TargetAbilityEvent data in this event
80+
# currently using for *MacroTracker only, so only need ability name
81+
event.ability_name = self.last_target_ability_event[event.player.pid].ability_name
82+
83+
self.handleTargetAbilityEvent(event, replay)
84+
6585
def handleSelectionEvent(self, event, replay):
6686
if not replay.datapack:
6787
return

sc2reader/events/game.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,22 @@ def __init__(self, frame, pid, data):
339339
self.location = (self.x, self.y, self.z)
340340

341341

342+
class UpdateTargetAbilityEvent(TargetAbilityEvent):
343+
"""
344+
Extends :class:`TargetAbilityEvent`
345+
346+
This event is generated when a TargetAbilityEvent is updated, likely due to
347+
changing the target unit. It is unclear if this needs to be a separate event
348+
from TargetAbilityEvent, but for flexibility, it will be treated
349+
differently.
350+
351+
One example of this event occuring is casting inject on a hatchery while
352+
holding shift, and then shift clicking on a second hatchery.
353+
"""
354+
355+
name = 'UpdateTargetAbilityEvent'
356+
357+
342358
class SelfAbilityEvent(AbilityEvent):
343359
"""
344360
Extends :class:`AbilityEvent`

sc2reader/readers.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,7 +1525,7 @@ def __init__(self):
15251525
61: (None, self.trigger_hotkey_pressed_event),
15261526
103: (None, self.command_manager_state_event),
15271527
104: (None, self.command_update_target_point_event),
1528-
105: (None, self.command_update_target_unit_event),
1528+
105: (UpdateTargetAbilityEvent, self.command_update_target_unit_event),
15291529
106: (None, self.trigger_anim_length_query_by_name_event),
15301530
107: (None, self.trigger_anim_length_query_by_props_event),
15311531
108: (None, self.trigger_anim_offset_event),
@@ -1596,19 +1596,24 @@ def command_update_target_point_event(self, data):
15961596

15971597
def command_update_target_unit_event(self, data):
15981598
return dict(
1599-
target=dict(
1600-
target_unit_flags=data.read_uint16(),
1599+
flags=0, # fill me with previous TargetUnitEvent.flags
1600+
ability=None, # fill me with previous TargetUnitEvent.ability
1601+
data=('TargetUnit', dict(
1602+
flags=data.read_uint16(),
16011603
timer=data.read_uint8(),
1602-
tag=data.read_uint32(),
1603-
snapshot_unit_link=data.read_uint16(),
1604-
snapshot_control_player_id=data.read_bits(4) if data.read_bool() else None,
1605-
snapshot_upkeep_player_id=data.read_bits(4) if data.read_bool() else None,
1606-
snapshot_point=dict(
1604+
unit_tag=data.read_uint32(),
1605+
unit_link=data.read_uint16(),
1606+
control_player_id=data.read_bits(4) if data.read_bool() else None,
1607+
upkeep_player_id=data.read_bits(4) if data.read_bool() else None,
1608+
point=dict(
16071609
x=data.read_bits(20),
16081610
y=data.read_bits(20),
16091611
z=data.read_bits(32) - 2147483648,
1610-
)
1611-
)
1612+
),
1613+
)),
1614+
sequence=0, # fill me with previous TargetUnitEvent.flags
1615+
other_unit_tag=None, # fill me with previous TargetUnitEvent.flags
1616+
unit_group=None, # fill me with previous TargetUnitEvent.flags
16121617
)
16131618

16141619
def command_event(self, data):
61.2 KB
Binary file not shown.
50.2 KB
Binary file not shown.

test_replays/test_all.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,12 +495,24 @@ def test_33(self):
495495
replay = sc2reader.load_replay("test_replays/3.3.0/{}.SC2Replay".format(replaynum))
496496
self.assertTrue(replay is not None)
497497

498+
def test_33_shift_click_calldown_mule(self):
499+
replay = sc2reader.load_replay("test_replays/3.3.0/ggissue48.SC2Replay")
500+
def efilter(e):
501+
return hasattr(e, "ability") and e.ability_name == "CalldownMULE"
502+
self.assertEqual(len(filter(efilter, replay.events)), 29)
503+
504+
def test_33_shift_click_spawn_larva(self):
505+
replay = sc2reader.load_replay("test_replays/3.3.0/ggissue49.SC2Replay")
506+
def efilter(e):
507+
return hasattr(e, "ability") and e.ability_name == "SpawnLarva"
508+
self.assertEqual(len(filter(efilter, replay.events)), 23)
509+
498510
def test_lotv_time(self):
499-
replay = sc2reader.load_replay("test_replays/lotv/lotv1.SC2Replay")
500-
self.assertEqual(replay.length.seconds, 1002)
501-
self.assertEqual(replay.real_length.seconds, 1002)
511+
replay = sc2reader.load_replay("test_replays/lotv/lotv1.SC2Replay")
512+
self.assertEqual(replay.length.seconds, 1002)
513+
self.assertEqual(replay.real_length.seconds, 1002)
514+
502515

503-
504516
class TestGameEngine(unittest.TestCase):
505517
class TestEvent(object):
506518
name='TestEvent'

0 commit comments

Comments
 (0)