Skip to content

Commit 93c4275

Browse files
committed
Small event documentation improvements.
1 parent 7a7f72e commit 93c4275

File tree

5 files changed

+201
-42
lines changed

5 files changed

+201
-42
lines changed

docs/source/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
import sys, os
1515

16+
autodoc_member_order = "bysource"
17+
1618
# If extensions (or modules to document with autodoc) are in another directory,
1719
# add these directories to sys.path here. If the directory is relative to the
1820
# documentation root, use os.path.abspath to make it absolute, like shown here.

docs/source/events/game.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
Game Events
44
=============
55

6-
Coming soon!
6+
Game events are what the Starcraft II engine uses to reconstruct games for you to watch
7+
and take over in. Because the game is deterministic, only event data directly created by
8+
a player action is recorded. These player actions are then replayed automatically when
9+
watching a replay. Because the AI is 100% deterministic no events are ever recorded for a
10+
computer player.
711

812
.. automodule:: sc2reader.events.game
913
:members:

docs/source/events/tracker.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Tracker Events
44
=====================
55

6+
Tracker events are new in Starcraft patch 2.0.8. These events are generated by
7+
the game engine when important non-player events occur in the game. Some of them
8+
are also periodically recorded to snapshot aspects of the current game state.
9+
610
.. automodule:: sc2reader.events.tracker
711
:members:
812
:undoc-members:

sc2reader/events/game.py

Lines changed: 185 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,28 @@
1010

1111
@loggable
1212
class GameEvent(Event):
13+
"""
14+
This is the base class for all game events. The attributes below are universally available.
15+
"""
1316
name = 'GameEvent'
1417

1518
def __init__(self, frame, pid):
19+
#: The id of the player generating the event. This is 16 for global non-player events.
20+
#: Prior to Heart of the Swarm this was the player id. Since HotS it is
21+
#: now the user id (uid), we still call it pid for backwards compatibility.
1622
self.pid = pid
23+
24+
#: A reference to the :class:`~sc2reader.objects.Player` object representing
25+
#: this player in the replay. Not available for global events (:attr:`pid` = 16)
26+
self.player = None
27+
28+
#: The frame of the game that this event was recorded at. 16 frames per game second.
1729
self.frame = frame
30+
31+
#: The second of the game that this event was recorded at. 16 frames per game second.
1832
self.second = frame >> 4
33+
34+
#: A flag indicating if it is a local or global event.
1935
self.is_local = (pid != 16)
2036

2137
def _str_prefix(self):
@@ -27,20 +43,34 @@ def __str__(self):
2743

2844

2945
class GameStartEvent(GameEvent):
46+
"""
47+
Recorded when the game starts and the frames start to roll. This is a global non-player
48+
event.
49+
"""
50+
3051
name = 'GameStartEvent'
3152

3253
def __init__(self, frame, pid, data):
3354
super(GameStartEvent, self).__init__(frame, pid)
3455

3556

3657
class PlayerLeaveEvent(GameEvent):
58+
"""
59+
Recorded when a player leaves the game.
60+
"""
61+
3762
name = 'PlayerLeaveEvent'
3863

3964
def __init__(self, frame, pid, data):
4065
super(PlayerLeaveEvent, self).__init__(frame, pid)
4166

4267

4368
class UserOptionsEvent(GameEvent):
69+
"""
70+
This event is recorded for each player at the very beginning of the game before the
71+
:class:`GameStartEvent`.
72+
"""
73+
4474
name = 'UserOptionsEvent'
4575

4676
def __init__(self, frame, pid, data):
@@ -94,7 +124,18 @@ class PlayerActionEvent(GameEvent):
94124

95125
@loggable
96126
class AbilityEvent(PlayerActionEvent):
127+
"""
128+
Ability events are generated when ever a player in the game issues a command
129+
to a unit or group of units. They are split into three subclasses of ability,
130+
each with their own set of associated data. The attributes listed below are
131+
shared across all ability event types.
132+
133+
See :class:`LocationAbilityEvent`, :class:`TargetAbilityEvent`, and :class:`SelfAbilityEvent`
134+
for individual details.
135+
"""
136+
97137
name = 'AbilityEvent'
138+
98139
is_player_action = True
99140

100141
def __init__(self, frame, pid, data):
@@ -157,47 +198,8 @@ def __init__(self, frame, pid, data):
157198
#: The type of ability, one of: None (no target), TargetPoint, TargetUnit, or Data
158199
self.ability_type = data['data'][0]
159200

160-
ability_type_data = data['data'][1]
161-
162-
if self.ability_type == 'TargetUnit':
163-
#: Flags set on the target unit. Available for TargetUnit type events
164-
self.target_flags = ability_type_data.get('flags', None)
165-
166-
#: Timer?? Available for TargetUnit type events.
167-
self.target_timer = ability_type_data.get('timer', None)
168-
169-
#: Unique id of the target unit. Available for TargetUnit type events.
170-
self.target_unit_id = ability_type_data.get('unit_tag', None)
171-
172-
#: A reference to the targetted unit
173-
self.target_unit = None
174-
175-
#: Current integer type id of the target unit. Available for TargetUnit type events.
176-
self.target_unit_type = ability_type_data.get('unit_link', None)
177-
178-
#: Integer player id of the controlling player. Available for TargetUnit type events starting in 19595.
179-
#: When the targetted unit is under fog of war this id is zero.
180-
self.control_player_id = ability_type_data.get('control_player_id', None)
181-
182-
#: Integer player id of the player paying upkeep. Available for TargetUnit type events.
183-
self.upkeep_player_id = ability_type_data.get('upkeep_player_id', None)
184-
185-
if self.ability_type in ('TargetPoint', 'TargetUnit'):
186-
#: The x coordinate of the target. Available for TargetPoint and TargetUnit type events.
187-
self.x = ability_type_data['point'].get('x', 0)/4096.0
188-
189-
#: The y coordinate of the target. Available for TargetPoint and TargetUnit type events.
190-
self.y = ability_type_data['point'].get('y', 0)/4096.0
191-
192-
#: The z coordinate of the target. Available for TargetPoint and TargetUnit type events.
193-
self.z = ability_type_data['point'].get('z', 0)
194-
195-
#: The location of the target. Available for TargetPoint and TargetUnit type events
196-
self.location = (self.x, self.y, self.z)
197-
198-
if self.ability_type == 'Data':
199-
#: Other target data. Available for Data type events.
200-
self.target_data = ability_type_data.get('data', None)
201+
#: The raw data associated with this ability type
202+
self.ability_type_data = data['data'][1]
201203

202204
#: Other unit id??
203205
self.other_unit_id = data['other_unit_tag']
@@ -224,19 +226,118 @@ def __str__(self):
224226

225227

226228
class LocationAbilityEvent(AbilityEvent):
229+
"""
230+
Extends :class:`AbilityEvent`
231+
232+
This event is recorded when ever a player issues a command that targets a location
233+
and NOT a unit. Commands like Psistorm, Attack Move, Fungal Growth, and EMP fall
234+
under this category.
235+
236+
Note that like all AbilityEvents, the event will be recorded regardless
237+
of whether or not the command was successful.
238+
"""
239+
227240
name = 'LocationAbilityEvent'
228241

242+
def __init__(self, frame, pid, data):
243+
super(LocationAbilityEvent, self).__init__(frame, pid, data)
244+
245+
#: The x coordinate of the target. Available for TargetPoint and TargetUnit type events.
246+
self.x = self.ability_type_data['point'].get('x', 0)/4096.0
247+
248+
#: The y coordinate of the target. Available for TargetPoint and TargetUnit type events.
249+
self.y = self.ability_type_data['point'].get('y', 0)/4096.0
250+
251+
#: The z coordinate of the target. Available for TargetPoint and TargetUnit type events.
252+
self.z = self.ability_type_data['point'].get('z', 0)
253+
254+
#: The location of the target. Available for TargetPoint and TargetUnit type events
255+
self.location = (self.x, self.y, self.z)
256+
229257

230258
class TargetAbilityEvent(AbilityEvent):
259+
"""
260+
Extends :class:`AbilityEvent`
261+
262+
TargetAbilityEvents are recorded when ever a player issues a command that targets a unit.
263+
The location of the target unit at the time of the command is also recorded. Commands like
264+
Chronoboost, Transfuse, and Snipe fall under this category.
265+
266+
Note that all AbilityEvents are recorded regardless of whether or not the command was successful.
267+
"""
268+
231269
name = 'TargetAbilityEvent'
232270

271+
def __init__(self, frame, pid, data):
272+
super(TargetAbilityEvent, self).__init__(frame, pid, data)
273+
274+
#: Flags set on the target unit. Available for TargetUnit type events
275+
self.target_flags = self.ability_type_data.get('flags', None)
276+
277+
#: Timer?? Available for TargetUnit type events.
278+
self.target_timer = self.ability_type_data.get('timer', None)
279+
280+
#: Unique id of the target unit. Available for TargetUnit type events.
281+
self.target_unit_id = self.ability_type_data.get('unit_tag', None)
282+
283+
#: A reference to the targetted unit
284+
self.target_unit = None
285+
286+
#: Current integer type id of the target unit. Available for TargetUnit type events.
287+
self.target_unit_type = self.ability_type_data.get('unit_link', None)
288+
289+
#: Integer player id of the controlling player. Available for TargetUnit type events starting in 19595.
290+
#: When the targetted unit is under fog of war this id is zero.
291+
self.control_player_id = self.ability_type_data.get('control_player_id', None)
292+
293+
#: Integer player id of the player paying upkeep. Available for TargetUnit type events.
294+
self.upkeep_player_id = self.ability_type_data.get('upkeep_player_id', None)
295+
296+
#: The x coordinate of the target. Available for TargetPoint and TargetUnit type events.
297+
self.x = self.ability_type_data['point'].get('x', 0)/4096.0
298+
299+
#: The y coordinate of the target. Available for TargetPoint and TargetUnit type events.
300+
self.y = self.ability_type_data['point'].get('y', 0)/4096.0
301+
302+
#: The z coordinate of the target. Available for TargetPoint and TargetUnit type events.
303+
self.z = self.ability_type_data['point'].get('z', 0)
304+
305+
#: The location of the target. Available for TargetPoint and TargetUnit type events
306+
self.location = (self.x, self.y, self.z)
307+
233308

234309
class SelfAbilityEvent(AbilityEvent):
310+
"""
311+
Extends :class:`AbilityEvent`
312+
313+
SelfAbilityEvents are recorded when ever a player issues a command that has no target. Commands
314+
like Burrow, SeigeMode, Train XYZ, and Stop fall under this category.
315+
316+
Note that all AbilityEvents are recorded regardless of whether or not the command was successful.
317+
"""
318+
235319
name = 'SelfAbilityEvent'
236320

321+
def __init__(self, frame, pid, data):
322+
super(SelfAbilityEvent, self).__init__(frame, pid, data)
323+
324+
#: Other target data. Available for Data type events.
325+
self.target_data = self.ability_type_data.get('data', None)
326+
237327

238328
@loggable
239329
class SelectionEvent(PlayerActionEvent):
330+
"""
331+
Selection events are generated when ever the active selection of the
332+
player is updated. Unlike other game events, these events can also be
333+
generated by non-player actions like unit deaths or transformations.
334+
335+
Starting in Starcraft 2.0.0, selection events targetting control group
336+
buffers are also generated when control group selections are modified
337+
by non-player actions. When a player action updates a control group
338+
a :class:`HotkeyEvent` is generated.
339+
"""
340+
240341
name = 'SelectionEvent'
241342
is_player_action = True
242343

@@ -300,6 +401,22 @@ def create_control_group_event(frame, pid, data):
300401

301402
@loggable
302403
class HotkeyEvent(PlayerActionEvent):
404+
"""
405+
Hotkey events are recorded when ever a player action modifies a control
406+
group. I know that calling control group events hotkey events doesn't make
407+
sense but for backwards compatibility I haven't changed it yet. Sorry.
408+
409+
There are three kinds of hotkey events, generated by each of the possible
410+
player actions:
411+
412+
* :class:`SetToHotkeyEvent` - Recorded when a user sets a control group (ctrl+#).
413+
* :class:`GetFromHotkeyEvent` - Recorded when a user retrieves a control group (#).
414+
* :class:`AddToHotkeyEvent` - Recorded when a user adds to a control group (shift+ctrl+#)
415+
416+
All three events have the same set of data (shown below) but are interpretted differently.
417+
See the class entry for details.
418+
"""
419+
303420
name = 'HotkeyEvent'
304421
is_player_action = True
305422

@@ -326,19 +443,46 @@ def __init__(self, frame, pid, data):
326443

327444

328445
class SetToHotkeyEvent(HotkeyEvent):
446+
"""
447+
Extends :class:`HotkeyEvent`
448+
449+
This event does a straight forward replace of the current control group contents
450+
with the player's current selection. This event doesn't have masks set.
451+
"""
452+
329453
name = 'SetToHotkeyEvent'
330454

331455

332456
class AddToHotkeyEvent(HotkeyEvent):
457+
"""
458+
Extends :class:`HotkeyEvent`
459+
460+
This event adds the current selection to the control group.
461+
"""
462+
333463
name = 'AddToHotkeyEvent'
334464

335465

336466
class GetFromHotkeyEvent(HotkeyEvent):
467+
"""
468+
Extends :class:`HotkeyEvent`
469+
This event replaces the current selection with the contents of the control group.
470+
The mask data is used to limit that selection to units that are currently selectable.
471+
You might have 1 medivac and 8 marines on the control group but if the 8 marines are
472+
inside the medivac they cannot be part of your selection.
473+
"""
474+
337475
name = 'GetFromHotkeyEvent'
338476

339477

340478
@loggable
341479
class CameraEvent(GameEvent):
480+
"""
481+
Camera events are generated when ever the player camera moves, zooms, or rotates.
482+
It does not matter why the camera changed, this event simply records the current
483+
state of the camera after changing.
484+
"""
485+
342486
name = 'CameraEvent'
343487

344488
def __init__(self, frame, pid, data):

sc2reader/events/tracker.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,11 @@ class UnitBornEvent(TrackerEvent):
217217
include the Marine, Zergling, and Zealot (when trained from a gateway).
218218
Units that enter the game unfinished (all buildings, warped in units) generate
219219
a :class:`UnitInitEvent` instead.
220+
221+
Unfortunately, units that are born do not have events marking their beginnings
222+
like :class:`UnitInitEvent` and :class:`UnitDoneEvent` do. The closest thing to
223+
it are the :class:`~sc2reader.event.game.AbilityEvent` game events where the ability
224+
is a train unit command.
220225
"""
221226

222227
name = 'UnitBornEvent'

0 commit comments

Comments
 (0)