Example #1
0
def test():
    fp = SLP_PATH + 'run_2.slp'
    game = slp.Game(fp)
    frames = game.frames[123:]
    i = 0
    for f in frames:
        print(f.ports[1].leader.post.hit_stun)
    print("done")
Example #2
0
def parseFile(filename):
    """
    Return a slippi game object from a filename

    :param filename: filename to be read
    :return: slippi game object
    :seealso: https://py-slippi.readthedocs.io/en/latest/source/slippi.html#module-slippi.game
    """
    game = slippi.Game(filename)
    return game
Example #3
0
File: data.py Project: girffy/mmrl
def parse_slp_file(slp_file, drive):
    try:
        game = slippi.Game(slp_file)
    except Exception as e:
        print("WARNING: slippi parsing exception while reading %s:" % slp_file)
        print("%s: %s" % (type(e), e))
        print("Skipping this replay")
        return None

    #start_date = pytz.timezone(config.TIME_ZONE).localize(game.metadata.date)
    start_time = game.metadata.date.replace(
        tzinfo=pytz.timezone(config.TIME_ZONE))
    end_time = start_time + datetime.timedelta(seconds=game.metadata.duration /
                                               60.)
    stage = game.start.stage

    ports = []
    numplayers = 0
    for i, port in enumerate(game.frames[-1].ports):
        if port == None:
            ports.append(None)
            continue

        # TODO: more robust win/lose logic, e.g. handle timeouts and LRAstart
        isdead = port.leader.post.stocks == 0
        charname = port.leader.post.character.name

        # address a weird edge case with ICs where popo dies last
        if charname == 'POPO':
            charname = 'ICE_CLIMBERS'

        ports.append({'char': charname, 'dead_at_end': isdead})
        numplayers += 1

    time_offset = datetime.timedelta(0)
    if drive in config.DRIVE_TIME_OFFSETS:
        time_offset = datetime.timedelta(
            seconds=config.DRIVE_TIME_OFFSETS[drive])

    dct = {
        'start_time': start_time - time_offset,
        'end_time': end_time - time_offset,
        'filename': slp_file,
        'drive': drive,
        'ports': ports,
        'stage': stage.name,
        'numplayers': numplayers,
    }

    return dct
Example #4
0
def record_replay(replay_filepath,
                  output_dir='../vid_out/',
                  slowdown_factor=1.1):

    # paths
    replay_filepath = Path(replay_filepath)
    dolphin_folder_path = Path(r'../dolphin')
    executable_path = dolphin_folder_path / 'Slippi Dolphin.exe'
    iso_path = read_json('../settings.json')['iso_path']
    tmp_output_folder = Path(
        '../tmp/dolphin_process_0'
    )  # if multiple dolphins output to same folder, there would be default filename conflicts with "framedump0.avi"
    real_output_folder = Path(output_dir)

    DEFAULT_VIDEO_NAME = 'framedump0.avi'
    old_video_path = tmp_output_folder / DEFAULT_VIDEO_NAME
    new_video_name = replay_filepath.stem + '.avi'
    new_video_path = real_output_folder / new_video_name

    # clear tmp (could have files if error on last run)
    shutil.rmtree(tmp_output_folder)
    os.mkdir(tmp_output_folder)

    # get how long it should take to finish playback
    game = slippi.Game(replay_filepath)
    num_frames = len(game.frames)
    FPS = 60
    duration_sec = num_frames / FPS

    # prep instructions for slippi dolphin to replay
    comm_filepath = generate_commfile(replay_filepath)

    # start dolphin, giving commfile (location) and other misc flags
    # for standard dolphin cmd line, see
    #  https://wiki.dolphin-emu.org/index.php?title=Help:Contents
    process = subprocess.Popen([
        str(executable_path),
        '-i',
        str(comm_filepath),
        '--hide-seekbar',
        '-e',
        str(iso_path),
        '-b',
        # '-l',
        # '-d',
        '--output-directory',
        str(tmp_output_folder),
    ])

    # I wish I could get a dolphin.on_start_playback and on_finish
    #   but this crude dircheck and sleep() will have to suffice

    # wait until video file is created, signaling start
    # print('waiting on dolphin start..')
    while not os.listdir(tmp_output_folder):
        pass
    # print('dolphin has started playing')

    # wait in realtime for replay to finish
    # 4:02 (+123 f) of game duration only made 3:41 of video with slowdown; guess my computer is not fast enough for realtime
    # 244 s made 221 s, so multiply by factor of 244/221 ~= 1.104
    sleep(slowdown_factor *
          duration_sec)  # overshoot with extra time as buffer

    # close dolphin, which will finish recording
    process.terminate()

    # give it time to close so video file can be modified
    sleep(1)

    # abort if video is too short (ie didn't finish)
    if video_tools.num_frames(str(old_video_path)) < num_frames:
        raise Exception(
            'Video did not finish recording; trying again with slowdown_factor + 0.1 ?'
        )
        # return record_replay(replay_filepath, output_dir, slowdown_factor+0.1)
        return -1

    # prep new location
    if new_video_path.exists():
        os.remove(new_video_path)
    # move_file(old_video_path, new_video_path)

    # trim excess "waiting for game.." frames and move to final location
    video_tools.trim(0, num_frames, str(old_video_path), str(new_video_path))
Example #5
0
def record_hs(path, plotname):
	game = slp.Game(path)
	frames = game.frames[123:]
	sdict = actionstate_dict()
	adict = attack_dict()

	p0_name = game.metadata.players[0].netplay_name
	p1_name = game.metadata.players[1].netplay_name

	# now try rolling average: 
	p0_wind = []
	p0_wsum = 0

	p1_wind = []
	p1_wsum = 0

	p0_dwind = []
	p0_dsum = 0
	p0_hp = 0

	p1_dwind = []
	p1_dsum = 0
	p1_hp = 0

	# things to analyze 
	p0_map = []
	p0_dmap = []

	p1_map = []
	p1_dmap = []

	p0_scores = []
	p1_scores = []

	fcount = []
	fc = 0

	for f in frames:
		fcount.append(fc)
		fc += 1 

		p0_ths = f.ports[0].leader.post.hit_stun
		p0_tdam = f.ports[0].leader.post.damage
		p1_ths = f.ports[1].leader.post.hit_stun 
		p1_tdam = f.ports[1].leader.post.damage

		# took damage 
		if p0_tdam > p0_hp: 
			p0_dwind.append(p0_tdam - p0_hp)
			p0_dsum += p0_tdam - p0_hp
		else: 
			p0_dwind.append(0)
		if p0_ths > 0.1: 
			p0_wsum += p0_ths
			p0_wind.append(p0_ths)
		else: 
			p0_wind.append(0)


		if p1_tdam > p1_hp:
			p1_dwind.append(p1_tdam - p1_hp)
			p1_dsum += p1_tdam - p1_hp
		else: 
			p1_dwind.append(0)
		if p1_ths > 0.1: 
			p1_wsum += p1_ths
			p1_wind.append(p1_ths)
		else: 
			p1_wind.append(0)


		# check lengths & adjust
		if(len(p0_wind) > WINDOW):
			p0_wsum -= p0_wind[0] 
			p0_wind.pop(0)
		if(len(p1_wind) > WINDOW):
			p1_wsum -= p1_wind[0] 
			p1_wind.pop(0)

		if(len(p0_dwind) > WINDOW): 
			p0_dsum -= p0_dwind[0]
			p0_dwind.pop(0)
		if(len(p1_dwind) > WINDOW): 
			p1_dsum -= p1_dwind[0]
			p1_dwind.pop(0)

		p0_map.append(p0_wsum)
		p0_dmap.append(p0_dsum)

		p1_map.append(p1_wsum)
		p1_dmap.append(p1_dsum)

		# calculate combo scores 
		# note: port 0's score is based on port 1's damage & hitstun values, as they
		# were a result of his attacks (same w/ port 2)
		p0_scores.append(comboscore(p1_dsum, p1_wsum))
		p1_scores.append(comboscore(p0_dsum, p0_wsum))


		# adjust hp for next frame
		p0_hp = p0_tdam
		p1_hp = p1_tdam

	fig, (ax1, ax2) = plt.subplots(2)
	ax1.plot(fcount, p0_map, label = p0_name)
	ax1.plot(fcount, p1_map, label = p1_name, color = 'red')
	ax1.set_title('hitstun map')
	ax1.legend()
	ax2.plot(fcount, p0_dmap, label = p0_name)
	ax2.plot(fcount, p1_dmap, label = p1_name, color = 'red')
	ax2.set_title('damage map')
	ax2.legend()
	fig.savefig('test_out/{}.png'.format(plotname))

	scorefig, ax = plt.subplots()
	ax.plot(fcount, p0_scores, label = p0_name)
	ax.plot(fcount, p1_scores, label = p1_name)
	ax.legend()
	scorefig.savefig('test_out/{}_cscores.png'.format(plotname))
Example #6
0
def find_combos(slp_path):
    game = slp.Game(slp_path)

    # cut the first 123 frames since its game startup
    frames = game.frames[123:]
    sdict = actionstate_dict()
    adict = attack_dict()

    # numbers to keep track of
    # char state:
    p1_prev_state = frames[0].ports[0].leader.post.state
    p2_prev_state = frames[0].ports[1].leader.post.state
    # current hitstun frames
    p1_hs = 0.5
    p2_hs = 0.5
    # each player's last percent
    p1_dam = 0
    p2_dam = 0
    # last attack landed
    p1_lal = None
    p2_lal = None

    # record rolling averages and stuff
    comboer = 0
    victim = 1
    window_hs = 0
    state = State.NEUTRAL
    combo_counter = 0

    # record when hits occured
    # key = frame, val = attack/combo start/stop
    hitmap = {}
    combomap = {}

    fcount = 0
    for f in frames:
        # for now, just look @ fox since i know he's the one getting abused
        if f.ports[victim].leader.post.damage > p2_dam:
            p1_lal = f.ports[comboer].leader.post.last_attack_landed
            if p1_lal < 30:
                hitmap[fcount] = (adict[p1_lal],
                                  f.ports[victim].leader.post.damage - p2_dam)
            else:
                hitmap[fcount] = (sdict[p1_lal],
                                  f.ports[victim].leader.post.damage - p2_dam)

        p2_dam = f.ports[victim].leader.post.damage
        p2_hs = f.ports[victim].leader.post.hit_stun

        # rolling hitstun counter
        if fcount > WINDOW:
            window_hs -= 1

        if f.ports[1].leader.post.hit_stun >= 1:
            window_hs += 1

        if window_hs >= HST and state != State.COMBO:
            state = State.COMBO
            combomap[fcount] = "combo started"

        else:
            # check for which non-combo status
            # if (neutral):
            # if (edgeguard):
            # if (offstage):
            # if (reverse):
            pass

        fcount += 1

    # write hitmap
    with open('ref/' + slp_path[-9:-4] + '_hitmap.json', 'w') as outfile:
        json.dump(hitmap, outfile, indent=4)
Example #7
0
def record_moves(slp_path, filename):
    game = slp.Game(slp_path)
    frames = game.frames[123:]
    sdict = actionstate_dict()
    adict = attack_dict()

    # record the metadata of the game
    md = game.metadata
    # dict. to record new charstates
    # key = state, val = initial frame it was found in
    falco_states = {}
    fox_states = {}
    moves = {}

    falco_states["duration"] = md.duration
    fox_states["duration"] = md.duration

    count = 0
    for f in frames:
        falstate = f.ports[0].leader.post.state
        foxstate = f.ports[1].leader.post.state
        last_move = f.ports[0].leader.post.last_attack_landed

        if falstate not in falco_states.keys():
            falco_states[sdict[falstate]] = count
        if foxstate not in fox_states.keys():
            fox_states[sdict[foxstate]] = count

        if last_move != None and last_move not in moves.keys():
            # if moves in the common moves list: if not, pull from char_states
            if int(last_move) > 30:
                moves[sdict[last_move]] = count
            else:
                moves[adict[last_move]] = count

        count += 1

    # reorder by value
    falco_states = {
        k: v
        for k, v in sorted(falco_states.items(), key=lambda item: item[1])
    }
    fox_states = {
        k: v
        for k, v in sorted(fox_states.items(), key=lambda item: item[1])
    }
    moves = {k: v for k, v in sorted(moves.items(), key=lambda item: item[1])}

    # export to a json file to look at
    with open('ref/' + filename + '.json', 'w') as outfile:
        json.dump(falco_states, outfile, indent=4)

    with open('ref/fox_' + filename + '.json', 'w') as outfile:
        json.dump(fox_states, outfile, indent=4)

    with open('ref/attacks_' + filename + '.json', 'w') as outfile:
        json.dump(moves, outfile, indent=4)

    # transforms the frame count to the IGT that you should be looking at
    def frame_to_sec(frame):
        # in total there are 60 * 60 * 8 frames total in a match
        total = 60 * 60 * 8
        return total
Example #8
0
def load(f="/Users/markvan/Slippi/Game_20200710T220209.slp"):
    return sl.Game(f)