15个版本 (2个稳定版)

2.0.1 2024年4月7日
2.0.0 2024年3月30日
2.0.0-alpha.42024年1月7日
2.0.0-alpha.22023年12月9日
1.0.0-alpha.32021年7月5日

#371 in 解析实现

Download history 12/week @ 2024-05-19 2/week @ 2024-06-09 2/week @ 2024-06-16 143/week @ 2024-06-30 97/week @ 2024-07-07 1/week @ 2024-07-14 98/week @ 2024-07-28 1/week @ 2024-08-04

102 每月下载量

MIT 协议

215KB
6.5K SLoC

Rust 5.5K SLoC // 0.0% comments Clojure 1K SLoC // 0.0% comments Edn 3 SLoC

Peppi

test

Peppi是用于任天堂GameCube上的《超级 Smash Brothers Melee》的.slp游戏回放文件的Rust解析器。这些回放是由Jas Laferriere的Slippi录制代码生成的,该代码运行在Wii或Dolphin仿真器上。

⚠️ slp工具已移动到peppi-slp包。

安装

在你的Cargo.toml

[dependencies]
peppi = "2.0"

用法

使用.slp进行一次性的解析(对于.slpp,请使用peppi::read代替)

use std::{fs, io};
use peppi::io::slippi::read;

fn main() {
    let mut r = io::BufReader::new(fs::File::open("tests/data/game.slp").unwrap());
    let game = read(&mut r, None).unwrap();
    println!("{:#?}", game);
}
更复杂的示例
use std::{fs, io};
use peppi::io::slippi::read;
use peppi::frame::Rollbacks;

// `ssbm-data` provides enums for characters, stages, action states, etc.
// You can just hard-code constants instead, if you prefer.
use ssbm_data::action_state::Common::{self, *};

/// Print the frames on which each player died.
fn main() {
    let mut r = io::BufReader::new(fs::File::open("tests/data/game.slp").unwrap());
    let game = read(&mut r, None).unwrap();

    let mut is_dead = vec![false; game.frames.ports.len()];
    let rollbacks = game.frames.rollbacks(Rollbacks::ExceptLast);
    for frame_idx in 0..game.frames.len() {
        if rollbacks[frame_idx] {
            continue;
        }
        for (port_idx, port_data) in game.frames.ports.iter().enumerate() {
            match port_data
                .leader
                .post
                .state
                .get(frame_idx)
                .and_then(|s| Common::try_from(s).ok())
            {
                Some(DeadDown)
                | Some(DeadLeft)
                | Some(DeadRight)
                | Some(DeadUp)
                | Some(DeadUpStar)
                | Some(DeadUpStarIce)
                | Some(DeadUpFall)
                | Some(DeadUpFallHitCamera)
                | Some(DeadUpFallHitCameraFlat)
                | Some(DeadUpFallIce)
                | Some(DeadUpFallHitCameraIce) => {
                    if !is_dead[port_idx] {
                        is_dead[port_idx] = true;
                        println!(
                            "{} died on frame {}",
                            game.start.players[port_idx].port,
                            game.frames.id.get(frame_idx).unwrap(),
                        )
                    }
                }
                _ => is_dead[port_idx] = false,
            }
        }
    }
}
实时解析
use std::fs;
use std::io::BufReader;
use byteorder::ReadBytesExt;
use peppi::io::slippi::de;

fn main() {
    let mut r = BufReader::new(fs::File::open("tests/data/game.slp").unwrap());

    // UBJSON wrapper (skip if using spectator protocol)
    let size = de::parse_header(&mut r, None).unwrap() as usize;

    // payload sizes & game start
    let mut state = de::parse_start(&mut r, None).unwrap();

    // loop until we hit GameEnd or run out of bytes
    while de::parse_event(&mut r, &mut state, None).unwrap() != de::Event::GameEnd as u8
        && state.bytes_read() < size
    {
        println!(
            "current frame number: {:?}",
            state.frames().id.iter().last()
        );
    }

    // `U` (0x55) means metadata next (skip if using spectator protocol)
    if r.read_u8().unwrap() == 0x55 {
        de::parse_metadata(&mut r, &mut state, None).unwrap();
    }
}

开发

src/frame中的Rust源文件是使用Clojure从frames.json生成的,该文件描述了每个规范版本中存在的每个帧的字段。如果您修改了frames.jsongen/src中的生成器代码,请运行gen/scripts/frames以重新生成这些Rust文件。

如果您正在添加对规范新版本的支持,您还需要更新 peppi::io::slippi::MAX_SUPPORTED_VERSION

目标

  • 性能:Peppi旨在成为.slp文件最快的解析器。
  • 易用性:与解析数据交互应该既简单又自然。
  • 宽容度:在可行的情况下,对格式不正确的数据进行接受并警告。
  • 跨语言支持:其他语言应该能够轻松高效地与Peppi交互。
  • 往返测试:Peppi可以解析回放,并将其完全相同地写回。
  • 替代格式:Peppi提供了一个替代格式,它比.slp更具可压缩性和易于处理。

Peppi格式

Peppi格式(.slpp)是一个包含以下文件的GNU tar存档,顺序如下

  • peppi.json:Peppi特定信息。
  • metadata.json:Slippi的元数据块
  • start.json:游戏开始事件的JSON表示。
  • start.raw:原始二进制游戏开始事件。
  • end.json:游戏结束事件的JSON表示。
  • end.raw:原始二进制游戏结束事件。
  • frames.arrow:以箭头格式(见下文)表示的帧数据。

大部分数据在frames.arrow中,这是一个包含所有游戏帧数据的Arrow IPC文件。这是一个列格式,使得.slpp大约是.slp的两倍可压缩。

要转换格式,请使用slp CLI工具。

依赖项

~15–26MB
~475K SLoC