Skip to content

Commit 0d1e6b8

Browse files
committed
All event.apply functions except the AbilityEvent one are working. Its almost safe to say that obslib has been successfully digested
1 parent d1b461e commit 0d1e6b8

File tree

4 files changed

+96
-46
lines changed

4 files changed

+96
-46
lines changed

sc2reader/data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def visit(self, timestamp, player, object_type=None):
154154
# TODO siege tanks should not auto-assign
155155
self.morph_to(object_type, timestamp)
156156

157-
if not player.is_observer and not self.player:
157+
if not player.is_obs and not self.player:
158158
self.player = player
159159

160160
def morph_to(self, cls, timestamp):

sc2reader/objects.py

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from constants import races
22
from collections import defaultdict
3-
from sc2reader.utils import PersonDict
3+
44
from sc2reader.constants import *
5+
from sc2reader.data import GameObject, ABILITIES
6+
from sc2reader.utils import PersonDict,Selection
7+
58

69
class Replay(object):
710

@@ -38,7 +41,7 @@ def __init__(self, filename, release, frames=0):
3841
self.messages = list()
3942
self.recorder = None # Player object
4043
self.winner_known = False
41-
44+
4245
# Set in parsers.DetailParser.load, should we hide this?
4346
self.file_time = None # Probably number milliseconds since EPOCH
4447

@@ -49,6 +52,9 @@ def __init__(self, filename, release, frames=0):
4952
self.date = None # Date when the game was played in local time
5053
self.utc_date = None # Date when the game was played in UTC
5154

55+
#from obslib
56+
self.objects = {}
57+
5258
class Attribute(object):
5359

5460
def __init__(self, data):
@@ -133,28 +139,63 @@ def __repr__(self):
133139

134140
# Actor is a base class for Observer and Player
135141
class Person(object):
136-
def __init__(self, pid, name):
142+
def __init__(self, pid, name, replay):
137143
self.pid = pid
138144
self.name = name
139145
self.is_obs = None
140146
self.messages = list()
141147
self.events = list()
142148
self.recorder = False # Actual recorder will be determined using the replay.message.events file
143149

150+
#From obslib
151+
self.selections = {}
152+
self.hotkeys = {}
153+
self.replay = replay
154+
155+
def get_selection(self, number=10):
156+
""" Get selection buffer by number """
157+
if number < 10:
158+
return self.get_hotkey(number)
159+
else:
160+
selection = self.selections.get(number, Selection())
161+
self.selections[number] = selection
162+
return selection
163+
164+
def get_hotkey(self, number):
165+
""" Get hotkey buffer by number (does not load it) """
166+
hotkey = self.hotkeys.get(number, Selection())
167+
self.hotkeys[number] = hotkey
168+
return hotkey
169+
170+
def load_hotkey(self, number, timestamp):
171+
""" Push hotkey to current selection (10) """
172+
hotkey = self.hotkeys.get(number, Selection())
173+
self.hotkeys[number] = hotkey
174+
selection = self.get_selection(10) # get user bank
175+
selection.deselect_all(timestamp)
176+
selection.select(hotkey.current(), timestamp)
177+
178+
def army_composition_at(self, frame):
179+
return [object for object in self.game.objects.values() if object.alive_at(frame) and object.player == self and issubclass(object.object_types[frame], Army)]
180+
181+
def production_structures_at(self, frame):
182+
return [object for object in self.game.objects.values() if object.alive_at(frame) and object.player == self and issubclass(object.object_types[frame], Production)]
183+
184+
144185
class Observer(Person):
145-
def __init__(self, pid, name):
146-
super(Observer,self).__init__(pid,name)
186+
def __init__(self, pid, name, replay):
187+
super(Observer,self).__init__(pid, name, replay)
147188
self.is_obs = True
148189

149190
class Player(Person):
150191

151192
url_template = "http://%s.battle.net/sc2/en/profile/%s/%s/%s/"
152193

153-
def __init__(self, pid, data, realm="us"):
194+
def __init__(self, pid, data, replay):
154195
# TODO: get a map of realm,subregion => region in here
155-
super(Player,self).__init__(pid,data[0])
196+
super(Player,self).__init__(pid, data[0], replay)
156197
self.is_obs = False
157-
self.realm = realm
198+
self.realm = replay.realm
158199
self.uid = data[1][4]
159200
self.subregion = data[1][2]
160201
self.url = self.url_template % (self.realm, self.uid, self.subregion, self.name)
@@ -176,10 +217,10 @@ def __init__(self, pid, data, realm="us"):
176217

177218
self.choosen_race = "" # Populated from the replay.attribute.events file
178219
self.color_rgba = dict([
179-
['r', data[3][1]],
180-
['g', data[3][2]],
181-
['b', data[3][3]],
182-
['a', data[3][0]],
220+
['r', data[3][1]],
221+
['g', data[3][2]],
222+
['b', data[3][3]],
223+
['a', data[3][0]],
183224
])
184225

185226
self.result = None
@@ -191,7 +232,7 @@ def __init__(self, pid, data, realm="us"):
191232
self.avg_apm = 0
192233
self.aps = dict() # Doesn't contain seconds with zero actions
193234
self.apm = dict() # Doesn't contain minutes with zero actions
194-
235+
195236
def __str__(self):
196237
return "Player %s - %s (%s)" % (self.pid, self.name, self.actual_race)
197238

@@ -211,7 +252,7 @@ def __init__(self, timestamp, player_id, event_type, event_code):
211252
self.type = event_type
212253
self.code = event_code
213254
self.is_local = (player_id != 16)
214-
self.player = player_id
255+
self.pid = player_id
215256
self.bytes = bytes
216257
self.abilitystr = ""
217258

@@ -258,15 +299,17 @@ def __init__(self, timestamp, player, type, code, ability):
258299
self.ability = ability
259300

260301
def apply(self):
302+
261303
if self.ability:
262304
if self.ability not in ABILITIES:
263-
raise ValueError("Unknown ability (%s)" % (hex(self.ability)),)
305+
print "Unknown ability (%s) in at %s" % (hex(self.ability),self.timestr)
306+
#raise ValueError("Unknown ability (%s)" % (hex(self.ability)),)
264307
self.ability = ABILITIES[self.ability]
265308
able = self.get_able_selection()
266309
if able:
267310
object = able[0]
268311
ability = getattr(object, self.ability)
269-
ability(self.timestamp)
312+
ability(self.time)
270313

271314
# claim units
272315
for obj in self.player.get_selection().current:
@@ -294,14 +337,14 @@ def apply(self):
294337
create_obj = not GameObject.has_type(obj_type & 0xfffffc | 0x2)
295338

296339
obj = None
297-
if obj_id in self.player.game.objects:
298-
obj = self.player.game.objects[obj_id]
340+
if obj_id in self.player.replay.objects:
341+
obj = self.player.replay.objects[obj_id]
299342
elif create_obj:
300-
obj = type_class(obj_id, self.timestamp)
301-
self.player.game.objects[obj_id] = obj
343+
obj = type_class(obj_id, self.time)
344+
self.player.replay.objects[obj_id] = obj
302345

303346
if obj:
304-
obj.visit(self.timestamp, self.player, type_class)
347+
obj.visit(self.time, self.player, type_class)
305348
self.target = obj
306349

307350
super(TargetAbilityEvent, self).apply()
@@ -324,11 +367,11 @@ class SetToHotkeyEvent(HotkeyEvent):
324367
def apply(self):
325368
hotkey = self.player.get_hotkey(self.hotkey)
326369
selection = self.player.get_selection()
327-
hotkey[self.timestamp] = selection.current
370+
hotkey[self.time] = selection.current
328371

329372
# They are alive!
330-
for obj in selection[self.timestamp]:
331-
obj.visit(self.timestamp, self.player)
373+
for obj in selection[self.time]:
374+
obj.visit(self.time, self.player)
332375

333376
class AddToHotkeyEvent(HotkeyEvent):
334377
name = 'AddToHotkeyEvent'
@@ -340,13 +383,13 @@ def apply(self):
340383
if self.overlay:
341384
hotkeyed = self.overlay(hotkeyed)
342385

343-
hotkeyed.extend(self.player.get_selection()[self.timestamp])
386+
hotkeyed.extend(self.player.get_selection()[self.time])
344387
hotkeyed = list(set(hotkeyed)) # remove dups
345-
hotkey[self.timestamp] = hotkeyed
388+
hotkey[self.time] = hotkeyed
346389

347390
# They are alive!
348391
for obj in hotkeyed:
349-
obj.visit(self.timestamp, self.player)
392+
obj.visit(self.time, self.player)
350393

351394
class GetHotkeyEvent(HotkeyEvent):
352395
name = 'GetHotkeyEvent'
@@ -358,11 +401,11 @@ def apply(self):
358401
hotkeyed = self.overlay(hotkeyed)
359402

360403
selection = self.player.get_selection()
361-
selection[self.timestamp] = hotkeyed
404+
selection[self.time] = hotkeyed
362405

363406
# selection is alive!
364407
for obj in hotkeyed:
365-
obj.visit(self.timestamp, self.player)
408+
obj.visit(self.time, self.player)
366409

367410
class SelectionEvent(Event):
368411
name = 'SelectionEvent'
@@ -378,20 +421,20 @@ def apply(self):
378421

379422
selected = selection.current[:]
380423
for obj in selected: # visit all old units
381-
obj.visit(self.timestamp, self.player)
424+
obj.visit(self.time, self.player)
382425

383426
if self.deselect:
384427
selected = self.deselect(selected)
385428

386429
# Add new selection
387430
for (obj_id, obj_type) in self.objects:
388431
type_class = GameObject.get_type(obj_type)
389-
if obj_id not in self.player.game.objects:
390-
obj = type_class(obj_id, self.timestamp)
391-
self.player.game.objects[obj_id] = obj
432+
if obj_id not in self.player.replay.objects:
433+
obj = type_class(obj_id, self.time)
434+
self.player.replay.objects[obj_id] = obj
392435
else:
393-
obj = self.player.game.objects[obj_id]
394-
obj.visit(self.timestamp, self.player, type_class)
436+
obj = self.player.replay.objects[obj_id]
437+
obj.visit(self.time, self.player, type_class)
395438
selected.append(obj)
396439

397-
selection[self.timestamp] = selected
440+
selection[self.time] = selected

sc2reader/processors.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,13 @@ class Processor(object):
2727
#####################################################
2828

2929
class PeopleProcessor(Processor):
30-
3130
def process(self, replay):
3231
obs_players = list(replay.player_names)
3332
for player in replay.players:
3433
obs_players.remove(player.name)
3534

3635
for pid,name in enumerate(obs_players):
37-
replay.observers.append(Observer(pid+len(replay.players)+1,name))
36+
replay.observers.append(Observer(pid+len(replay.players)+1,name,replay))
3837

3938
for person in replay.observers+replay.players:
4039
replay.people.append(person)
@@ -116,12 +115,14 @@ class EventProcessor(Processor):
116115
def process(self, replay):
117116
replay.events_by_type = defaultdict(list)
118117
for event in replay.events:
119-
#event.apply()
120-
replay.events_by_type[event.name].append(event)
121118
if event.is_local:
122-
person = replay.person[event.player]
119+
person = replay.person[event.pid]
120+
event.player = person
123121
person.events.append(event)
124122

123+
event.apply()
124+
replay.events_by_type[event.name].append(event)
125+
125126
return replay
126127

127128
#####################################################
@@ -130,7 +131,7 @@ class ApmProcessor(Processor):
130131
def process(self, replay):
131132
for event in replay.events:
132133
if event.is_local and event.is_player_action:
133-
person = replay.person[event.player]
134+
person = event.player
134135
if not person.is_obs:
135136
# Calculate APS, APM and average
136137
if event.seconds in person.aps:
@@ -157,15 +158,21 @@ def process(self, replay):
157158
class ResultsProcessor(Processor):
158159
def process(self, replay):
159160
#Remove players from the teams as they drop out of the game
161+
print replay.teams
162+
print replay.players
160163
replay.results = dict([team, len(players)] for team, players in replay.teams.iteritems())
161164

165+
print replay.results
166+
162167
for event in replay.events_by_type['PlayerLeave']:
163168
#Some observer actions seem to be recorded, they aren't on teams anyway
164169
#Their pid will always be higher than the players
165-
if event.player <= len(replay.players):
166-
team = replay.person[event.player].team
170+
print "Player %s has left" % event.pid
171+
if event.pid <= len(replay.players):
172+
team = replay.person[event.pid].team
167173
replay.results[team] -= 1
168174

175+
print replay.results
169176
#mark all teams with no players left as losing, save the rest of the teams
170177
remaining = set()
171178
for team, count in replay.results.iteritems():

sc2reader/readers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def read(self, filecontents, replay):
9898
data = ReplayBuffer(filecontents).read_data_struct()
9999

100100
for pid, pdata in enumerate(data[0]):
101-
replay.players.append(Player(pid+1, pdata, replay.realm)) #pid's start @ 1
101+
replay.players.append(Player(pid+1, pdata, replay)) #pid's start @ 1
102102

103103
replay.map = data[1]
104104
replay.file_time = data[5]

0 commit comments

Comments
 (0)