def parse_file(replay):
    replay_name = write_files_to_disk([replay])[0]
    replay = analyze_replay_file(os.path.join(folder_location, replay_name),
                                 os.path.join(folder_location, replay_name) + '.json')
    proto = replay.protobuf_game
    guid = proto.game_metadata.match_guid
    return replay, proto, guid
Exemple #2
0
 def _process(self, id_) -> AnalysisManager:
     if id_ in self.REPLAYS_MAP:
         return self.REPLAYS_MAP[id_]
     path = os.path.join(self.REPLAYS_DIR, id_ + '.replay')
     manager = carball.analyze_replay_file(path, "replay.json")
     self.REPLAYS_MAP[id_] = manager
     return manager
def parse_replay_task(self,
                      fn,
                      preserve_upload_date=False,
                      custom_file_location: str = None,
                      force_reparse=False):
    if custom_file_location is None:
        pickled = os.path.join(os.path.dirname(__file__), '..', '..', 'data',
                               'parsed', os.path.basename(fn))
    else:
        pickled = os.path.join(custom_file_location, os.path.basename(fn))
    if custom_file_location is None:
        failed_dir = os.path.join(os.path.dirname(os.path.dirname(pickled)),
                                  'failed')
    else:
        failed_dir = custom_file_location
    if os.path.isfile(pickled) and not force_reparse:
        return
    # try:
    try:
        analysis_manager = analyze_replay_file(fn)  # type: ReplayGame
    except Exception as e:
        if not os.path.isdir(failed_dir):
            os.makedirs(failed_dir)
        shutil.move(fn, os.path.join(failed_dir, os.path.basename(fn)))
        with open(os.path.join(failed_dir,
                               os.path.basename(fn) + '.txt'), 'a') as f:
            f.write(str(e))
            f.write(traceback.format_exc())
        raise e

    with open(pickled + '.pts', 'wb') as fo:
        analysis_manager.write_proto_out_to_file(fo)
    with gzip.open(pickled + '.gzip', 'wb') as fo:
        analysis_manager.write_pandas_out_to_file(fo)

    g = analysis_manager.protobuf_game
    sess = self.session()
    game, player_games, players, teamstats = convert_pickle_to_db(g)
    add_objs_to_db(game,
                   player_games,
                   players,
                   teamstats,
                   sess,
                   preserve_upload_date=preserve_upload_date)
    sess.commit()
    sess.close()

    replay_id = g.game_metadata.match_guid
    if replay_id == '':
        replay_id = g.game_metadata.id
    shutil.move(fn, os.path.join(os.path.dirname(fn), replay_id + '.replay'))
    shutil.move(
        pickled + '.pts',
        os.path.join(os.path.dirname(pickled), replay_id + '.replay.pts'))
    shutil.move(
        pickled + '.gzip',
        os.path.join(os.path.dirname(pickled), replay_id + '.replay.gzip'))
    return replay_id
Exemple #4
0
def write_proto_pandas_to_file(filename):
    proto_manager = analyze_replay_file(filename)
    _, proto_name = tempfile.mkstemp(dir=get_test_folder())
    with open(proto_name, 'wb') as f:
        proto_manager.write_proto_out_to_file(f)
    _, pandas_name = tempfile.mkstemp(dir=get_test_folder())
    with open(pandas_name, 'wb') as f:
        proto_manager.write_pandas_out_to_file(f)
    return proto_name, pandas_name, proto_manager.protobuf_game
Exemple #5
0
def convert_replay_to_game_frames(inputName, JSONpath, save_json=True):
    manager = carball.analyze_replay_file(inputName,
                                          output_path=JSONpath,
                                          overwrite=True)

    result = convert_json_to_game_frames(JSONpath)
    if not save_json:
        os.remove(JSONpath)
    return result
 def setUp(self):
     engine, sessionmaker = startup.startup()
     self.session = sessionmaker()
     _, path = tempfile.mkstemp()
     with open(path, 'wb') as tmp:
         tmp.write(download_replay_discord(get_complex_replay_list()[0]))
     self.replay = analyze_replay_file(path, path + '.json')
     self.proto = self.replay.protobuf_game
     self.guid = self.proto.game_metadata.match_guid
Exemple #7
0
def parse_file(replay):
    replay_name = write_files_to_disk([replay])[0]
    replay = analyze_replay_file(
        os.path.join(get_test_folder(), replay_name),
        os.path.join(get_test_folder(), replay_name) + '.json')
    proto = replay.protobuf_game
    if proto.game_metadata.match_guid is not None and proto.game_metadata.match_guid != '':
        guid = proto.game_metadata.match_guid
    else:
        guid = proto.game_metadata.id
    return replay, proto, guid
Exemple #8
0
def write_proto_pandas_to_file(filename):
    proto_manager = analyze_replay_file(filename)

    _, proto_name = tempfile.mkstemp(dir=TestFolderManager.get_test_folder())
    proto_name = proto_name + PROTO_EXTENSION
    with open(proto_name, 'wb') as f:
        proto_manager.write_proto_out_to_file(f)

    _, pandas_name = tempfile.mkstemp(dir=TestFolderManager.get_test_folder())
    pandas_name = pandas_name + PANDAS_EXTENSION
    with gzip.open(pandas_name, 'wb') as f:
        proto_manager.write_pandas_out_to_file(f)

    return proto_name, pandas_name, proto_manager.protobuf_game
def parse_replay_wrapper(replay_to_parse_path: str,
                         parsed_data_path: str,
                         failed_dir: str,
                         force_reparse: bool,
                         logger, query_params=None) -> Optional[AnalysisManager]:
    """
    Parses a replay with the given parameters.
    :param replay_to_parse_path:  The path where the replay that is being parsed is stored
    :param parsed_data_path:  The path where the post parsing data will be stored
    :param failed_dir:  The path where we will store a replay that failed to parse
    :param force_reparse: If true the replay will parse even if it has already been parsed before.
    :param logger:  The logger that is logging the error messages
    :return: An analysis manager if the replay was successfully parsed.  It will return None if the replay has already been parsed.
    """
    # Todo preparse replay ID here to save on extra parsing and on locks.  (remember to delete locks older than 1 day)
    if os.path.isfile(parsed_data_path) and not force_reparse:
        return
    # try:
    try:
        analysis_manager = analyze_replay_file(replay_to_parse_path)  # type: AnalysisManager
    except Exception as e:
        if not os.path.isdir(failed_dir):
            os.makedirs(failed_dir)
        shutil.move(replay_to_parse_path, os.path.join(failed_dir, os.path.basename(replay_to_parse_path)))
        with open(os.path.join(failed_dir, os.path.basename(replay_to_parse_path) + '.txt'), 'a') as f:
            f.write(str(e))
            f.write(traceback.format_exc())
        payload = {
            'replay_uuid': os.path.basename(replay_to_parse_path),
            'error_type': type(e).__name__,
            'stack': traceback.format_exc(),
            'game_hash': None
        }
        ErrorLogger.log_replay_error(payload, query_params)
        raise e
    try:
        write_replay_to_disk(analysis_manager, parsed_data_path)
    except Exception as e:
        ErrorLogger.log_error(e, logger=logger)
        with open(os.path.join(failed_dir, os.path.basename(replay_to_parse_path) + '.txt'), 'a') as f:
            f.write(str(e))
            f.write(traceback.format_exc())

    return analysis_manager
Exemple #10
0
def predict_boost_values(rp, model):
    if isinstance(rp, str):
        rp = cb.analyze_replay_file(rp,
                                    controls=ControlsCreator(),
                                    logging_level=logging.CRITICAL)

    pp = replay_to_dfs(rp, skip_ties=False)
    cpx, cpy = convert_dfs(pp, frame_mode=1)
    normalize(cpx)

    results = np.zeros((cpx[0].shape[0], len(pp["players"]), 101))

    # xs = np.zeros((cpx[0].shape[0], len(pp["players"])))
    # ys = np.zeros((cpx[0].shape[0], len(pp["players"])))

    model.eval()
    with torch.no_grad():
        for p, row in pp["players"].iterrows():
            print(p)
            cpxc = [np.copy(v) for v in cpx]

            # # For making histogram
            # preds = model(*[torch.from_numpy(v).float().cuda() for v in cpxc])
            # preds = preds[0].cpu().detach().numpy()
            # preds = preds[:, 1] - preds[:, 0]
            # if row["color"] == "blue":
            #     preds = -preds
            # xs[:, p] = cpxc[2][:, p, 19]
            # ys[:, p] = preds

            # For changing the boost amount at every step
            for b in range(101):
                print("\t", b)
                cpxc[2][:, p, 19] = b / 100
                cpxc[2][:, p, 19][cpxc[2][:, p, 20] == 1] = 0
                preds = model(
                    *[torch.from_numpy(v).float().cuda() for v in cpxc])
                preds = preds[0].cpu().detach().numpy()
                preds = preds[:, 1] - preds[:, 0]
                if row["color"] == "blue":
                    preds = -preds
                results[:, p, b] = preds

    return results
Exemple #11
0
def parse_file(analysis_manager, temp_folder=None):
    replay_name = write_files_to_disk([analysis_manager],
                                      temp_folder=temp_folder)[0]
    try:
        analysis_manager = analyze_replay_file(
            os.path.join(
                TestFolderManager.get_test_folder(temp_folder=temp_folder),
                replay_name))
    except Exception as e:
        print('error parsing ', replay_name)
        raise e

    proto = analysis_manager.protobuf_game
    if proto.game_metadata.match_guid is not None and proto.game_metadata.match_guid != '':
        guid = proto.game_metadata.match_guid
    else:
        guid = proto.game_metadata.id

    replay_path = os.path.join(
        TestFolderManager.get_test_folder(temp_folder=temp_folder),
        guid) + REPLAY_EXTENSION

    write_replay_to_disk(analysis_manager, replay_path)
    return analysis_manager, proto, guid, replay_path
Exemple #12
0
def replays_to_csv(in_files: List[str], output_path: str, shared: List[Value]):
    """
    Multiprocessing function called by pre_process_parallel. Converts replay files to csv files.
    :param in_files: A list of files to process.
    :type in_files: List[str]
    :param output_path: The path to save CSVs
    :type output_path: str
    :param shared: A list of multiprocessing values to track errors.
    :type shared: List[Value]
    :return: None
    :rtype: None
    """
    try:
        ordered_cols = get_ordered_columns(NUM_PLAYERS)
        print("Starting {} with {} files".format(current_process().name, len(in_files)))
        file_average = [timedelta(), 0]
        for file in in_files:
            file_start = datetime.now()
            try:
                with HiddenPrints():
                    try:
                        e = False
                        # Analysis has a lot of possible errors
                        analysis = carball.analyze_replay_file(replay_path + file)
                    except IndexError:
                        with shared[0].get_lock():
                            shared[0].value += 1
                        e = True
                        continue
                    except KeyError:
                        with shared[1].get_lock():
                            shared[1].value += 1
                        e = True
                        continue
                    except RattleTrapException:  # Currently can't figure out how to except "carball.rattletrap.run_rattletrap.RattleTrapException"
                        with shared[2].get_lock():
                            shared[2].value += 1
                        e = True
                        continue
                    except UnboundLocalError:
                        with shared[3].get_lock():
                            shared[3].value += 1
                        e = True
                        continue
                    except KeyboardInterrupt:
                        print("Exiting")
                        break
                    except():
                        with shared[4].get_lock():
                            shared[4].value += 1
                        e = True
                        continue
                    finally:
                        if e:
                            copyfile(replay_path + file, error_path + file)

                proto_game = analysis.get_protobuf_data()
                gdf = analysis.get_data_frame()
                # Check if game has overtime, and skip it if it has extra columns (very rare, but can happen)
                gdf.columns = gdf.columns.to_flat_index()
                game_has_overtime = False
                if len(gdf.columns) != 65:
                    if len(gdf.columns) == 66:
                        if ('game', 'is_overtime') in gdf.columns:
                            game_has_overtime = True
                        else:
                            copyfile(replay_path + file, skip_path + file)
                            continue

                goal_seconds, goal_frames, goal_scorers, goal_teams, gdf = restructure_and_get_goals(proto_game, gdf)

                # Skip if no goals or if game is too short
                # Take this out or change it depending on how much you care about dataset quality
                if 210 not in gdf['game_seconds_remaining']:
                    copyfile(replay_path + file, skip_path + file)
                    continue

                if len(goal_frames) == 0:
                    copyfile(replay_path + file, skip_path + file)
                    assert (len(proto_game.game_metadata.goals) == 0)
                    continue
                # Order the columns of the df
                gdf = gdf[ordered_cols]
                # Get times of each goal
                try:
                    for i in goal_frames:
                        goal_seconds.append(gdf.iloc[i]['game_seconds_remaining'])
                except IndexError:
                    with shared[5].get_lock():
                        shared[5].value += 1
                    copyfile(replay_path + file, error_path + file)
                    print('Index Error')
                    continue
                # Skip overtimes.
                if game_has_overtime:
                    if len(goal_seconds) == 1:
                        copyfile(replay_path + file, skip_path + file)
                        continue
                    else:
                        goal_seconds = goal_seconds[:-1]
                        goal_frames = goal_frames[:-1]

                trunc_length = add_game_columns(gdf, goal_frames, goal_seconds, goal_teams)

                # Fixing up missing values and rows after the last goal
                gdf = gdf.truncate(after=trunc_length - 1)
                # Drop when all player values are NA
                sub = ['z_0_pos_x', 'o_0_pos_x', 'z_1_pos_x', 'o_1_pos_x', 'z_2_pos_x', 'o_2_pos_x']
                gdf = gdf.dropna(how='all', subset=sub[:NUM_PLAYERS*2])
                # forward fill demos (Single player NA), then fill empty values (Ball values)
                for team in ['z_', 'o_']:
                    for i in range(NUM_PLAYERS):
                        num = str(i) + '_'
                        gen_list = ['pos_x', 'pos_y', 'pos_z', 'rot_x', 'rot_y', 'rot_z', 'vel_x', 'vel_y', 'vel_z',
                                    'ang_vel_x', 'ang_vel_y',
                                    'ang_vel_z', 'boost_active', 'jump_active', 'double_jump_active', 'dodge_active']
                        fill_list = [team + num + entry for entry in gen_list]
                        # Change demo column using presence of NA values
                        gdf[team + num + 'is_demo'] = gdf[fill_list].isna().replace({True: 1, False: 0}).mean(axis=1)
                        # Turn NA values into value before demo
                        for _ in fill_list:
                            gdf.loc[:, fill_list] = gdf.loc[:, fill_list].ffill(axis=0)

                # Drop the time after a goal is scored but before reset (in these casesm game_goal_number is N/A)
                gdf = gdf.dropna(axis='index', subset=['game_goal_number'])
                gdf = gdf.drop(['game_goal_number'], axis=1)
                gdf = gdf[gdf['secs_to_goal'] > 0]
                # Fill rest of NA value with 0
                gdf = gdf.fillna(0)
                # Change active values to boolean
                gdf['z_0_jump_active'] = ((gdf['z_0_jump_active'] % 2) != 0).astype(int)
                gdf['o_0_jump_active'] = ((gdf['o_0_jump_active'] % 2) != 0).astype(int)
                gdf['z_0_double_jump_active'] = ((gdf['z_0_double_jump_active'] % 2) != 0).astype(int)
                gdf['o_0_double_jump_active'] = ((gdf['o_0_double_jump_active'] % 2) != 0).astype(int)
                gdf['z_0_dodge_active'] = ((gdf['z_0_dodge_active'] % 2) != 0).astype(int)
                gdf['o_0_dodge_active'] = ((gdf['o_0_dodge_active'] % 2) != 0).astype(int)
                # Convert all booleans to 0 or 1
                gdf = gdf.replace({True: 1, False: 0})
                # Reduce size in memory
                # Write out to CSV after shrinking
                gdf = shrink_df(gdf)
                gdf.to_csv(output_path + file.split('.')[0] + '.csv')
                file_average[1] += 1
                file_average[0] += (datetime.now() - file_start)
                sys.stdout.flush()
            except(KeyboardInterrupt, SystemExit):
                break
    except(KeyboardInterrupt, SystemExit):
        pass
    # Update number of processes so reporting doesn't idle
    with shared[6].get_lock():
        shared[6].value -= 1
    print("{} Exiting".format(current_process().name))
    return
Exemple #13
0
 def decompile_replay(path: str) -> Union[pd.DataFrame, pd.DataFrame]:
     analysis_manager = carball.analyze_replay_file(path, logging_level=logging.CRITICAL)
     frames = analysis_manager.get_data_frame().fillna(value=0)
     stats = dict(analysis_manager.get_json_data())
     return frames, stats
def save_replay_dataframe(replay_file: str, save_file: str):
    data_frame = carball.analyze_replay_file(replay_file).data_frame
    data_frame.to_csv(save_file)
def replay_to_dfs(replay, skip_ties=True, skip_kickoffs=True):
    import pandas as pd
    import carball as cb

    if isinstance(replay, (str, bytes)):
        from carball.controls.controls import ControlsCreator
        replay = cb.analyze_replay_file(replay, controls=ControlsCreator(), logging_level=logging.CRITICAL)

    blue_team, orange_team = replay.game.teams
    if blue_team.is_orange:
        blue_team, orange_team = orange_team, blue_team

    frames = pd.DataFrame(index=replay.data_frame.index)

    frames[f"ball/pos_x"] = replay.game.ball["pos_x"].fillna(0.)
    frames[f"ball/pos_y"] = replay.game.ball["pos_y"].fillna(0.)
    frames[f"ball/pos_z"] = replay.game.ball["pos_z"].fillna(0.)

    frames[f"ball/vel_x"] = replay.game.ball["vel_x"].fillna(0.) / 10
    frames[f"ball/vel_y"] = replay.game.ball["vel_y"].fillna(0.) / 10
    frames[f"ball/vel_z"] = replay.game.ball["vel_z"].fillna(0.) / 10

    frames[f"ball/ang_vel_x"] = replay.game.ball["ang_vel_x"].fillna(0.) / 1000
    frames[f"ball/ang_vel_y"] = replay.game.ball["ang_vel_y"].fillna(0.) / 1000
    frames[f"ball/ang_vel_z"] = replay.game.ball["ang_vel_z"].fillna(0.) / 1000

    boost_grabs = pd.DataFrame(columns=["frame", "boost_id", "player"])

    player_index = {}
    player_df = pd.DataFrame(columns=["color", "online_id", "name"])
    i = 0
    for color, team in ("blue", blue_team), ("orange", orange_team):
        for player in team.players:
            player_index[player.online_id] = i
            frames[f"{i}/pos_x"] = player.data["pos_x"].fillna(0.)
            frames[f"{i}/pos_y"] = player.data["pos_y"].fillna(0.)
            frames[f"{i}/pos_z"] = player.data["pos_z"].fillna(0.)

            yaw = player.data["rot_y"].fillna(0.)
            pitch = player.data["rot_x"].fillna(0.)
            roll = player.data["rot_z"].fillna(0.)
            forward, up = rotator_to_matrix(yaw, pitch, roll)

            frames[f"{i}/forward_x"] = forward[0]
            frames[f"{i}/forward_y"] = forward[1]
            frames[f"{i}/forward_z"] = forward[2]

            frames[f"{i}/up_x"] = up[0]
            frames[f"{i}/up_y"] = up[1]
            frames[f"{i}/up_z"] = up[2]

            frames[f"{i}/vel_x"] = player.data["vel_x"].fillna(0.) / 10
            frames[f"{i}/vel_y"] = player.data["vel_y"].fillna(0.) / 10
            frames[f"{i}/vel_z"] = player.data["vel_z"].fillna(0.) / 10

            frames[f"{i}/ang_vel_x"] = player.data["ang_vel_x"].fillna(0.) / 1000
            frames[f"{i}/ang_vel_y"] = player.data["ang_vel_y"].fillna(0.) / 1000
            frames[f"{i}/ang_vel_z"] = player.data["ang_vel_z"].fillna(0.) / 1000

            frames[f"{i}/boost_amount"] = player.data["boost"].fillna(0.) / 2.55

            for col in player.controls.columns:
                frames[f"{i}/{col}_control"] = player.controls[col].astype(float)

            boost_pickups = player.data["boost"].diff() > 0
            for frame, row in player.data[boost_pickups].iterrows():
                xyz = (row["pos_x"], row["pos_y"], row["pos_z"])
                # TODO use boost ID instead
                closest_boost = min(range(len(boost_locations)),
                                    key=lambda j: sum((a - b) ** 2 for a, b in zip(xyz, boost_locations[j])))
                boost_grabs.loc[len(boost_grabs)] = [frame, closest_boost, i]

            player_df.loc[len(player_df)] = [color, player.online_id, player.name]
            i += 1

    rallies = pd.DataFrame(columns=["start_frame", "end_frame", "team"])
    for kf1, kf2 in zip(replay.game.kickoff_frames, replay.game.kickoff_frames[1:] + [replay.game.frames.index[-1]]):
        for goal in replay.game.goals:
            if kf1 < goal.frame_number < kf2:
                rallies.loc[len(rallies)] = [kf1, goal.frame_number, ["blue", "orange"][goal.player_team]]
                break
        else:  # No goal between kickoffs
            rallies.loc[len(rallies)] = [kf1, kf2, None]

    demos = pd.DataFrame(columns=["frame", "attacker", "victim"])
    for demo in replay.game.demos:
        frame = demo.get("frame_number", None)
        attacker = demo.get("attacker", None)
        victim = demo.get("victim", None)

        if frame and attacker and victim:
            demos.loc[len(demos)] = [frame, player_index[attacker.online_id], player_index[victim.online_id]]

    touches = pd.DataFrame(columns=["frame", "player"])
    for touch in replay.protobuf_game.game_stats.hits:
        touches.loc[len(touches)] = [touch.frame_number, player_index[touch.player_id.id]]

    if skip_ties:
        goal_rallies = rallies[rallies["team"].notna()]
        frames = frames.loc[
            np.r_[tuple(slice(row["start_frame"], row["end_frame"]) for _, row in goal_rallies.iterrows())]]
    elif skip_kickoffs:
        goal_rallies = rallies
        frames = frames.loc[
            np.r_[tuple(slice(row["start_frame"], row["end_frame"]) for _, row in goal_rallies.iterrows())]]

    # if isinstance(frame_mode, int):
    #     frames = frames.iloc[np.random.randint(0, frame_mode)::frame_mode]
    # else:
    #     frames = frames.sample(frac=frame_mode)

    return {"frames": frames, "rallies": rallies, "touches": touches, "boost_grabs": boost_grabs, "demos": demos,
            "players": player_df}
def parse_replay(
        self,
        filename,
        preserve_upload_date: bool = False,
        # url parameters
        query_params: Dict[str, any] = None,
        # test parameters
        custom_file_location: str = None,
        force_reparse: bool = False):
    """
    :param self:
    :param filename: filename
    :param query_params: The arguments from the url
    :param preserve_upload_date: If true the upload date is retained
    :param custom_file_location: If a custom file path should be used instead
    :param force_reparse: if true parsing will happen even if a file already exists.
    :return:
    """

    if custom_file_location is None:
        pickled = os.path.join(get_default_parse_folder(),
                               os.path.basename(filename))
    else:
        pickled = os.path.join(custom_file_location,
                               os.path.basename(filename))
    if custom_file_location is None:
        failed_dir = os.path.join(os.path.dirname(get_default_parse_folder()),
                                  'failed')
    else:
        failed_dir = custom_file_location
    if os.path.isfile(pickled) and not force_reparse:
        return
    # try:
    try:
        analysis_manager = analyze_replay_file(filename)  # type: ReplayGame
    except Exception as e:
        if not os.path.isdir(failed_dir):
            os.makedirs(failed_dir)
        shutil.move(filename,
                    os.path.join(failed_dir, os.path.basename(filename)))
        with open(
                os.path.join(failed_dir,
                             os.path.basename(filename) + '.txt'), 'a') as f:
            f.write(str(e))
            f.write(traceback.format_exc())
        raise e
    try:
        if not os.path.isdir(os.path.dirname(pickled)):
            os.makedirs(os.path.dirname(pickled))
        with open(pickled + '.pts', 'wb') as fo:
            analysis_manager.write_proto_out_to_file(fo)
        with gzip.open(pickled + '.gzip', 'wb') as fo:
            analysis_manager.write_pandas_out_to_file(fo)
    except Exception as e:
        log_error(e, logger=logger)
        with open(
                os.path.join(failed_dir,
                             os.path.basename(filename) + '.txt'), 'a') as f:
            f.write(str(e))
            f.write(traceback.format_exc())

    # success!
    proto_game = analysis_manager.protobuf_game

    if proto_game.game_metadata.match_guid is None or proto_game.game_metadata.match_guid == '':
        proto_game.game_metadata.match_guid = proto_game.game_metadata.id

    parsed_replay_processing(proto_game,
                             query_params,
                             preserve_upload_date=preserve_upload_date)

    return save_replay(proto_game, filename, pickled)
Exemple #17
0
def main(program_args=None):
    parser = argparse.ArgumentParser(
        description='Rocket League replay parsing and analysis.')
    parser.add_argument(
        '-i',
        '--input',
        type=str,
        required=True,
        help=
        'Path to replay file that will be analyzed. Carball expects a raw replay file unless '
        '--skip-decompile is provided.')
    parser.add_argument(
        '--proto',
        type=str,
        required=False,
        help=
        'The result of the analysis will be saved to this file in protocol buffers format.'
    )
    parser.add_argument(
        '--json',
        type=str,
        required=False,
        help=
        'The result of the analysis will be saved to this file in json file format.'
    )
    parser.add_argument(
        '--gzip',
        type=str,
        required=False,
        help=
        'The pandas data frame containing the replay frames will be saved to this file in a '
        'compressed gzip format.')
    parser.add_argument(
        '-v',
        '--verbose',
        action='count',
        default=0,
        help=
        'Set the logging level to INFO. To set the logging level to DEBUG use -vv.'
    )
    parser.add_argument('-s',
                        '--silent',
                        action='store_true',
                        default=False,
                        help='Disable logging altogether.')
    parser.add_argument(
        '-dr',
        '--dry-run',
        action='store_true',
        default=False,
        help=
        'Explicitly notifying that there is not going to be any output to be saved'
    )
    if program_args is not None:
        args = parser.parse_args(program_args)
    else:
        args = parser.parse_args()

    if not args.proto and not args.json and not args.gzip and not args.dry_run:
        parser.error(
            'at least one of the following arguments are required: --proto, --json, --gzip'
        )

    log_level = logging.WARNING

    if args.verbose == 1:
        log_level = logging.INFO
    elif args.verbose >= 2:
        log_level = logging.DEBUG

    if args.silent:
        logging.basicConfig(handlers=[logging.NullHandler()])
    else:
        logging.basicConfig(handlers=[logging.StreamHandler()],
                            level=log_level)

    manager = carball.analyze_replay_file(args.input)

    if args.proto:
        with open(args.proto, 'wb') as f:
            manager.write_proto_out_to_file(f)
    if args.json:
        with open(args.json, 'w') as f:
            manager.write_json_out_to_file(f)
    if args.gzip:
        with gzip.open(args.gzip, 'wb') as f:
            manager.write_pandas_out_to_file(f)
Exemple #18
0
def make_summary(rp, model):
    if isinstance(rp, str):
        rp = cb.analyze_replay_file(rp, logging_level=logging.CRITICAL)

    pp = replay_to_dfs(rp, skip_ties=False)

    cpx, cpy = convert_dfs(pp, frame_mode=1)
    # print(cpy)

    normalize(cpx)

    pred_df = pd.DataFrame(index=pp["frames"].index)

    model.eval()

    with torch.no_grad():

        def get_predictions(x_data):
            preds = None
            bs = 1024
            lo, hi = 0, bs
            for batch in range(bs, len(x_data[0]) + bs, bs):
                hi = min(batch, len(x_data[0]))

                batch_x = [v[lo:hi] for v in x_data]
                batch_preds_b = model(
                    *[torch.from_numpy(v).float().cuda() for v in batch_x])
                batch_preds_b = [
                    bp.cpu().detach().numpy() for bp in batch_preds_b
                ]

                # swap_teams(batch_x)
                # batch_preds_s = model(*[torch.from_numpy(v).float().cuda() for v in batch_x])
                # batch_preds_s = [bp.cpu().detach().numpy() for bp in batch_preds_s]
                #
                # swap_left_right(batch_x)
                # batch_preds_sm = model(*[torch.from_numpy(v).float().cuda() for v in batch_x])
                # batch_preds_sm = [bp.cpu().detach().numpy() for bp in batch_preds_sm]
                #
                # swap_teams(batch_x)
                # batch_preds_m = model(*[torch.from_numpy(v).float().cuda() for v in batch_x])
                # batch_preds_m = [bp.cpu().detach().numpy() for bp in batch_preds_m]
                #
                # batch_preds = [(b + s + m + sm) / 4 for b, s, m, sm in
                #                zip(batch_preds_b, batch_preds_s, batch_preds_m, batch_preds_sm)]
                batch_preds = batch_preds_b

                if preds is None:
                    preds = batch_preds
                else:
                    preds = [
                        np.concatenate([p, bp])
                        for p, bp in zip(preds, batch_preds)
                    ]
                lo = hi
            return preds

        # 1. Get predictions with all players
        preds = get_predictions(cpx)
        pred_df["pred"] = preds[0][:, 0] - preds[0][:, 1]

        for i, row in pp["players"].iterrows():
            color = row["color"]
            sgn = 1 if color == "blue" else -1
            cpxc = [np.copy(v) for v in cpx]
            cpxc[2] = cpxc[2][:, [k for k in range(cpx[2].shape[1]) if k != i]]

            # 2. Get predictions with one player removed
            preds = get_predictions(cpxc)
            pred_df[f"{i}/pred_removed"] = preds[0][:, 0] - preds[0][:, 1]

            cpxc = [np.copy(v) for v in cpx]
            cpxc[2] = cpxc[2][:, [i]]

            # 3. Get predictions with teammates removed
            preds = get_predictions(cpxc)
            pred_df[f"{i}/pred_solo"] = preds[0][:, 0] - preds[0][:, 1]

            # pred_df[f"{identifier}/pred"] = sigmoid(sgn * pred_df["pred"]) * \
            #                                 sigmoid(sgn * pred_df[f"{identifier}/pred_solo"]) / \
            #                                 sigmoid(sgn * pred_df[f"{identifier}/pred_removed"])

            pred_df[f"{i}/pred"] = sgn * (pred_df["pred"] -
                                          pred_df[f"{i}/pred_removed"])

            # pred_df[f"{identifier}/pred"] = sgn * (
            #         pred_df["pred"] - pred_df[f"{identifier}/pred_removed"] + pred_df[f"{identifier}/pred_solo"])

        return pred_df, pp
Exemple #19
0
def plot_replay(rp_path,
                model,
                plot_players=True,
                invert=None,
                plot_goal_distance=False):
    if plot_players is True:
        plot_players = ("blue", "orange")
    elif plot_players is False:
        plot_players = ()
    elif plot_players == "blue":
        plot_players = ("blue", )
    elif plot_players == "orange":
        plot_players = ("orange", )
    else:
        plot_players = ()

    rp = cb.analyze_replay_file(rp_path,
                                controls=ControlsCreator(),
                                logging_level=logging.CRITICAL)

    id_team = {
        p.online_id: ["blue", "orange"][p.team.is_orange]
        for p in rp.game.players
    }
    id_name = {p.online_id: p.name for p in rp.game.players}

    pred_df, dfs = make_summary(rp, model)

    if invert is None:
        d = 0
        for goal in rp.game.goals:
            if goal.player.is_orange:
                d += 1
            else:
                d -= 1
        invert = d < 0

    # pp["pred"][pp["ball/ball/vel_y"] == 0] = float("nan")
    # pp["pred"][pp["ball/ball/vel_y"].isna()] = float("nan")

    fig, ax = plt.subplots(figsize=((6.4 * dfs["frames"].index[-1] + 1000) /
                                    5000, 4.8),
                           dpi=400,
                           constrained_layout=True)

    ax.hlines(0.5,
              xmin=0,
              xmax=dfs["frames"].index[-1],
              color="black",
              linestyle="dashed")

    blue_shots = []
    orange_shots = []

    blue_saves = []
    orange_saves = []

    for hit in rp.protobuf_game.game_stats.hits:
        if hit.shot:
            if id_team[hit.player_id.id] == "blue":
                blue_shots.append(hit.frame_number)
            else:
                orange_shots.append(hit.frame_number)
        if hit.save:
            if id_team[hit.player_id.id] == "blue":
                blue_saves.append(hit.frame_number)
            else:
                orange_saves.append(hit.frame_number)

    blue_ymin, blue_ymax, orange_ymin, orange_ymax = (0.5, 1, 0,
                                                      0.5) if invert else (0,
                                                                           0.5,
                                                                           0.5,
                                                                           1)

    ax.vlines(blue_shots,
              ymin=blue_ymin,
              ymax=blue_ymax,
              color="m",
              linestyle="dotted",
              label="Shot")
    ax.vlines(orange_shots,
              ymin=orange_ymin,
              ymax=orange_ymax,
              color="m",
              linestyle="dotted")

    ax.vlines(blue_saves,
              ymin=orange_ymin,
              ymax=orange_ymax,
              color="c",
              linestyle="dotted",
              label="Save")
    ax.vlines(orange_saves,
              ymin=blue_ymin,
              ymax=blue_ymax,
              color="c",
              linestyle="dotted")

    if plot_goal_distance:
        goal_location = np.array([0, -5120 if invert else 5120, 642 / 2])
        distances = np.linalg.norm(
            np.tile(goal_location, len(dfs["frames"])).reshape(
                (len(dfs["frames"]), 3)) -
            dfs["frames"].filter(regex="ball/pos_").values,
            axis=-1)
        ax.plot(dfs["frames"].index,
                distances / 11216,
                label="Ball-Goal Distance")

    pred = sigmoid(pred_df["pred"])
    ax.plot(dfs["frames"].index,
            pred if invert else 1 - pred,
            color="blue",
            label="Advantage")

    blue_colors = ["springgreen", "mediumseagreen", "green"]
    orange_colors = ["lightcoral", "indianred", "brown"]
    # plt.show()

    b = o = 0
    for i, row in dfs["players"].iterrows():
        name = row["name"]
        color = row["color"]

        avg_score = np.exp(pred_df[f"{i}/pred"].mean())
        print(name, avg_score)

        # pred_df[f"{identifier}/pred"].plot.hist(title=name, bins=100)
        # plt.show()

        pred_col = sigmoid(pred_df[f"{i}/pred"])
        if color == "blue" and "blue" in plot_players:
            ax.plot(dfs["frames"].index,
                    pred_col if invert else 1 - pred_col,
                    color=blue_colors[b],
                    label=name,
                    linewidth=0.5)
            b += 1
        elif color == "orange" and "orange" in plot_players:
            ax.plot(dfs["frames"].index,
                    1 - pred_col if invert else pred_col,
                    color=orange_colors[o],
                    label=name,
                    linewidth=0.5)
            o += 1

    rallies = dfs["rallies"]
    ax.vlines(rallies[rallies["team"].notna()]["end_frame"],
              ymin=0,
              ymax=1,
              color="red",
              label="Goal")
    ax.set_xlim(0, dfs["frames"].index[-1])
    ax.set_ylim(0, 1)
    ax.set_xlabel("Frame")
    ax.set_ylabel("Orange <-> Blue" if invert else "Blue <-> Orange")
    ax.set_title(rp.game.name)
    ax.legend(bbox_to_anchor=(1.01, 1), loc='upper left')

    secax = ax.twiny()
    new_tick_locations = []
    new_ticks = []
    taken = None
    for frame in reversed(rp.game.frames.index):
        left = rp.game.frames["seconds_remaining"].loc[frame]
        if np.isnan(left):
            continue
        left = int(left)
        if left % 10 == 0 and left != taken:
            new_tick_locations.append(frame)
            new_ticks.append("{0:.0f}:{1:02.0f}".format(
                *divmod(rp.game.frames["seconds_remaining"].loc[frame], 60)))
            taken = left
    secax.set_xlim(*ax.get_xlim())
    secax.set_xticks(new_tick_locations)
    secax.set_xticklabels(new_ticks)
    secax.set_xlabel("Time")

    ax.grid()
    # df["pred"].plot(x=df["game/info/frame"], color="blue")
    return fig, dfs
Exemple #20
0
if replay_parsing_file.is_file():
    with replay_parsing_file.open("r") as f:
        replays_parsing = json.load(f)
else:
    replays_parsing = {}

for replay in replays:
    print("\n")
    print(replay)

    if replays_parsing.get(str(replay), False) is True:
        print("\tReplay previously parsed. Skipping...")
        continue
    try:
        analysis_manager = carball.analyze_replay_file(str(replay))
        proto_game = analysis_manager.get_protobuf_data()
        dataframe = analysis_manager.get_data_frame()

        print(
            f"\tplayers name and score: {[(player.name, player.score) for player in proto_game.players]}"
        )
        print(f"\tdf length: {len(dataframe)}")

        replays_parsing[str(replay)] = True
    except:
        import traceback

        traceback.print_exc()
        replays_parsing[str(replay)] = traceback.format_exc()
Exemple #21
0
def main():
    parser = argparse.ArgumentParser(
        description='Rocket League replay parsing and analysis.')
    parser.add_argument(
        '-i',
        '--input',
        type=str,
        required=True,
        help=
        'Path to replay file that will be analyzed. Carball expects a raw replay file unless '
        '--skip-decompile is provided.')
    parser.add_argument(
        '--proto',
        type=str,
        required=False,
        help=
        'The result of the analysis will be saved to this file in protocol buffers format.'
    )
    parser.add_argument(
        '--json',
        type=str,
        required=False,
        help=
        'The result of the analysis will be saved to this file in json file format. This is not '
        'the decompiled replay json from rattletrap.')
    parser.add_argument(
        '--gzip',
        type=str,
        required=False,
        help=
        'The pandas data frame containing the replay frames will be saved to this file in a '
        'compressed gzip format.')
    parser.add_argument(
        '-sd',
        '--skip-decompile',
        action='store_true',
        default=False,
        help=
        'If set, carball will treat the input file as a json file that Rattletrap outputs.'
    )
    parser.add_argument(
        '-v',
        '--verbose',
        action='count',
        default=0,
        help=
        'Set the logging level to INFO. To set the logging level to DEBUG use -vv.'
    )
    parser.add_argument('-s',
                        '--silent',
                        action='store_true',
                        default=False,
                        help='Disable logging altogether.')
    args = parser.parse_args()

    if not args.proto and not args.json and not args.gzip:
        parser.error(
            'at least one of the following arguments are required: --proto, --json, --gzip'
        )

    log_level = logging.WARNING

    if args.verbose == 1:
        log_level = logging.INFO
    elif args.verbose >= 2:
        log_level = logging.DEBUG

    if args.silent:
        logging.basicConfig(handlers=[logging.NullHandler()])
    else:
        logging.basicConfig(handlers=[logging.StreamHandler()],
                            level=log_level)

    if args.skip_decompile:
        game = Game()
        game.initialize(loaded_json=args.input)
        manager = AnalysisManager(game)
        manager.create_analysis()
    else:
        manager = carball.analyze_replay_file(args.input)

    if args.proto:
        with open(args.proto, 'wb') as f:
            manager.write_proto_out_to_file(f)
    if args.json:
        proto_game = manager.get_protobuf_data()
        with open(args.json, 'w') as f:
            f.write(MessageToJson(proto_game))
    if args.gzip:
        with gzip.open(args.gzip, 'wb') as f:
            manager.write_pandas_out_to_file(f)