diff options
author | metamuffin <metamuffin@disroot.org> | 2025-03-12 16:34:45 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-03-12 16:34:45 +0100 |
commit | 3ed621256f1e02032250477fa574eab38bd34976 (patch) | |
tree | 100f24b5a97a20cee87fd14b1a68e8250a6328f9 /shared | |
parent | 56ffdcff01b57af14db97b4515b419da0d234387 (diff) | |
download | weareserver-3ed621256f1e02032250477fa574eab38bd34976.tar weareserver-3ed621256f1e02032250477fa574eab38bd34976.tar.bz2 weareserver-3ed621256f1e02032250477fa574eab38bd34976.tar.zst |
respack
Diffstat (limited to 'shared')
-rw-r--r-- | shared/src/lib.rs | 1 | ||||
-rw-r--r-- | shared/src/resources.rs | 4 | ||||
-rw-r--r-- | shared/src/respack.rs | 107 | ||||
-rw-r--r-- | shared/src/store.rs | 10 |
4 files changed, 122 insertions, 0 deletions
diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 9c3e863..c3d8d6b 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -27,5 +27,6 @@ pub mod packets; pub mod resources; pub mod store; pub mod tree; +pub mod respack; pub use glam::{Affine3A, Mat3A, Vec2, Vec3A, Vec4, vec2, vec3a, vec4}; diff --git a/shared/src/resources.rs b/shared/src/resources.rs index fbc171b..d5ec76c 100644 --- a/shared/src/resources.rs +++ b/shared/src/resources.rs @@ -73,6 +73,10 @@ macro_rules! resource_dicts { } resource_dicts!( + pub struct RespackEntry { + name: String, + } + pub struct Prefab { name: String, mesh[multi]: (Affine3A, Resource<MeshPart>), diff --git a/shared/src/respack.rs b/shared/src/respack.rs new file mode 100644 index 0000000..8c0b9d8 --- /dev/null +++ b/shared/src/respack.rs @@ -0,0 +1,107 @@ +/* + 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::Resource, resources::RespackEntry, store::ResourceStore}; +use anyhow::{Result, bail}; +use log::{info, warn}; +use std::{ + io::{Read, Seek, SeekFrom, Write}, + marker::PhantomData, +}; + +const MAGIC: &[u8; 16] = b"\x0f\x0cWEARE\x01RESPACK\x02"; + +pub fn save_respack( + mut output: impl Write, + store: &ResourceStore, + resources: &[Resource], + entry: Option<Resource<RespackEntry>>, +) -> Result<()> { + output.write_all(MAGIC)?; + output.write_all(&entry.map(|e| e.0).unwrap_or([0u8; 32]))?; + output.write_all(&u64::to_be_bytes(resources.len() as u64))?; + let mut off = + (MAGIC.len() + 32 + size_of::<u64>() + (32 + size_of::<u64>() * 2) * resources.len()) + as u64; + for r in resources { + let size = store.get_raw_size(*r)?.unwrap() as u64; + output.write_all(&r.0)?; + output.write_all(&u64::to_be_bytes(off))?; + output.write_all(&u64::to_be_bytes(size))?; + off += size; + } + for r in resources { + output.write_all(&store.get_raw(*r)?.unwrap())?; + } + Ok(()) +} + +pub fn load_respack( + mut input: impl Read + Seek, + store: &ResourceStore, +) -> Result<Option<Resource<RespackEntry>>> { + let mut magic = [0u8; MAGIC.len()]; + input.read_exact(&mut magic)?; + if magic != *MAGIC { + bail!("wrong magic bytes"); + } + let mut entry = [0u8; 32]; + input.read_exact(&mut entry)?; + let entry = if entry != [0u8; 32] { + Some(Resource(entry, PhantomData)) + } else { + None + }; + + let mut count = [0u8; size_of::<u64>()]; + input.read_exact(&mut count)?; + let count = u64::from_be_bytes(count); + + let mut load_queue = Vec::new(); + let mut found_entry = false; + for _ in 0..count { + let mut res = [0u8; 32]; + let mut off = [0u8; size_of::<u64>()]; + let mut size = [0u8; size_of::<u64>()]; + input.read_exact(&mut res)?; + input.read_exact(&mut off)?; + input.read_exact(&mut size)?; + + found_entry |= Some(Resource(res, PhantomData)) == entry; + if store.get_raw_size(Resource(res, PhantomData))?.is_none() { + load_queue.push((res, u64::from_be_bytes(off), u64::from_be_bytes(size))) + } + } + if !found_entry && entry.is_some() { + warn!("respack does not contain its entry resource") + } + info!( + "loading {} of {count} resources from pack", + load_queue.len(), + ); + + for (res, off, size) in load_queue { + input.seek(SeekFrom::Start(off))?; + let mut buf = Vec::new(); + input.by_ref().take(size).read_to_end(&mut buf)?; + let key = store.set_raw(&buf)?; + if key.0 != res { + warn!("respack containes mislabeled resources") + } + } + + Ok(entry) +} diff --git a/shared/src/store.rs b/shared/src/store.rs index 3db6bac..e3e5949 100644 --- a/shared/src/store.rs +++ b/shared/src/store.rs @@ -76,6 +76,16 @@ impl ResourceStore { pub fn set<T: ReadWrite>(&self, value: &T) -> Result<Resource<T>> { Ok(Resource(self.set_raw(&value.write_alloc())?.0, PhantomData)) } + pub fn get_raw_size(&self, key: Resource) -> Result<Option<usize>> { + match self { + ResourceStore::Redb(_) => todo!(), + ResourceStore::Filesystem(_) => todo!(), + ResourceStore::Memory(mutex) => { + let g = mutex.lock().unwrap(); + Ok(g.get(&key).map(|s| s.len())) + } + } + } pub fn get_raw(&self, key: Resource) -> Result<Option<Vec<u8>>> { match self { ResourceStore::Redb(database) => { |