Skip to content

Commit 1511ed9

Browse files
committed
Performance improvements for SelectionTracker.
1 parent 3c098c6 commit 1511ed9

File tree

2 files changed

+34
-24
lines changed

2 files changed

+34
-24
lines changed

sc2reader/plugins/replay.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,45 +97,49 @@ def APMTracker(replay):
9797

9898
@plugin
9999
def SelectionTracker(replay):
100+
debug = replay.opt.debug
100101
logger = log_utils.get_logger(SelectionTracker)
101102
efilter = lambda e: isinstance(e, SelectionEvent) or isinstance(e, HotkeyEvent)
102103

103104
for person in replay.people:
104105
# TODO: A more robust person interface might be nice
105106
person.selection_errors = 0
106-
person.selection = GameState(PlayerSelection())
107+
player_selection = GameState(PlayerSelection())
107108
for event in filter(efilter, person.events):
108-
if replay.opt.debug:
109-
logger.debug("Event bytes: "+event.bytes.encode("hex"))
109+
if debug: logger.debug("Event bytes: "+event.bytes.encode("hex"))
110110

111111
error = False
112-
selection = person.selection[event.frame]
112+
selection = player_selection[event.frame]
113113

114-
if isinstance(event, SetToHotkeyEvent):
115-
# Make a copy to decouple the hotkey from primary selection
116-
selection[event.hotkey] = selection[0x0A].copy()
117-
logger.info("[{0}] {1} set hotkey {2} to current selection".format(Length(seconds=event.second),person.name,event.hotkey))
118-
119-
elif isinstance(event, AddToHotkeyEvent):
120-
error = not selection[event.hotkey].deselect(*event.deselect)
121-
selection[event.hotkey].select(selection[0x0A].objects)
122-
logger.info("[{0}] {1} added current selection to hotkey {2}".format(Length(seconds=event.second),person.name,event.hotkey))
114+
if isinstance(event, SelectionEvent):
115+
error = not selection[0x0A].deselect(*event.deselect)
116+
selection[0x0A].select(event.objects)
117+
if debug: logger.info("[{0}] {1} selected {2} units: {3}".format(Length(seconds=event.second),person.name,len(selection[0x0A].objects),selection[0x0A]))
123118

124119
elif isinstance(event, GetFromHotkeyEvent):
125120
# For some reason they leave the hotkey buffer unmodified so make a copy
126121
selection[0x0A] = selection[event.hotkey].copy()
127122
error = not selection[0x0A].deselect(*event.deselect)
128-
logger.info("[{0}] {1} retrieved hotkey {2}, {3} units: {4}".format(Length(seconds=event.second),person.name,event.hotkey,len(selection[0x0A].objects),selection[0x0A]))
123+
if debug: logger.info("[{0}] {1} retrieved hotkey {2}, {3} units: {4}".format(Length(seconds=event.second),person.name,event.hotkey,len(selection[0x0A].objects),selection[0x0A]))
129124

130-
elif isinstance(event, SelectionEvent):
131-
error = not selection[0x0A].deselect(*event.deselect)
132-
selection[0x0A].select(event.objects)
133-
logger.info("[{0}] {1} selected {2} units: {3}".format(Length(seconds=event.second),person.name,len(selection[0x0A].objects),selection[0x0A]))
125+
elif isinstance(event, SetToHotkeyEvent):
126+
# Make a copy to decouple the hotkey from primary selection
127+
selection[event.hotkey] = selection[0x0A].copy()
128+
if debug: logger.info("[{0}] {1} set hotkey {2} to current selection".format(Length(seconds=event.second),person.name,event.hotkey))
129+
130+
elif isinstance(event, AddToHotkeyEvent):
131+
error = not selection[event.hotkey].deselect(*event.deselect)
132+
selection[event.hotkey].select(selection[0x0A].objects)
133+
if debug: logger.info("[{0}] {1} added current selection to hotkey {2}".format(Length(seconds=event.second),person.name,event.hotkey))
134134

135135
# TODO: The event level interface here should be improved
136136
# Possibly use 'added' and 'removed' unit lists as well
137137
event.selected = selection[0x0A].objects
138138
if error:
139139
person.selection_errors += 1
140-
if replay.opt.debug:
140+
if debug:
141141
logger.warn("Error detected in deselection mode {}.".format(event.deselect[0]))
142+
143+
person.selection = player_selection
144+
# Not a real lock, so don't change it!
145+
person.selection.locked = True

sc2reader/plugins/utils.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from functools import wraps
99
from bisect import bisect_left
10+
from collections import defaultdict
1011

1112
def plugin(func):
1213
@wraps(func)
@@ -31,6 +32,7 @@ def __init__(self, initial_state):
3132
self._frames = list()
3233
self._frameset = set()
3334
self[0] = initial_state
35+
self.locked = False
3436

3537
def __getitem__(self, frame):
3638
if frame in self:
@@ -46,8 +48,13 @@ def __getitem__(self, frame):
4648
else:
4749
prev_frame = self._frames[key]
4850

49-
# Copy the previous state and use it as our basis here
50-
state = self[prev_frame].copy()
51+
# If we've locked the game state we don't need deep copies anymore
52+
if self.locked:
53+
state = self[prev_frame]
54+
else:
55+
# Copy the previous state and use it as our basis here
56+
state = self[prev_frame].copy()
57+
5158
self[frame] = state
5259
return state
5360

@@ -105,10 +112,9 @@ def copy(self):
105112
return UnitSelection(self.objects[:])
106113

107114

108-
class PlayerSelection(dict):
115+
class PlayerSelection(defaultdict):
109116
def __init__(self):
110-
for bank in range(0x00, 0x0B):
111-
self[bank]=UnitSelection()
117+
super(PlayerSelection, self).__init__(UnitSelection)
112118

113119
def copy(self):
114120
new = PlayerSelection()

0 commit comments

Comments
 (0)