diff options
-rw-r--r-- | shared/src/helper.rs | 132 | ||||
-rw-r--r-- | shared/src/lib.rs | 1 | ||||
-rw-r--r-- | shared/src/packets.rs | 124 | ||||
-rw-r--r-- | shared/src/resources.rs | 2 | ||||
-rw-r--r-- | shared/src/store.rs | 2 | ||||
-rw-r--r-- | world/src/main.rs | 38 | ||||
-rw-r--r-- | world/src/mesh.rs | 5 |
7 files changed, 182 insertions, 122 deletions
diff --git a/shared/src/helper.rs b/shared/src/helper.rs new file mode 100644 index 0000000..65918ad --- /dev/null +++ b/shared/src/helper.rs @@ -0,0 +1,132 @@ +/* + 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 <https://www.gnu.org/licenses/>. +*/ +use crate::packets::{Data, Object, Resource}; +use anyhow::Result; +use std::{ + io::{Read, Write}, + marker::PhantomData, +}; + +pub trait ReadWrite: Sized { + fn write(&self, w: &mut dyn Write) -> Result<()>; + fn read(r: &mut dyn Read) -> Result<Self>; + + fn write_alloc(&self) -> Vec<u8> { + let mut buf = Vec::new(); + self.write(&mut buf).unwrap(); + buf + } +} + +impl ReadWrite for f32 { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&self.to_be_bytes())?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut buf = [0; 4]; + r.read_exact(&mut buf)?; + Ok(f32::from_be_bytes(buf)) + } +} +impl ReadWrite for u32 { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&self.to_be_bytes())?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut buf = [0; 4]; + r.read_exact(&mut buf)?; + Ok(u32::from_be_bytes(buf)) + } +} +impl ReadWrite for Vec<u8> { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&self)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut buf = Vec::new(); + r.read_to_end(&mut buf)?; + Ok(buf) + } +} +impl ReadWrite for String { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&(self.len() as u32).to_be_bytes())?; + w.write_all(self.as_bytes())?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut size = [0; 4]; + r.read_exact(&mut size)?; + let size = u32::from_be_bytes(size); + let mut buf = vec![0; size as usize]; + r.read_exact(&mut buf)?; + Ok(String::from_utf8(buf)?) + } +} + +impl ReadWrite for Data { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&(self.0.len() as u32).to_be_bytes())?; + w.write_all(&self.0)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut size = [0; 4]; + r.read_exact(&mut size)?; + let size = u32::from_be_bytes(size); + let mut buf = vec![0; size as usize]; + r.read_exact(&mut buf)?; + Ok(Self(buf)) + } +} +impl<T> ReadWrite for Resource<T> { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&self.0)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut s = Self([0; 32], PhantomData); + r.read_exact(&mut s.0)?; + Ok(s) + } +} +impl ReadWrite for Object { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&self.0.to_be_bytes())?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result<Self> { + let mut s = [0; 16]; + r.read_exact(&mut s)?; + Ok(Object(u128::from_be_bytes(s))) + } +} +impl<T: ReadWrite, const N: usize> ReadWrite for [T; N] { + fn write(&self, w: &mut dyn Write) -> Result<()> { + for e in self { + e.write(w)?; + } + Ok(()) + } + + fn read(r: &mut dyn Read) -> Result<Self> { + [(); N].try_map(|()| T::read(r)) + } +} diff --git a/shared/src/lib.rs b/shared/src/lib.rs index d198283..951683c 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -20,5 +20,6 @@ pub mod packets; pub mod resources; pub mod store; pub mod tree; +pub mod helper; pub use glam::{Affine3A, Mat3A, Vec3A, vec3a}; diff --git a/shared/src/packets.rs b/shared/src/packets.rs index 66b0b55..a35b4e9 100644 --- a/shared/src/packets.rs +++ b/shared/src/packets.rs @@ -14,7 +14,10 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use crate::resources::{Prefab, PrefabIndex}; +use crate::{ + helper::ReadWrite, + resources::{Prefab, PrefabIndex}, +}; use anyhow::{Result, bail}; use glam::Vec3A; use std::{ @@ -61,17 +64,6 @@ pub enum Packet { PrefabName(Resource<Prefab>, String), } -pub trait ReadWrite: Sized { - fn write(&self, w: &mut dyn Write) -> Result<()>; - fn read(r: &mut dyn Read) -> Result<Self>; - - fn write_alloc(&self) -> Vec<u8> { - let mut buf = Vec::new(); - self.write(&mut buf).unwrap(); - buf - } -} - impl Object { pub fn new() -> Self { Self(rand::random()) @@ -152,16 +144,16 @@ impl ReadWrite for Packet { 0x00 => Packet::Connect(read_u128(r)?), 0x01 => Packet::RequestResource(Resource::read(r)?), 0x02 => Packet::RespondResource(Data::read(r)?), - 0x03 => Packet::Add(Object(read_u128(r)?), Resource::read(r)?), - 0x04 => Packet::Remove(Object(read_u128(r)?)), + 0x03 => Packet::Add(Object::read(r)?, Resource::read(r)?), + 0x04 => Packet::Remove(Object::read(r)?), 0x05 => Packet::Position( - Object(read_u128(r)?), + 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_u128(r)?), read_params(r)?), - 0x07 => Packet::Parent(Object(read_u128(r)?), Object(read_u128(r)?)), - 0x08 => Packet::Sound(Object(read_u128(r)?), Data::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::PrefabName(Resource::read(r)?, String::read(r)?), _ => { @@ -179,68 +171,7 @@ fn read_u128(r: &mut dyn Read) -> Result<u128> { r.read_exact(&mut buf)?; Ok(u128::from_be_bytes(buf)) } -impl<T> ReadWrite for Resource<T> { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&self.0)?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result<Self> { - let mut s = Self([0; 32], PhantomData); - r.read_exact(&mut s.0)?; - Ok(s) - } -} -impl ReadWrite for Object { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&self.0.to_be_bytes())?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result<Self> { - let mut s = [0; 16]; - r.read_exact(&mut s)?; - Ok(Object(u128::from_be_bytes(s))) - } -} - -impl ReadWrite for Data { - fn write(&self, w: &mut dyn Write) -> Result<()> { - self.0.write(w) - } - fn read(r: &mut dyn Read) -> Result<Self> { - Ok(Self(Vec::read(r)?)) - } -} -impl ReadWrite for Vec<u8> { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&(self.len() as u32).to_be_bytes())?; - w.write_all(&self)?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result<Self> { - let mut size = [0; 4]; - r.read_exact(&mut size)?; - let size = u32::from_be_bytes(size); - let mut buf = vec![0; size as usize]; - r.read_exact(&mut buf)?; - Ok(buf) - } -} -impl ReadWrite for String { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&(self.len() as u32).to_be_bytes())?; - w.write_all(self.as_bytes())?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result<Self> { - let mut size = [0; 4]; - r.read_exact(&mut size)?; - let size = u32::from_be_bytes(size); - let mut buf = vec![0; size as usize]; - r.read_exact(&mut buf)?; - Ok(String::from_utf8(buf)?) - } -} fn read_params(r: &mut dyn Read) -> Result<Vec<f32>> { let mut size = [0; 2]; r.read_exact(&mut size)?; @@ -252,29 +183,6 @@ fn read_params(r: &mut dyn Read) -> Result<Vec<f32>> { Ok(v) } -impl ReadWrite for f32 { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&self.to_be_bytes())?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result<Self> { - let mut buf = [0; 4]; - r.read_exact(&mut buf)?; - Ok(f32::from_be_bytes(buf)) - } -} -impl ReadWrite for u32 { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&self.to_be_bytes())?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result<Self> { - let mut buf = [0; 4]; - r.read_exact(&mut buf)?; - Ok(u32::from_be_bytes(buf)) - } -} - impl<T> Display for Resource<T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -293,18 +201,6 @@ impl<T> Debug for Resource<T> { } } -impl<T: ReadWrite, const N: usize> ReadWrite for [T; N] { - fn write(&self, w: &mut dyn Write) -> Result<()> { - for e in self { - e.write(w)?; - } - Ok(()) - } - - fn read(r: &mut dyn Read) -> Result<Self> { - [(); N].try_map(|()| T::read(r)) - } -} impl Debug for Data { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Data").finish_non_exhaustive() diff --git a/shared/src/resources.rs b/shared/src/resources.rs index 95f42e4..44d6e40 100644 --- a/shared/src/resources.rs +++ b/shared/src/resources.rs @@ -14,7 +14,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use crate::packets::{ReadWrite, Resource}; +use crate::{helper::ReadWrite, packets::Resource}; use anyhow::Result; use glam::{Affine3A, Vec3A}; use log::warn; diff --git a/shared/src/store.rs b/shared/src/store.rs index f63ed6c..976960e 100644 --- a/shared/src/store.rs +++ b/shared/src/store.rs @@ -14,7 +14,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use crate::packets::{ReadWrite, Resource}; +use crate::{helper::ReadWrite, packets::Resource}; use anyhow::Result; use redb::{Database, TableDefinition}; use sha2::{Digest, Sha256}; diff --git a/world/src/main.rs b/world/src/main.rs index 546b73b..1b59cc6 100644 --- a/world/src/main.rs +++ b/world/src/main.rs @@ -20,12 +20,13 @@ pub mod mesh; use anyhow::{Result, bail}; use clap::Parser; use gltf::image::Source; +use image::{ImageReader, codecs::webp::WebPEncoder}; use log::info; use mesh::import_mesh; use rand::random; use std::{ fs::File, - io::{Read, Write}, + io::{Cursor, Read, Write}, net::{SocketAddr, TcpStream}, path::{Path, PathBuf}, thread::{self, sleep}, @@ -33,7 +34,8 @@ use std::{ }; use weareshared::{ Vec3A, - packets::{Data, Object, Packet, ReadWrite, Resource}, + helper::ReadWrite, + packets::{Data, Object, Packet, Resource}, resources::{Image, LightPart, Prefab}, store::ResourceStore, vec3a, @@ -50,6 +52,8 @@ struct Args { #[arg(short, long)] clear: bool, #[arg(short, long)] + webp: bool, + #[arg(short, long)] name: Option<String>, } @@ -68,7 +72,15 @@ fn main() -> Result<()> { let mut prefab = Prefab::default(); for node in gltf.nodes() { if let Some(mesh) = node.mesh() { - import_mesh(mesh, &buffers, &store, path_base, &node, &mut prefab)?; + import_mesh( + mesh, + &buffers, + &store, + path_base, + &node, + &mut prefab, + args.webp, + )?; } let (position, _, _) = node.transform().decomposed(); if let Some(light) = node.light() { @@ -153,13 +165,14 @@ fn load_texture( path: &Path, buffers: &[gltf::buffer::Data], source: &Source, + webp: bool, ) -> Result<Resource<Image>> { - match source { + let mut image = match source { gltf::image::Source::View { view, mime_type } => { info!("{name} texture is embedded and of type {mime_type:?}"); let buf = &buffers[view.buffer().index()].0[view.offset()..view.offset() + view.length()]; - return Ok(store.set(&Image(buf.to_vec()))?); + Image(buf.to_vec()) } gltf::image::Source::Uri { uri, @@ -169,10 +182,23 @@ fn load_texture( let path = path.join(uri); let mut buf = Vec::new(); File::open(path)?.read_to_end(&mut buf)?; - return Ok(store.set(&Image(buf))?); + Image(buf) } _ => { bail!("texture is external and has no mime type") } + }; + + if webp { + let mut image_out = Image(Vec::new()); + + let len = image.0.len(); + ImageReader::new(Cursor::new(image.0)) + .with_guessed_format()? + .decode()? + .write_with_encoder(WebPEncoder::new_lossless(&mut image_out.0))?; + info!("webp encode: {len} -> {}", image_out.0.len()); + image = image_out; } + Ok(store.set(&image)?) } diff --git a/world/src/mesh.rs b/world/src/mesh.rs index cbc33c0..8742fb7 100644 --- a/world/src/mesh.rs +++ b/world/src/mesh.rs @@ -32,6 +32,7 @@ pub fn import_mesh( path_base: &Path, node: &Node, prefab: &mut Prefab, + webp: bool, ) -> Result<()> { Ok(for p in mesh.primitives() { let reader = p.reader(|buf| Some(&buffers[buf.index()])); @@ -151,6 +152,7 @@ pub fn import_mesh( path_base, &buffers, &tex.texture().source().source(), + webp, )?; tex_albedo = Some(r.clone()); tex_transmission = Some(r.clone()); @@ -163,6 +165,7 @@ pub fn import_mesh( path_base, &buffers, &tex.texture().source().source(), + webp, )?); } let mut tex_emission = None; @@ -173,6 +176,7 @@ pub fn import_mesh( path_base, &buffers, &tex.texture().source().source(), + webp, )?); } let mut tex_roughness = None; @@ -188,6 +192,7 @@ pub fn import_mesh( path_base, &buffers, &tex.texture().source().source(), + webp, )?; tex_roughness = Some(r.clone()); tex_metallic = Some(r.clone()); |