|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +from __future__ import absolute_import, print_function, unicode_literals, division |
| 3 | + |
| 4 | +from sc2reader import objects, utils |
| 5 | + |
| 6 | + |
| 7 | +def GameHeartNormalizer(replay): |
| 8 | + """ |
| 9 | + normalize a GameHeart replay to: |
| 10 | + 1) reset frames to the game start |
| 11 | + 2) remove observing players |
| 12 | + 3) fix race selection |
| 13 | + 4) fix team selection |
| 14 | + If a replay is not a GameHeart replay, it should be left untouched |
| 15 | + Hopefully, the changes here will also extend to other replays that use |
| 16 | + in-game lobbies |
| 17 | +
|
| 18 | + This makes a few assumptions |
| 19 | + 1) 1v1 game |
| 20 | + """ |
| 21 | + |
| 22 | + PRIMARY_BUILDINGS = set (['Hatchery', 'Nexus', 'CommandCenter']) |
| 23 | + start_frame = -1 |
| 24 | + actual_players = {} |
| 25 | + |
| 26 | + if not replay.tracker_events: |
| 27 | + return replay # necessary using this strategy |
| 28 | + |
| 29 | + for event in replay.tracker_events: |
| 30 | + if start_frame != -1 and event.frame > start_frame + 5: # fuzz it a little |
| 31 | + break |
| 32 | + if event.name == 'UnitBornEvent' and event.control_pid and \ |
| 33 | + event.unit_type_name in PRIMARY_BUILDINGS: |
| 34 | + if event.frame == 0: # it's a normal, legit replay |
| 35 | + return replay |
| 36 | + start_frame = event.frame |
| 37 | + actual_players[event.control_pid] = event.unit.race |
| 38 | + |
| 39 | + # set game length starting with the actual game start |
| 40 | + replay.frames -= start_frame |
| 41 | + replay.game_length = utils.Length(seconds=replay.frames / 16) |
| 42 | + |
| 43 | + # this should cover events of all types |
| 44 | + # not nuking entirely because there are initializations that may be relevant |
| 45 | + for event in replay.events: |
| 46 | + if event.frame < start_frame: |
| 47 | + event.frame = 0 |
| 48 | + event.second = 0 |
| 49 | + else: |
| 50 | + event.frame -= start_frame |
| 51 | + event.second = event.frame >> 4 |
| 52 | + |
| 53 | + # replay.humans is okay because they're all still humans |
| 54 | + # replay.person and replay.people is okay because the mapping is still true |
| 55 | + |
| 56 | + # add observers |
| 57 | + # not reinitializing because players appear to have the properties of observers |
| 58 | + # TODO in a better world, these players would get reinitialized |
| 59 | + replay.observers += [player for player in replay.players if not player.pid in actual_players] |
| 60 | + for observer in replay.observers: |
| 61 | + observer.is_observer = True |
| 62 | + observer.team_id = None |
| 63 | + |
| 64 | + # reset team |
| 65 | + # reset teams |
| 66 | + replay.team = {} |
| 67 | + replay.teams = [] |
| 68 | + |
| 69 | + # reset players |
| 70 | + replay.players = [player for player in replay.players if player.pid in actual_players] |
| 71 | + for i, player in enumerate(replay.players): |
| 72 | + race = actual_players[player.pid] |
| 73 | + player.pick_race = race |
| 74 | + player.play_race = race |
| 75 | + |
| 76 | + team = objects.Team(i + 1) |
| 77 | + team.players.append(player) |
| 78 | + team.result = player.result |
| 79 | + player.team = team |
| 80 | + replay.team[i + 1] = team |
| 81 | + replay.teams.append(team) |
| 82 | + |
| 83 | + # set winner |
| 84 | + if team.result == 'Win': |
| 85 | + replay.winner = team |
| 86 | + |
| 87 | + # clear observers out of the players list |
| 88 | + for pid in replay.player.keys(): |
| 89 | + if not pid in actual_players: |
| 90 | + del replay.player[pid] |
| 91 | + |
| 92 | + return replay |
0 commit comments