summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared/src/helper.rs132
-rw-r--r--shared/src/lib.rs1
-rw-r--r--shared/src/packets.rs124
-rw-r--r--shared/src/resources.rs2
-rw-r--r--shared/src/store.rs2
-rw-r--r--world/src/main.rs38
-rw-r--r--world/src/mesh.rs5
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());