use insim_core::binrw::{self, binrw, BinRead, BinWrite};
use crate::identifiers::{ConnectionId, RequestId};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum CimMode {
Normal(CimSubModeNormal),
Options,
HostOptions,
Garage(CimSubModeGarage),
CarSelect,
TrackSelect,
ShiftU {
submode: CimSubModeShiftU,
seltype: u8,
},
}
impl Default for CimMode {
fn default() -> Self {
Self::Normal(CimSubModeNormal::Normal)
}
}
#[repr(u8)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum CimSubModeNormal {
#[default]
Normal = 0,
WheelTemps = 1,
WheelDamage = 2,
LiveSettings = 3,
PitInstructions = 4,
}
impl From<u8> for CimSubModeNormal {
fn from(value: u8) -> Self {
match value {
0 => Self::Normal,
1 => Self::WheelTemps,
2 => Self::WheelDamage,
3 => Self::LiveSettings,
4 => Self::PitInstructions,
_ => {
unreachable!(
"Unhandled CimSubModeNormal. Perhaps a programming error or protocol update?"
)
},
}
}
}
#[repr(u8)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum CimSubModeGarage {
#[default]
Info = 0,
Colours = 1,
BrakeTC = 2,
Susp = 3,
Steer = 4,
Drive = 5,
Tyres = 6,
Aero = 7,
Pass = 8,
}
impl From<u8> for CimSubModeGarage {
fn from(value: u8) -> Self {
match value {
0 => Self::Info,
1 => Self::Colours,
2 => Self::BrakeTC,
3 => Self::Susp,
4 => Self::Steer,
5 => Self::Drive,
6 => Self::Tyres,
7 => Self::Aero,
8 => Self::Pass,
_ => {
unreachable!(
"Unhandled CimSubModeGarage. Perhaps a programming error or protocol update?"
)
},
}
}
}
#[repr(u8)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum CimSubModeShiftU {
#[default]
Plain = 0,
Buttons = 1,
Edit = 2,
}
impl From<u8> for CimSubModeShiftU {
fn from(value: u8) -> Self {
match value {
1 => Self::Buttons,
2 => Self::Edit,
_ => Self::Plain,
}
}
}
impl BinRead for CimMode {
type Args<'a> = ();
fn read_options<R: std::io::Read + std::io::Seek>(
reader: &mut R,
endian: binrw::Endian,
_args: Self::Args<'_>,
) -> binrw::BinResult<Self> {
let pos = reader.stream_position()?;
let discrim = u8::read_options(reader, endian, ())?;
let submode = u8::read_options(reader, endian, ())?;
let seltype = u8::read_options(reader, endian, ())?;
let res = match discrim {
0 => Self::Normal(submode.into()),
1 => Self::Options,
2 => Self::HostOptions,
3 => Self::Garage(submode.into()),
4 => Self::CarSelect,
5 => Self::TrackSelect,
6 => Self::ShiftU {
submode: submode.into(),
seltype,
},
_ => {
return Err(binrw::Error::BadMagic {
pos,
found: Box::new(submode),
})
},
};
Ok(res)
}
}
impl BinWrite for CimMode {
type Args<'a> = ();
fn write_options<W: std::io::Write + std::io::Seek>(
&self,
writer: &mut W,
endian: binrw::Endian,
_args: Self::Args<'_>,
) -> binrw::BinResult<()> {
let (discrim, submode, seltype) = match self {
CimMode::Normal(submode) => (0u8, *submode as u8, 0u8),
CimMode::Options => (1u8, 0u8, 0u8),
CimMode::HostOptions => (2u8, 0u8, 0u8),
CimMode::Garage(submode) => (3u8, *submode as u8, 0u8),
CimMode::CarSelect => (4u8, 0u8, 0u8),
CimMode::TrackSelect => (5u8, 0u8, 0u8),
CimMode::ShiftU {
submode: mode,
seltype,
} => (6u8, *mode as u8, *seltype),
};
discrim.write_options(writer, endian, ())?;
submode.write_options(writer, endian, ())?;
seltype.write_options(writer, endian, ())?;
Ok(())
}
}
#[binrw]
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Cim {
pub reqi: RequestId,
pub ucid: ConnectionId,
#[brw(pad_after = 1)]
pub mode: CimMode,
}