Skip to content

Commit 700eb39

Browse files
committed
A series of performance improvements for parsing.
1 parent 4c9dcac commit 700eb39

File tree

2 files changed

+68
-47
lines changed

2 files changed

+68
-47
lines changed

sc2reader/readers.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -232,21 +232,24 @@ def __call__(self, data, replay):
232232
data_length = data.length
233233
read_timestamp = data.read_timestamp
234234
read_bits = data.read_bits
235+
read_byte = data.read_byte
235236
read_bytes = data.read_bytes
236237
byte_align = data.byte_align
237238
append = game_events.append
238239
event_start = 0
239240

240241
try:
241242
while event_start != data_length:
242-
event = None
243243
fstamp += read_timestamp()
244244
pid = read_bits(5)
245245
event_type = read_bits(7)
246246

247247
# Check for a lookup
248248
if event_type in EVENT_DISPATCH:
249249
event = EVENT_DISPATCH[event_type](data, fstamp, pid, event_type)
250+
if debug:
251+
event.bytes = data.read_range(event_start, data.tell())
252+
append(event)
250253

251254
# Otherwise maybe it is an unknown chunk
252255
elif event_type == 0x26:
@@ -272,12 +275,6 @@ def __call__(self, data, replay):
272275
raise ReadError("Event type {} unknown at position {}.".format(hex(event_type),hex(event_start)), event_type, event_start, replay, game_events, data)
273276

274277
byte_align()
275-
276-
if event:
277-
if debug:
278-
event.bytes = data.read_range(event_start, data.tell())
279-
append(event)
280-
281278
event_start = data.tell()
282279

283280
return game_events
@@ -320,7 +317,7 @@ def player_selection_event(self, data, fstamp, pid, event_type):
320317
unit_types = [(data.read_short(BIG_ENDIAN) << 8 | data.read_byte(),data.read_bits(self.UNIT_INDEX_BITS)) for index in range(type_count)]
321318

322319
unit_count = data.read_bits(self.UNIT_INDEX_BITS)
323-
unit_ids = [data.read_bits(32) for index in range(unit_count)]
320+
unit_ids = [data.read_int(BIG_ENDIAN) for index in range(unit_count)]
324321

325322
unit_types = chain(*[[utype]*count for (utype, count) in unit_types])
326323
units = list(zip(unit_ids, unit_types))
@@ -364,21 +361,22 @@ def player_request_resource_event(self, data, fstamp, pid, event_type):
364361

365362
def camera_event(self, data, fstamp, pid, event_type):
366363
# From https://github.com/Mischanix/sc2replay-csharp/wiki/replay.game.events
367-
x = data.read_bits(16)/256.0
368-
y = data.read_bits(16)/256.0
364+
block = data.read_int(BIG_ENDIAN)
365+
x = (block >> 16)/256.0
366+
y = (block & 0xFFFF)/256.0
369367
distance = pitch = yaw = height = 0
370368
if data.read_bits(1):
371-
distance = data.read_bits(16)/256.0
369+
distance = data.read_short(BIG_ENDIAN)/256.0
372370
if data.read_bits(1):
373371
#Note: this angle is relative to the horizontal plane, but the editor shows the angle relative to the vertical plane. Subtract from 90 degrees to convert.
374-
pitch = data.read_bits(16) #?
372+
pitch = data.read_short(BIG_ENDIAN) #?
375373
pitch = 45 * (((((pitch * 0x10 - 0x2000) << 17) - 1) >> 17) + 1) / 4096.0
376374
if data.read_bits(1):
377375
#Note: this angle is the vector from the camera head to the camera target projected on to the x-y plane in positive coordinates. So, default is 90 degrees, while insert and delete produce 45 and 135 degrees by default.
378-
yaw = data.read_bits(16) #?
376+
yaw = data.read_short(BIG_ENDIAN) #?
379377
yaw = 45 * (((((yaw * 0x10 - 0x2000) << 17) - 1) >> 17) + 1) / 4096.0
380378
if data.read_bits(1):
381-
height_offset = data.read_bits(16)/256.0
379+
height_offset = data.read_short(BIG_ENDIAN)/256.0
382380
return CameraEvent(fstamp, pid, event_type, x, y, distance, pitch, yaw, height)
383381

384382

@@ -421,7 +419,7 @@ def player_ability_event(self, data, fstamp, pid, event_type):
421419

422420
default_ability = not data.read_bits(1)
423421
if not default_ability:
424-
ability = data.read_bits(16) << 5 | data.read_bits(5)
422+
ability = data.read_short(BIG_ENDIAN) << 5 | data.read_bits(5)
425423
default_actor = not data.read_bits(1)
426424
else:
427425
ability = 0
@@ -430,17 +428,17 @@ def player_ability_event(self, data, fstamp, pid, event_type):
430428
if target_type == 1:
431429
x = data.read_bits(20)/4096.0
432430
y = data.read_bits(20)/4096.0
433-
z = data.read_bits(32)
431+
z = data.read_int(BIG_ENDIAN)
434432
z = (z>>1)/8192.0 * pow(-1, z & 0x1)
435433
unknown = data.read_bits(1)
436434
return LocationAbilityEvent(fstamp, pid, event_type, ability, (x, y, z))
437435

438436
elif target_type == 2:
439437
player = team = None
440438

441-
data.read_bits(8)
442-
data.read_bits(8)
443-
unit = (data.read_bits(32), data.read_bits(16))
439+
data.read_byte()
440+
data.read_byte()
441+
unit = (data.read_int(BIG_ENDIAN), data.read_short(BIG_ENDIAN))
444442

445443
if self.ABILITY_TEAM_FLAG and data.read_bits(1):
446444
team = data.read_bits(4)
@@ -450,13 +448,13 @@ def player_ability_event(self, data, fstamp, pid, event_type):
450448

451449
x = data.read_bits(20)/4096.0
452450
y = data.read_bits(20)/4096.0
453-
z = data.read_bits(32)
451+
z = data.read_int(BIG_ENDIAN)
454452
z = (z>>1)/8192.0 * pow(-1, z & 0x1)
455453
unknown = data.read_bits(1)
456454
return TargetAbilityEvent(fstamp, pid, event_type, ability, unit, player, team, (x, y, z))
457455

458456
elif target_type == 3:
459-
unit_id = data.read_bits(32)
457+
unit_id = data.read_int(BIG_ENDIAN)
460458
unknown = data.read_bits(1)
461459
return SelfAbilityEvent(fstamp, pid, event_type, ability, unit_id)
462460

sc2reader/utils.py

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ def peek(self, length):
126126
Optimized bit-shift aware read methods
127127
'''
128128
def read_byte(self):
129-
if self.bytes_left() == 0:
130-
raise EOFError("Cannot read byte; no bytes remaining")
129+
#if self.bytes_left() == 0:
130+
# raise EOFError("Cannot read byte; no bytes remaining")
131131

132132
if self.bit_shift==0:
133133
return ord(self.read(1))
@@ -139,8 +139,8 @@ def read_byte(self):
139139
return hi_bits | lo_bits
140140

141141
def read_short(self, endian=LITTLE_ENDIAN):
142-
if self.bytes_left() < 2:
143-
raise EOFError("Cannot read short; only {} bytes left in buffer".format(self.left))
142+
#if self.bytes_left() < 2:
143+
# raise EOFError("Cannot read short; only {} bytes left in buffer".format(self.left))
144144

145145
if self.bit_shift == 0:
146146
return struct.unpack(endian+'H', self.read(2))[0]
@@ -156,8 +156,8 @@ def read_short(self, endian=LITTLE_ENDIAN):
156156
return number
157157

158158
def read_int(self, endian=LITTLE_ENDIAN):
159-
if self.bytes_left() < 4:
160-
raise EOFError("Cannot read int; only {} bytes left in buffer".format(self.left))
159+
#if self.bytes_left() < 4:
160+
# raise EOFError("Cannot read int; only {} bytes left in buffer".format(self.left))
161161

162162
if self.bit_shift == 0:
163163
return struct.unpack(endian+'I', self.read(4))[0]
@@ -173,34 +173,60 @@ def read_int(self, endian=LITTLE_ENDIAN):
173173
return number
174174

175175
def read_bits(self, bits):
176-
if self.bytes_left()*8 < bits-(8-self.bit_shift):
177-
raise EOFError("Cannot read {} bits. only {} bits left in buffer.".format(bits, (self.length-self.tell()+1)*8-self.bit_shift))
178-
179-
if self.bit_shift!=0:
180-
first_bits = min(8-self.bit_shift, bits)
181-
bits = bits-first_bits
182-
mask = self.lo_masks[first_bits] << self.bit_shift
183-
result = ((self.bit_buffer & mask) >> self.bit_shift) << bits
184-
self.bit_shift = (self.bit_shift + first_bits) % 8
176+
#if self.bytes_left()*8 < bits-(8-self.bit_shift):
177+
# raise EOFError("Cannot read {} bits. only {} bits left in buffer.".format(bits, (self.length-self.tell()+1)*8-self.bit_shift))
178+
bit_shift = self.bit_shift
179+
if bit_shift!=0:
180+
bits_left = 8-bit_shift
181+
182+
# Read it all and continue
183+
if bits_left < bits:
184+
bits -= bits_left
185+
result = (self.bit_buffer >> bit_shift) << bits
186+
187+
# Read part and return
188+
elif bits_left > bits:
189+
self.bit_shift+=bits
190+
return (self.bit_buffer >> bit_shift) & self.lo_masks[bits]
191+
192+
# Read all and return
193+
else:
194+
self.bit_shift = 0
195+
return self.bit_buffer >> bit_shift
196+
185197
else:
186198
result = 0
187199

188-
if bits > 8:
200+
if bits >= 8:
189201
bytes = bits/8
190-
for byte in struct.unpack("B"*bytes, self.read(bytes)):
202+
203+
if bytes == 1:
191204
bits -= 8
192-
result |= byte << bits
205+
result |= ord(self.read(1)) << bits
206+
207+
elif bytes == 2:
208+
bits -= 16
209+
result |= struct.unpack(">H",self.read(2))[0] << bits
210+
211+
elif bytes == 4:
212+
bits -= 32
213+
result |= struct.unpack(">I",self.read(4))[0] << bits
214+
215+
else:
216+
for byte in struct.unpack("B"*bytes, self.read(bytes)):
217+
bits -= 8
218+
result |= byte << bits
193219

194220
if bits != 0:
195-
self.bit_shift = bits
196221
self.bit_buffer = ord(self.read(1))
197222
result |= self.bit_buffer & self.lo_masks[bits]
198223

224+
self.bit_shift = bits
199225
return result
200226

201227
def read_bytes(self, bytes):
202-
if self.bytes_left() < bytes:
203-
raise EOFError("Cannot read {} bytes. only {} bytes left in buffer.".format(bytes, self.length-self.tell()))
228+
#if self.bytes_left() < bytes:
229+
# raise EOFError("Cannot read {} bytes. only {} bytes left in buffer.".format(bytes, self.length-self.tell()))
204230

205231
if self.bit_shift==0:
206232
return self.read(bytes)
@@ -251,19 +277,16 @@ def read_timestamp(self):
251277
The least significant 2 bits of the first byte specify how many extra
252278
bytes the timestamp has.
253279
"""
254-
return self.read_bits(self.read_bits(2)*8+6)
255-
"""faster???
256280
first = self.read_byte()
257281
time,count = first >> 2, first & 0x03
258282
if count == 0:
259283
return time
260284
elif count == 1:
261285
return time << 8 | self.read_byte()
262286
elif count == 2:
263-
return time << 16 | self.read_short()
287+
return time << 16 | self.read_short(BIG_ENDIAN)
264288
elif count == 3:
265-
return time << 24 | self.read_short() << 8 | self.read_byte()
266-
"""
289+
return time << 24 | self.read_short(BIG_ENDIAN) << 8 | self.read_byte()
267290

268291
def read_data_struct(self, indent=0, key=None):
269292
"""

0 commit comments

Comments
 (0)