#![allow(unused_variables)]
mod peppi;
mod slippi;
use std::fmt;
use arrow2::{array::PrimitiveArray, bitmap::Bitmap, buffer::Buffer, offset::OffsetsBuffer};
use crate::{
frame::{self, Rollbacks, mutable, transpose},
game::Port,
io::slippi::Version,
};
#[derive(Debug)]
pub struct Data {
pub pre: Pre,
pub post: Post,
pub validity: Option<Bitmap>,
}
impl Data {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Data {
transpose::Data {
pre: self.pre.transpose_one(i, version),
post: self.post.transpose_one(i, version),
}
}
}
impl From<mutable::Data> for Data {
fn from(d: mutable::Data) -> Self {
Self {
pre: d.pre.into(),
post: d.post.into(),
validity: d.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct PortData {
pub port: Port,
pub leader: Data,
pub follower: Option<Data>,
}
impl PortData {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::PortData {
transpose::PortData {
port: self.port,
leader: self.leader.transpose_one(i, version),
follower: self.follower.as_ref().map(|f| f.transpose_one(i, version)),
}
}
}
impl From<mutable::PortData> for PortData {
fn from(p: mutable::PortData) -> Self {
Self {
port: p.port,
leader: p.leader.into(),
follower: p.follower.map(|f| f.into()),
}
}
}
pub struct Frame {
pub id: PrimitiveArray<i32>,
pub ports: Vec<PortData>,
pub start: Option<Start>,
pub end: Option<End>,
pub item: Option<Item>,
pub item_offset: Option<OffsetsBuffer<i32>>,
pub fod_platform: Option<FodPlatform>,
pub fod_platform_offset: Option<OffsetsBuffer<i32>>,
pub dreamland_whispy: Option<DreamlandWhispy>,
pub dreamland_whispy_offset: Option<OffsetsBuffer<i32>>,
pub stadium_transformation: Option<StadiumTransformation>,
pub stadium_transformation_offset: Option<OffsetsBuffer<i32>>,
}
impl Frame {
pub fn len(&self) -> usize {
self.id.len()
}
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Frame {
transpose::Frame {
id: self.id.values()[i],
ports: self
.ports
.iter()
.map(|p| p.transpose_one(i, version))
.collect(),
start: version
.gte(2, 2)
.then(|| self.start.as_ref().unwrap().transpose_one(i, version)),
end: version
.gte(3, 0)
.then(|| self.end.as_ref().unwrap().transpose_one(i, version)),
items: version.gte(3, 0).then(|| {
let (start, end) = self.item_offset.as_ref().unwrap().start_end(i);
(start..end)
.map(|i| self.item.as_ref().unwrap().transpose_one(i, version))
.collect()
}),
fod_platforms: version.gte(3, 18).then(|| {
let (start, end) = self.fod_platform_offset.as_ref().unwrap().start_end(i);
(start..end)
.map(|i| {
self.fod_platform
.as_ref()
.unwrap()
.transpose_one(i, version)
})
.collect()
}),
dreamland_whispys: version.gte(3, 18).then(|| {
let (start, end) = self.dreamland_whispy_offset.as_ref().unwrap().start_end(i);
(start..end)
.map(|i| {
self.dreamland_whispy
.as_ref()
.unwrap()
.transpose_one(i, version)
})
.collect()
}),
stadium_transformations: version.gte(3, 18).then(|| {
let (start, end) = self
.stadium_transformation_offset
.as_ref()
.unwrap()
.start_end(i);
(start..end)
.map(|i| {
self.stadium_transformation
.as_ref()
.unwrap()
.transpose_one(i, version)
})
.collect()
}),
}
}
pub fn rollbacks(&self, keep: Rollbacks) -> Vec<bool> {
use Rollbacks::*;
match keep {
ExceptFirst => self.rollbacks_(self.id.values_iter().enumerate()),
ExceptLast => self.rollbacks_(self.id.values_iter().enumerate().rev()),
}
}
fn rollbacks_<'a>(&self, ids: impl Iterator<Item = (usize, &'a i32)>) -> Vec<bool> {
let mut result = vec![false; self.len()];
let unique_id_count = self.id.values_iter().max().map_or(0, |idx| {
1 + usize::try_from(idx - frame::FIRST_INDEX).unwrap()
});
let mut seen = vec![false; unique_id_count];
for (idx, id) in ids {
let zero_based_id = usize::try_from(id - frame::FIRST_INDEX).unwrap();
if !seen[zero_based_id] {
seen[zero_based_id] = true;
result[idx] = false;
} else {
result[idx] = true;
}
}
result
}
}
impl From<mutable::Frame> for Frame {
fn from(f: mutable::Frame) -> Self {
Self {
id: f.id.into(),
ports: f.ports.into_iter().map(|p| p.into()).collect(),
start: f.start.map(|x| x.into()),
end: f.end.map(|x| x.into()),
item: f.item.map(|x| x.into()),
item_offset: f
.item_offset
.map(|x| OffsetsBuffer::try_from(Buffer::from(x.into_inner())).unwrap()),
fod_platform: f.fod_platform.map(|x| x.into()),
fod_platform_offset: f
.fod_platform_offset
.map(|x| OffsetsBuffer::try_from(Buffer::from(x.into_inner())).unwrap()),
dreamland_whispy: f.dreamland_whispy.map(|x| x.into()),
dreamland_whispy_offset: f
.dreamland_whispy_offset
.map(|x| OffsetsBuffer::try_from(Buffer::from(x.into_inner())).unwrap()),
stadium_transformation: f.stadium_transformation.map(|x| x.into()),
stadium_transformation_offset: f
.stadium_transformation_offset
.map(|x| OffsetsBuffer::try_from(Buffer::from(x.into_inner())).unwrap()),
}
}
}
impl fmt::Debug for Frame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
write!(f, "Frame {{ len: {} }}", self.id.len())
}
}
#[derive(Debug)]
pub struct DreamlandWhispy {
pub direction: PrimitiveArray<u8>,
pub validity: Option<Bitmap>,
}
impl DreamlandWhispy {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::DreamlandWhispy {
transpose::DreamlandWhispy {
direction: self.direction.values()[i],
}
}
}
impl From<mutable::DreamlandWhispy> for DreamlandWhispy {
fn from(x: mutable::DreamlandWhispy) -> Self {
Self {
direction: x.direction.into(),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct End {
pub latest_finalized_frame: Option<PrimitiveArray<i32>>,
pub validity: Option<Bitmap>,
}
impl End {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::End {
transpose::End {
latest_finalized_frame: self.latest_finalized_frame.as_ref().map(|x| x.values()[i]),
}
}
}
impl From<mutable::End> for End {
fn from(x: mutable::End) -> Self {
Self {
latest_finalized_frame: x.latest_finalized_frame.map(|x| x.into()),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct FodPlatform {
pub platform: PrimitiveArray<u8>,
pub height: PrimitiveArray<f32>,
pub validity: Option<Bitmap>,
}
impl FodPlatform {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::FodPlatform {
transpose::FodPlatform {
platform: self.platform.values()[i],
height: self.height.values()[i],
}
}
}
impl From<mutable::FodPlatform> for FodPlatform {
fn from(x: mutable::FodPlatform) -> Self {
Self {
platform: x.platform.into(),
height: x.height.into(),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct Item {
pub r#type: PrimitiveArray<u16>,
pub state: PrimitiveArray<u8>,
pub direction: PrimitiveArray<f32>,
pub velocity: Velocity,
pub position: Position,
pub damage: PrimitiveArray<u16>,
pub timer: PrimitiveArray<f32>,
pub id: PrimitiveArray<u32>,
pub misc: Option<ItemMisc>,
pub owner: Option<PrimitiveArray<i8>>,
pub instance_id: Option<PrimitiveArray<u16>>,
pub validity: Option<Bitmap>,
}
impl Item {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Item {
transpose::Item {
r#type: self.r#type.values()[i],
state: self.state.values()[i],
direction: self.direction.values()[i],
velocity: self.velocity.transpose_one(i, version),
position: self.position.transpose_one(i, version),
damage: self.damage.values()[i],
timer: self.timer.values()[i],
id: self.id.values()[i],
misc: self.misc.as_ref().map(|x| x.transpose_one(i, version)),
owner: self.owner.as_ref().map(|x| x.values()[i]),
instance_id: self.instance_id.as_ref().map(|x| x.values()[i]),
}
}
}
impl From<mutable::Item> for Item {
fn from(x: mutable::Item) -> Self {
Self {
r#type: x.r#type.into(),
state: x.state.into(),
direction: x.direction.into(),
velocity: x.velocity.into(),
position: x.position.into(),
damage: x.damage.into(),
timer: x.timer.into(),
id: x.id.into(),
misc: x.misc.map(|x| x.into()),
owner: x.owner.map(|x| x.into()),
instance_id: x.instance_id.map(|x| x.into()),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct ItemMisc(
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
);
impl ItemMisc {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::ItemMisc {
transpose::ItemMisc(
self.0.values()[i],
self.1.values()[i],
self.2.values()[i],
self.3.values()[i],
)
}
}
impl From<mutable::ItemMisc> for ItemMisc {
fn from(x: mutable::ItemMisc) -> Self {
Self(x.0.into(), x.1.into(), x.2.into(), x.3.into())
}
}
#[derive(Debug)]
pub struct Position {
pub x: PrimitiveArray<f32>,
pub y: PrimitiveArray<f32>,
pub validity: Option<Bitmap>,
}
impl Position {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Position {
transpose::Position {
x: self.x.values()[i],
y: self.y.values()[i],
}
}
}
impl From<mutable::Position> for Position {
fn from(x: mutable::Position) -> Self {
Self {
x: x.x.into(),
y: x.y.into(),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct Post {
pub character: PrimitiveArray<u8>,
pub state: PrimitiveArray<u16>,
pub position: Position,
pub direction: PrimitiveArray<f32>,
pub percent: PrimitiveArray<f32>,
pub shield: PrimitiveArray<f32>,
pub last_attack_landed: PrimitiveArray<u8>,
pub combo_count: PrimitiveArray<u8>,
pub last_hit_by: PrimitiveArray<u8>,
pub stocks: PrimitiveArray<u8>,
pub state_age: Option<PrimitiveArray<f32>>,
pub state_flags: Option<StateFlags>,
pub misc_as: Option<PrimitiveArray<f32>>,
pub airborne: Option<PrimitiveArray<u8>>,
pub ground: Option<PrimitiveArray<u16>>,
pub jumps: Option<PrimitiveArray<u8>>,
pub l_cancel: Option<PrimitiveArray<u8>>,
pub hurtbox_state: Option<PrimitiveArray<u8>>,
pub velocities: Option<Velocities>,
pub hitlag: Option<PrimitiveArray<f32>>,
pub animation_index: Option<PrimitiveArray<u32>>,
pub last_hit_by_instance: Option<PrimitiveArray<u16>>,
pub instance_id: Option<PrimitiveArray<u16>>,
pub validity: Option<Bitmap>,
}
impl Post {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Post {
transpose::Post {
character: self.character.values()[i],
state: self.state.values()[i],
position: self.position.transpose_one(i, version),
direction: self.direction.values()[i],
percent: self.percent.values()[i],
shield: self.shield.values()[i],
last_attack_landed: self.last_attack_landed.values()[i],
combo_count: self.combo_count.values()[i],
last_hit_by: self.last_hit_by.values()[i],
stocks: self.stocks.values()[i],
state_age: self.state_age.as_ref().map(|x| x.values()[i]),
state_flags: self
.state_flags
.as_ref()
.map(|x| x.transpose_one(i, version)),
misc_as: self.misc_as.as_ref().map(|x| x.values()[i]),
airborne: self.airborne.as_ref().map(|x| x.values()[i]),
ground: self.ground.as_ref().map(|x| x.values()[i]),
jumps: self.jumps.as_ref().map(|x| x.values()[i]),
l_cancel: self.l_cancel.as_ref().map(|x| x.values()[i]),
hurtbox_state: self.hurtbox_state.as_ref().map(|x| x.values()[i]),
velocities: self
.velocities
.as_ref()
.map(|x| x.transpose_one(i, version)),
hitlag: self.hitlag.as_ref().map(|x| x.values()[i]),
animation_index: self.animation_index.as_ref().map(|x| x.values()[i]),
last_hit_by_instance: self.last_hit_by_instance.as_ref().map(|x| x.values()[i]),
instance_id: self.instance_id.as_ref().map(|x| x.values()[i]),
}
}
}
impl From<mutable::Post> for Post {
fn from(x: mutable::Post) -> Self {
Self {
character: x.character.into(),
state: x.state.into(),
position: x.position.into(),
direction: x.direction.into(),
percent: x.percent.into(),
shield: x.shield.into(),
last_attack_landed: x.last_attack_landed.into(),
combo_count: x.combo_count.into(),
last_hit_by: x.last_hit_by.into(),
stocks: x.stocks.into(),
state_age: x.state_age.map(|x| x.into()),
state_flags: x.state_flags.map(|x| x.into()),
misc_as: x.misc_as.map(|x| x.into()),
airborne: x.airborne.map(|x| x.into()),
ground: x.ground.map(|x| x.into()),
jumps: x.jumps.map(|x| x.into()),
l_cancel: x.l_cancel.map(|x| x.into()),
hurtbox_state: x.hurtbox_state.map(|x| x.into()),
velocities: x.velocities.map(|x| x.into()),
hitlag: x.hitlag.map(|x| x.into()),
animation_index: x.animation_index.map(|x| x.into()),
last_hit_by_instance: x.last_hit_by_instance.map(|x| x.into()),
instance_id: x.instance_id.map(|x| x.into()),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct Pre {
pub random_seed: PrimitiveArray<u32>,
pub state: PrimitiveArray<u16>,
pub position: Position,
pub direction: PrimitiveArray<f32>,
pub joystick: Position,
pub cstick: Position,
pub triggers: PrimitiveArray<f32>,
pub buttons: PrimitiveArray<u32>,
pub buttons_physical: PrimitiveArray<u16>,
pub triggers_physical: TriggersPhysical,
pub raw_analog_x: Option<PrimitiveArray<i8>>,
pub percent: Option<PrimitiveArray<f32>>,
pub raw_analog_y: Option<PrimitiveArray<i8>>,
pub raw_analog_cstick_x: Option<PrimitiveArray<i8>>,
pub raw_analog_cstick_y: Option<PrimitiveArray<i8>>,
pub validity: Option<Bitmap>,
}
impl Pre {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Pre {
transpose::Pre {
random_seed: self.random_seed.values()[i],
state: self.state.values()[i],
position: self.position.transpose_one(i, version),
direction: self.direction.values()[i],
joystick: self.joystick.transpose_one(i, version),
cstick: self.cstick.transpose_one(i, version),
triggers: self.triggers.values()[i],
buttons: self.buttons.values()[i],
buttons_physical: self.buttons_physical.values()[i],
triggers_physical: self.triggers_physical.transpose_one(i, version),
raw_analog_x: self.raw_analog_x.as_ref().map(|x| x.values()[i]),
percent: self.percent.as_ref().map(|x| x.values()[i]),
raw_analog_y: self.raw_analog_y.as_ref().map(|x| x.values()[i]),
raw_analog_cstick_x: self.raw_analog_cstick_x.as_ref().map(|x| x.values()[i]),
raw_analog_cstick_y: self.raw_analog_cstick_y.as_ref().map(|x| x.values()[i]),
}
}
}
impl From<mutable::Pre> for Pre {
fn from(x: mutable::Pre) -> Self {
Self {
random_seed: x.random_seed.into(),
state: x.state.into(),
position: x.position.into(),
direction: x.direction.into(),
joystick: x.joystick.into(),
cstick: x.cstick.into(),
triggers: x.triggers.into(),
buttons: x.buttons.into(),
buttons_physical: x.buttons_physical.into(),
triggers_physical: x.triggers_physical.into(),
raw_analog_x: x.raw_analog_x.map(|x| x.into()),
percent: x.percent.map(|x| x.into()),
raw_analog_y: x.raw_analog_y.map(|x| x.into()),
raw_analog_cstick_x: x.raw_analog_cstick_x.map(|x| x.into()),
raw_analog_cstick_y: x.raw_analog_cstick_y.map(|x| x.into()),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct StadiumTransformation {
pub event: PrimitiveArray<u16>,
pub r#type: PrimitiveArray<u16>,
pub validity: Option<Bitmap>,
}
impl StadiumTransformation {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::StadiumTransformation {
transpose::StadiumTransformation {
event: self.event.values()[i],
r#type: self.r#type.values()[i],
}
}
}
impl From<mutable::StadiumTransformation> for StadiumTransformation {
fn from(x: mutable::StadiumTransformation) -> Self {
Self {
event: x.event.into(),
r#type: x.r#type.into(),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct Start {
pub random_seed: PrimitiveArray<u32>,
pub scene_frame_counter: Option<PrimitiveArray<u32>>,
pub validity: Option<Bitmap>,
}
impl Start {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Start {
transpose::Start {
random_seed: self.random_seed.values()[i],
scene_frame_counter: self.scene_frame_counter.as_ref().map(|x| x.values()[i]),
}
}
}
impl From<mutable::Start> for Start {
fn from(x: mutable::Start) -> Self {
Self {
random_seed: x.random_seed.into(),
scene_frame_counter: x.scene_frame_counter.map(|x| x.into()),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct StateFlags(
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
pub PrimitiveArray<u8>,
);
impl StateFlags {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::StateFlags {
transpose::StateFlags(
self.0.values()[i],
self.1.values()[i],
self.2.values()[i],
self.3.values()[i],
self.4.values()[i],
)
}
}
impl From<mutable::StateFlags> for StateFlags {
fn from(x: mutable::StateFlags) -> Self {
Self(x.0.into(), x.1.into(), x.2.into(), x.3.into(), x.4.into())
}
}
#[derive(Debug)]
pub struct TriggersPhysical {
pub l: PrimitiveArray<f32>,
pub r: PrimitiveArray<f32>,
pub validity: Option<Bitmap>,
}
impl TriggersPhysical {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::TriggersPhysical {
transpose::TriggersPhysical {
l: self.l.values()[i],
r: self.r.values()[i],
}
}
}
impl From<mutable::TriggersPhysical> for TriggersPhysical {
fn from(x: mutable::TriggersPhysical) -> Self {
Self {
l: x.l.into(),
r: x.r.into(),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct Velocities {
pub self_x_air: PrimitiveArray<f32>,
pub self_y: PrimitiveArray<f32>,
pub knockback_x: PrimitiveArray<f32>,
pub knockback_y: PrimitiveArray<f32>,
pub self_x_ground: PrimitiveArray<f32>,
pub validity: Option<Bitmap>,
}
impl Velocities {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Velocities {
transpose::Velocities {
self_x_air: self.self_x_air.values()[i],
self_y: self.self_y.values()[i],
knockback_x: self.knockback_x.values()[i],
knockback_y: self.knockback_y.values()[i],
self_x_ground: self.self_x_ground.values()[i],
}
}
}
impl From<mutable::Velocities> for Velocities {
fn from(x: mutable::Velocities) -> Self {
Self {
self_x_air: x.self_x_air.into(),
self_y: x.self_y.into(),
knockback_x: x.knockback_x.into(),
knockback_y: x.knockback_y.into(),
self_x_ground: x.self_x_ground.into(),
validity: x.validity.map(|v| v.into()),
}
}
}
#[derive(Debug)]
pub struct Velocity {
pub x: PrimitiveArray<f32>,
pub y: PrimitiveArray<f32>,
pub validity: Option<Bitmap>,
}
impl Velocity {
pub fn transpose_one(&self, i: usize, version: Version) -> transpose::Velocity {
transpose::Velocity {
x: self.x.values()[i],
y: self.y.values()[i],
}
}
}
impl From<mutable::Velocity> for Velocity {
fn from(x: mutable::Velocity) -> Self {
Self {
x: x.x.into(),
y: x.y.into(),
validity: x.validity.map(|v| v.into()),
}
}
}