use super::patch::{Edit, Patch, Picture};
use crate::raster::IRect;
pub type PeerId = u32;
pub const VERSION: u32 = 2;
#[derive(Clone, Debug, PartialEq, bincode::Encode, bincode::Decode)]
pub struct Hello {
pub magic: [u8; 4],
pub version: u32,
pub name: String,
pub color: [u8; 3],
pub listen: u16,
}
impl Hello {
pub const MAGIC: [u8; 4] = *b"PNT!";
pub fn new(name: String, color: [u8; 3], listen: u16) -> Self {
Self { magic: Self::MAGIC, version: VERSION, name, color, listen }
}
}
#[derive(Clone, Debug, PartialEq, bincode::Encode, bincode::Decode)]
pub struct Kid {
pub id: PeerId,
pub name: String,
pub color: [u8; 3],
pub addr: String,
}
#[derive(Clone, Debug, PartialEq, bincode::Encode, bincode::Decode)]
pub struct Tile {
pub tx: u16,
pub ty: u16,
pub patch: Option<Patch>,
}
pub const TILE: i32 = 64;
#[derive(Clone, Copy, Debug, PartialEq, bincode::Encode, bincode::Decode)]
pub struct Presence {
pub at: Option<(f32, f32)>,
pub tool: Held,
pub color: [u8; 4],
pub size: f32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, bincode::Encode, bincode::Decode)]
pub enum Held {
Pencil,
Fill,
Brush,
Eraser,
Picker,
Other,
}
#[derive(Clone, Debug, PartialEq, bincode::Encode, bincode::Decode)]
pub enum ToHub {
Edit {
id: u64,
edit: Edit,
},
Preview(Vec<Tile>),
Presence(Presence),
Ping,
Kick(PeerId),
LetIn { kid: PeerId, yes: bool },
AskFirst(bool),
}
#[derive(Clone, Debug, PartialEq, bincode::Encode, bincode::Decode)]
pub enum FromHub {
Welcome {
you: PeerId,
host: PeerId,
seq: u64,
picture: Picture,
kids: Vec<Kid>,
ask_first: bool,
},
Sequenced {
seq: u64,
from: PeerId,
id: u64,
edit: Edit,
},
Kids(Vec<Kid>),
KickedOut { kid: PeerId, by: PeerId, kids: Vec<Kid> },
Asking(String),
Waiting(Vec<Kid>),
AskFirst(bool),
Rejected(String),
Preview {
from: PeerId,
tiles: Vec<Tile>,
},
Presence {
from: PeerId,
presence: Presence,
},
Ping,
}
impl ToHub {
pub fn is_valid(&self) -> bool {
match self {
ToHub::Edit { edit, .. } => edit.is_valid(),
ToHub::Preview(tiles) => tiles_valid(tiles),
ToHub::Presence(p) => p.is_valid(),
ToHub::Ping | ToHub::Kick(_) | ToHub::LetIn { .. } | ToHub::AskFirst(_) => true,
}
}
}
impl FromHub {
pub fn is_valid(&self) -> bool {
match self {
FromHub::Welcome { picture, .. } => picture.is_valid(),
FromHub::Sequenced { edit, .. } => edit.is_valid(),
FromHub::Preview { tiles, .. } => tiles_valid(tiles),
FromHub::Presence { presence, .. } => presence.is_valid(),
FromHub::Kids(_)
| FromHub::KickedOut { .. }
| FromHub::Asking(_)
| FromHub::Waiting(_)
| FromHub::AskFirst(_)
| FromHub::Rejected(_)
| FromHub::Ping => true,
}
}
}
impl Tile {
pub fn rect(tx: u16, ty: u16) -> IRect {
let (x, y) = (tx as i32 * TILE, ty as i32 * TILE);
IRect::new(x, y, x + TILE, y + TILE)
}
}
fn tiles_valid(tiles: &[Tile]) -> bool {
tiles.len() <= 4096
&& tiles.iter().all(|t| t.patch.as_ref().is_none_or(|p| p.is_valid() && Tile::rect(t.tx, t.ty).contains_rect(p.rect())))
}
impl Presence {
fn is_valid(&self) -> bool {
self.at.is_none_or(|(x, y)| x.is_finite() && y.is_finite()) && (0.0..=1000.0).contains(&self.size)
}
}