/* wearechat - generic multiplayer game with voip Copyright (C) 2025 metamuffin This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use crate::{ helper::ReadWrite, resources::{Prefab, PrefabIndex}, }; use anyhow::{Result, bail}; use glam::Vec3A; use std::{ fmt::{Debug, Display}, hash::Hash, io::{Read, Write}, marker::PhantomData, }; #[derive(Clone, Copy)] pub struct Resource(pub [u8; 32], pub PhantomData); impl PartialEq for Resource { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl Eq for Resource {} impl Hash for Resource { fn hash(&self, state: &mut H) { self.0.hash(state); } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Object(pub u128); #[derive(Clone)] pub struct Data(pub Vec); #[derive(Debug, Clone)] pub enum Packet { Connect(u128), Disconnect, RequestResource(Resource), RespondResource(Data), Add(Object, Resource), Remove(Object), Position(Object, Vec3A, Vec3A), Pose(Object, Vec), Parent(Object, Object), Sound(Object, Data), PrefabIndex(Resource), AnnouncePrefab(Resource), } impl Object { pub fn new() -> Self { Self(rand::random()) } } impl Packet { fn serialize_inner(&self, w: &mut impl Write) -> Result<()> { match self { Packet::Connect(id) => { w.write_all(&[0x00])?; w.write_all(&id.to_be_bytes())?; } Packet::Disconnect => { w.write_all(&[0xff])?; } Packet::RequestResource(resource) => { w.write_all(&[0x01])?; w.write_all(&resource.0)?; } Packet::RespondResource(data) => { w.write_all(&[0x02])?; data.write(w)?; } Packet::Add(object, resource) => { w.write_all(&[0x03])?; w.write_all(&object.0.to_be_bytes())?; w.write_all(&resource.0)?; } Packet::Remove(object) => { w.write_all(&[0x04])?; object.write(w)?; } Packet::Position(object, pos, rot) => { w.write_all(&[0x05])?; w.write_all(&object.0.to_be_bytes())?; pos.write(w)?; rot.write(w)?; } Packet::Pose(object, vec) => { w.write_all(&[0x06])?; w.write_all(&object.0.to_be_bytes())?; w.write_all(&(vec.len() as u16).to_be_bytes())?; } Packet::Parent(parent, child) => { w.write_all(&[0x07])?; w.write_all(&parent.0.to_be_bytes())?; w.write_all(&child.0.to_be_bytes())?; } Packet::Sound(object, data) => { w.write_all(&[0x08])?; w.write_all(&object.0.to_be_bytes())?; data.write(w)?; } Packet::PrefabIndex(resource) => { w.write_all(&[0x09])?; resource.write(w)?; } Packet::AnnouncePrefab(resource) => { w.write_all(&[0x0a])?; resource.write(w)?; } } Ok(()) } } impl ReadWrite for Packet { fn write(&self, w: &mut dyn Write) -> Result<()> { let mut buf = Vec::new(); self.serialize_inner(&mut buf)?; w.write_all(&(buf.len() as u32).to_be_bytes())?; w.write_all(&buf)?; Ok(()) } fn read(r: &mut dyn Read) -> Result { let packet_len = u32::read(r)?; Ok(match u8::read(r)? { 0x00 => Packet::Connect(read_u128(r)?), 0x01 => Packet::RequestResource(Resource::read(r)?), 0x02 => Packet::RespondResource(Data::read(r)?), 0x03 => Packet::Add(Object::read(r)?, Resource::read(r)?), 0x04 => Packet::Remove(Object::read(r)?), 0x05 => Packet::Position( Object::read(r)?, Vec3A::new(f32::read(r)?, f32::read(r)?, f32::read(r)?), Vec3A::new(f32::read(r)?, f32::read(r)?, f32::read(r)?), ), 0x06 => Packet::Pose(Object::read(r)?, read_params(r)?), 0x07 => Packet::Parent(Object::read(r)?, Object::read(r)?), 0x08 => Packet::Sound(Object::read(r)?, Data::read(r)?), 0x09 => Packet::PrefabIndex(Resource::read(r)?), 0x0a => Packet::AnnouncePrefab(Resource::read(r)?), _ => { for _ in 0..packet_len.max(1) - 1 { r.read_exact(&mut [0])?; } bail!("unknown packet tag"); } }) } } fn read_u128(r: &mut dyn Read) -> Result { let mut buf = [0; 16]; r.read_exact(&mut buf)?; Ok(u128::from_be_bytes(buf)) } fn read_params(r: &mut dyn Read) -> Result> { let mut size = [0; 2]; r.read_exact(&mut size)?; let size = u16::from_be_bytes(size); let mut v = Vec::with_capacity(size as usize); for _ in 0..size { v.push(f32::read(r)?); } Ok(v) } impl Display for Resource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Res{{{:08x}{:08x}{:08x}{:08x}}}", u64::from_be_bytes(self.0[0..8].try_into().unwrap()), u64::from_be_bytes(self.0[8..16].try_into().unwrap()), u64::from_be_bytes(self.0[16..24].try_into().unwrap()), u64::from_be_bytes(self.0[24..32].try_into().unwrap()), ) } } impl Debug for Resource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) } } impl Debug for Data { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Data").finish_non_exhaustive() } } impl Display for Object { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Object").field(&self.0).finish() } }