Exemple #1
0
    def handleUnitDiedEvent(self, event, replay):
        if not replay.datapack:
            return

        if event.unit_id in replay.objects:
            event.unit = replay.objects[event.unit_id]
            event.unit.died_at = event.frame
            event.unit.location = event.location
            if event.unit_id_index in replay.active_units:
                del replay.active_units[event.unit_id_index]
            else:
                self.logger.error(
                    "Unable to delete unit index {0} at {1} [{2}], index not active."
                    .format(event.killer_pid, Length(seconds=event.second),
                            event.frame))
        else:
            self.logger.error(
                "Unit {0} died at {1} [{2}] before it was born!".format(
                    event.unit_id, Length(seconds=event.second), event.frame))

        if event.killer_pid in replay.player:
            event.killer = replay.player[event.killer_pid]
            if event.unit:
                event.unit.killed_by = event.killer
                event.killer.killed_units.append(event.unit)
        elif event.killer_pid:
            self.logger.error("Unknown killer pid {0} at {1} [{2}]".format(
                event.killer_pid, Length(seconds=event.second), event.frame))
Exemple #2
0
    def handleInitGame(self, event, replay):
        # without tracker events game heart games can't be fixed
        if len(replay.tracker_events) == 0:
            yield PluginExit(self, code=0, details=dict())
            return

        start_frame = -1
        actual_players = {}
        for event in replay.tracker_events:
            if start_frame != -1 and event.frame > start_frame + 5:  # fuzz it a little
                break
            if event.name == 'UnitBornEvent' and event.control_pid and event.unit_type_name in self.PRIMARY_BUILDINGS:
                # In normal replays, starting units are born on frame zero.
                if event.frame == 0:
                    yield PluginExit(self, code=0, details=dict())
                    return
                else:
                    start_frame = event.frame
                    actual_players[event.control_pid] = self.PRIMARY_BUILDINGS[
                        event.unit_type_name]

        self.fix_entities(replay, actual_players)
        self.fix_events(replay, start_frame)

        replay.frames -= start_frame
        replay.game_length = Length(seconds=replay.frames / 16)
        replay.real_type = get_real_type(replay.teams)
        replay.real_length = Length(
            seconds=int(replay.game_length.seconds /
                        GAME_SPEED_FACTOR[replay.speed]))
        replay.start_time = datetime.utcfromtimestamp(
            replay.unix_timestamp - replay.real_length.seconds)
Exemple #3
0
    def load_message_game_player(self, event, replay):
        if replay.versions[1] == 1 or (replay.versions[1] == 2
                                       and replay.build < 24247):
            if event.pid in replay.entity:
                event.player = replay.entity[event.pid]
                event.player.events.append(event)
            elif event.pid != 16:
                self.logger.error(
                    "Bad pid ({0}) for event {1} at {2} [{3}].".format(
                        event.pid, event.__class__,
                        Length(seconds=event.second), event.frame))
            else:
                pass  # This is a global event

        else:  # Now event.pid is actually a user id for human entities
            if event.pid < len(replay.humans):
                event.player = replay.human[event.pid]
                event.player.events.append(event)
            elif event.pid != 16:
                self.logger.error(
                    "Bad pid ({0}) for event {1} at {2} [{3}].".format(
                        event.pid, event.__class__,
                        Length(seconds=event.second), event.frames))
            else:
                pass  # This is a global event
Exemple #4
0
 def load_tracker_controller(self, event, replay):
     if event.control_pid in replay.entity:
         event.unit_controller = replay.entity[event.control_pid]
     elif event.control_pid != 0:
         self.logger.error(
             "Bad control_pid ({0}) for event {1} at {2} [{3}].".format(
                 event.control_pid, event.__class__,
                 Length(seconds=event.second), event.frame))
Exemple #5
0
 def load_tracker_player(self, event, replay):
     if event.pid in replay.entity:
         event.player = replay.entity[event.pid]
     else:
         self.logger.error(
             "Bad pid ({0}) for event {1} at {2} [{3}].".format(
                 event.pid, event.__class__, Length(seconds=event.second),
                 event.frame))
Exemple #6
0
def SelectionTracker(replay):
    debug = replay.opt['debug']
    logger = log_utils.get_logger(SelectionTracker)

    for person in replay.entities:
        # TODO: A more robust person interface might be nice
        person.selection_errors = 0
        player_selections = GameState(PlayerSelection())
        for event in person.events:
            error = False
            if event.name == 'SelectionEvent':
                selections = player_selections[event.frame]
                control_group = selections[event.control_group].copy()
                error = not control_group.deselect(event.mask_type, event.mask_data)
                control_group.select(event.new_units)
                selections[event.control_group] = control_group
                if debug:
                    logger.info("[{0}] {1} selected {2} units: {3}".format(Length(seconds=event.second), person.name, len(selections[0x0A].objects), selections[0x0A]))

            elif event.name == 'SetControlGroupEvent':
                selections = player_selections[event.frame]
                selections[event.control_group] = selections[0x0A].copy()
                if debug:
                    logger.info("[{0}] {1} set hotkey {2} to current selection".format(Length(seconds=event.second), person.name, event.hotkey))

            elif event.name == 'AddToControlGroupEvent':
                selections = player_selections[event.frame]
                control_group = selections[event.control_group].copy()
                error = not control_group.deselect(event.mask_type, event.mask_data)
                control_group.select(selections[0x0A].objects)
                selections[event.control_group] = control_group
                if debug:
                    logger.info("[{0}] {1} added current selection to hotkey {2}".format(Length(seconds=event.second), person.name, event.hotkey))

            elif event.name == 'GetControlGroupEvent':
                selections = player_selections[event.frame]
                control_group = selections[event.control_group].copy()
                error = not control_group.deselect(event.mask_type, event.mask_data)
                selections[0xA] = control_group
                if debug:
                    logger.info("[{0}] {1} retrieved hotkey {2}, {3} units: {4}".format(Length(seconds=event.second), person.name, event.control_group, len(selections[0x0A].objects), selections[0x0A]))

            else:
                continue

            # TODO: The event level interface here should be improved
            #       Possibly use 'added' and 'removed' unit lists as well
            event.selected = selections[0x0A].objects
            if error:
                person.selection_errors += 1
                if debug:
                    logger.warn("Error detected in deselection mode {0}.".format(event.mask_type))

        person.selection = player_selections
        # Not a real lock, so don't change it!
        person.selection.locked = True

    return replay
Exemple #7
0
 def _str_prefix(self):
     if getattr(self, 'pid', 16) == 16:
         player_name = "Global"
     elif self.player and not self.player.name:
         player_name = "Player {0} - ({1})".format(self.player.pid, self.player.play_race)
     elif self.player:
         player_name = self.player.name
     else:
         player_name = "no name"
     return "{0}\t{1:<15} ".format(Length(seconds=int(self.frame / 16)), player_name)
Exemple #8
0
    def __init__(self, replay_file, **options):
        #Useful references
        self.opt = AttributeDict(**options)

        # Some file-like objects may not support filenames. Issue #21
        if hasattr(replay_file, 'name'):
            self.filename = replay_file.name
        else:
            self.filename = "Unavailable"

        #header information
        self.versions, self.frames = read_header(replay_file)
        self.build = self.versions[4]
        self.release_string = "%s.%s.%s.%s" % tuple(self.versions[1:5])
        self.seconds = self.frames / 16
        self.length = Length(seconds=self.seconds)

        #default values, filled in during file read
        self.player_names = list()
        self.other_people = set()
        self.speed = ""
        self.type = ""
        self.category = ""
        self.is_ladder = False
        self.is_private = False
        self.map = ""
        self.gateway = ""
        self.events = list()
        self.events_by_type = defaultdict(list)
        self.results = dict()
        self.teams = list()
        self.team = dict()
        self.observers = list()  #Unordered list of Observer
        self.players = list()  #Unordered list of Player
        self.player = PersonDict()
        self.people = list()  #Unordered list of Players+Observers
        self.humans = list()  #Unordered list of Human People
        self.person = PersonDict()  #Maps pid to Player/Observer
        self.attributes = list()
        self.messages = list()
        self.recorder = None  # Player object
        self.winner_known = False
        self.packets = list()
        # Set in parsers.DetailParser.load, should we hide this?
        self.file_time = None

        # TODO: Test EPOCH differences between MacOsX and Windows
        # http://en.wikipedia.org/wiki/Epoch_(reference_date)
        # Notice that Windows and Mac have different EPOCHs, I wonder whether
        # this is different depending on the OS on which the replay was played.
        self.date = None  # Date when the game was played in local time
        self.utc_date = None  # Date when the game was played in UTC

        self.objects = {}
        self.raw = AttributeDict()
Exemple #9
0
    def handleUnitTypeChangeEvent(self, event, replay):
        if not replay.datapack:
            return

        if event.unit_id in replay.objects:
            event.unit = replay.objects[event.unit_id]
            replay.datapack.change_type(event.unit, event.unit_type_name,
                                        event.frame)
        else:
            self.logger.error(
                "Unit {0} type changed at {1} [{2}] before it was born!".
                format(event.unit_id, Length(seconds=event.second)))
Exemple #10
0
    def load_context(self, replay):
        if replay.versions[1] == 1 or (replay.versions[1] == 2
                                       and replay.build < 24247):
            if self.pid <= len(replay.people):
                self.player = replay.person[self.pid]
                self.player.events.append(self)
            elif self.pid != 16:
                self.logger.error("Bad pid ({0}) for event {1} at {2}.".format(
                    self.pid, self.__class__, Length(seconds=self.second)))
            else:
                pass  # This is a global event

        else:
            if self.pid < len(replay.clients):
                self.player = replay.client[self.pid]
                self.player.events.append(self)
            elif self.pid != 16:
                self.logger.error("Bad pid ({0}) for event {1} at {2}.".format(
                    self.pid, self.__class__, Length(seconds=self.second)))
            else:
                pass  # This is a global event
Exemple #11
0
    def handleUnitDoneEvent(self, event, replay):
        if not replay.datapack:
            return

        if event.unit_id in replay.objects:
            event.unit = replay.objects[event.unit_id]
            event.unit.finished_at = event.frame
        else:
            self.logger.error(
                "Unit {0} done at {1} [{2}] before it was started!".format(
                    event.killer_pid, Length(seconds=event.second),
                    event.frame))
Exemple #12
0
    def __init__(self):
        self.initialize_txt()

        # Config
        # Tracked Player
        name = input("Type the player name you want to track \n")
        self.tracked_player = name
        # Tracked Race
        race = input(
            "Type the race you want to track (Zerg, Protoss, Terran) \n")
        self.tracked_race = race

        if platform == "win32":
            try:
                self.replay_folder = f"{expanduser('~')}\\documents\\StarCraft II"
            except ValueError:
                print(
                    "Replay folder not found, are you sure Starcraft II is installed?"
                )
        elif platform == "linux" or platform == "linux2":
            try:
                self.replay_folder = os.environ['SC2_REPLAYS']
            except KeyError:
                print(
                    "Replay folder not found, are you sure Starcraft II is installed?"
                )
                self.replay_folder = input(
                    "Provide path to your SC2 replay folder. "
                    "This is usually located under .wine \n")

        # Folder polling rate in seconds
        self.poll_rate = 5
        # Minimum length of a game
        self.min_length = Length(seconds=60)

        print("GGParser initialized")
        print("Tracking folder: " + self.replay_folder)
        print("Tracking player: " + self.tracked_player + " - " +
              self.tracked_race)
        print("Polling the folder every " + str(self.poll_rate) + " seconds")

        self.zerg = "Zerg"
        self.protoss = "Protoss"
        self.terran = "Terran"

        self.XvZ = Score()
        self.XvP = Score()
        self.XvT = Score()
        self.XvR = Score()

        # Variables
        self.replay_path = self.get_latest_replay_init()
Exemple #13
0
    def handleUnitPositionsEvent(self, event, replay):
        if not replay.datapack:
            return

        for unit_index, (x, y) in event.positions:
            if unit_index in replay.active_units:
                unit = replay.active_units[unit_index]
                unit.location = (x, y)
                event.units[unit] = unit.location
            else:
                self.logger.error(
                    "Unit at active_unit index {0} moved at {1} [{2}] but it doesn't exist!"
                    .format(event.killer_pid, Length(seconds=event.second),
                            event.frame))
Exemple #14
0
    def handleUnitOwnerChangeEvent(self, event, replay):
        self.load_tracker_controller(event, replay)
        self.load_tracker_upkeeper(event, replay)

        if not replay.datapack:
            return

        if event.unit_id in replay.objects:
            event.unit = replay.objects[event.unit_id]
        else:
            self.logger.error(
                "Unit {0} owner changed at {1} [{2}] before it was born!".
                format(event.unit_id, Length(seconds=event.second),
                       event.frame))

        if event.unit_upkeeper:
            if event.unit.owner:
                event.unit.owner.units.remove(event.unit)
            event.unit.owner = event.unit_upkeeper
            event.unit_upkeeper.units.append(event.unit)
Exemple #15
0
 def __init__(self, framestamp, sender, target, text):
     self.framestamp, self.sender, self.target, self.text = framestamp, sender, target, text
     self.time = Length(seconds=self.framestamp / 16)
     self.to_all = (self.target == 0)
     self.to_allies = (self.target == 2)
Exemple #16
0
 def _str_prefix(self):
     return "{0}\t ".format(Length(seconds=int(self.frame / 16)))
Exemple #17
0
 def _str_prefix(self):
     if self.player:
         player_name = self.player.name if getattr(self, 'pid', 16) != 16 else "Global"
     else:
         player_name = "no name"
     return "{0}\t{1:<15} ".format(Length(seconds=int(self.frame / 16)), player_name)
Exemple #18
0
def SelectionTracker(replay):
    debug = replay.opt.debug
    logger = log_utils.get_logger(SelectionTracker)

    for person in replay.people:
        # TODO: A more robust person interface might be nice
        person.selection_errors = 0
        player_selection = GameState(PlayerSelection())
        for event in person.selection_events:
            if debug: logger.debug("Event bytes: " + event.bytes.encode("hex"))

            error = False
            selection = player_selection[event.frame]

            if isinstance(event, SelectionEvent):
                selection[event.bank] = selection[event.bank].copy()
                error = not selection[event.bank].deselect(*event.deselect)
                selection[event.bank].select(event.objects)
                if debug:
                    logger.info("[{0}] {1} selected {2} units: {3}".format(
                        Length(seconds=event.second), person.name,
                        len(selection[0x0A].objects), selection[0x0A]))

            elif isinstance(event, GetFromHotkeyEvent):
                # For some reason they leave the hotkey buffer unmodified so make a copy
                selection[0x0A] = selection[event.hotkey].copy()
                error = not selection[0x0A].deselect(*event.deselect)
                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]))

            elif isinstance(event, SetToHotkeyEvent):
                # Make a copy to decouple the hotkey from primary selection
                selection[event.hotkey] = selection[0x0A].copy()
                if debug:
                    logger.info(
                        "[{0}] {1} set hotkey {2} to current selection".format(
                            Length(seconds=event.second), person.name,
                            event.hotkey))

            elif isinstance(event, AddToHotkeyEvent):
                selection[event.hotkey] = selection[event.hotkey].copy()
                error = not selection[event.hotkey].deselect(*event.deselect)
                selection[event.hotkey].select(selection[0x0A].objects)
                if debug:
                    logger.info(
                        "[{0}] {1} added current selection to hotkey {2}".
                        format(Length(seconds=event.second), person.name,
                               event.hotkey))

            # TODO: The event level interface here should be improved
            #       Possibly use 'added' and 'removed' unit lists as well
            event.selected = selection[0x0A].objects
            if error:
                person.selection_errors += 1
                if debug:
                    logger.warn(
                        "Error detected in deselection mode {0}.".format(
                            event.deselect[0]))

        person.selection = player_selection
        # Not a real lock, so don't change it!
        person.selection.locked = True

    return replay
Exemple #19
0
 def _str_prefix(self):
     player_name = self.player.name if getattr(self, 'pid',
                                               16) != 16 else "Global"
     return "%s\t%-15s " % (Length(seconds=int(self.frame / 16)),
                            player_name)
Exemple #20
0
 def _str_prefix(self):
     player_name = self.player.name if getattr(self, "pid",
                                               16) != 16 else "Global"
     return "{0}\t{1:<15} ".format(Length(seconds=int(self.frame / 22.4)),
                                   player_name)
Exemple #21
0
 def _str_prefix(self):
     player_name = self.player.name if self.is_local else "Global"
     return "%s\t%-15s " % (Length(seconds=int(self.frame / 16)),
                            player_name)