summaryrefslogtreecommitdiff
path: root/world/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'world/src/main.rs')
-rw-r--r--world/src/main.rs304
1 files changed, 0 insertions, 304 deletions
diff --git a/world/src/main.rs b/world/src/main.rs
deleted file mode 100644
index 554a2bd..0000000
--- a/world/src/main.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- 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/>.
-*/
-#![feature(iter_array_chunks)]
-#![allow(clippy::too_many_arguments, clippy::type_complexity)]
-pub mod animation;
-pub mod mesh;
-pub mod physics;
-pub mod prefab;
-pub mod vrm;
-
-use anyhow::{Result, bail};
-use clap::Parser;
-use gltf::{image::Source, scene::Transform};
-use humansize::BINARY;
-use image::{ImageReader, codecs::webp::WebPEncoder};
-use log::{debug, info};
-use prefab::import_prefab;
-use rand::random;
-use std::{
- borrow::Cow,
- collections::HashMap,
- fs::File,
- io::{BufWriter, Cursor, Read, Write},
- marker::PhantomData,
- net::{SocketAddr, TcpStream},
- path::{Path, PathBuf},
- sync::{Arc, Mutex},
- thread::{self, sleep},
- time::Duration,
-};
-use weareshared::{
- Affine3A, Vec3A,
- helper::ReadWrite,
- packets::{Data, Object, Packet, Resource},
- resources::{Image, RespackEntry},
- respack::save_respack,
- store::ResourceStore,
- vec3a,
-};
-
-#[derive(Parser)]
-pub struct Args {
- #[arg(short, long)]
- address: Option<SocketAddr>,
-
- /// Output converted prefab as resource package
- #[arg(short = 'o', long)]
- pack: Option<PathBuf>,
-
- /// Path(s) to a glTF file, binary or json format
- scene: Vec<PathBuf>,
- /// Send all resources to the server then quit
- #[arg(short, long)]
- push: bool,
-
- /// Remove all other object from the world
- #[arg(short, long)]
- clear: bool,
- /// Add the object to the world
- #[arg(short, long)]
- add: bool,
- /// Transcode all textures to WebP
- #[arg(short, long)]
- webp: bool,
- /// Add skybox
- #[arg(long)]
- skybox: Option<PathBuf>,
- /// Override prefab name
- #[arg(short, long)]
- name: Option<String>,
- #[arg(short, long)]
- scale: Option<f32>,
- #[arg(short, long)]
- dry_run: bool,
- #[arg(short, long)]
- line_up: bool,
-
- #[arg(long)]
- use_cache: bool,
-
- #[arg(short = 'S', long)]
- with_default_sun: bool,
-
- #[arg(long)]
- animation: Option<PathBuf>,
- #[arg(long)]
- animation_bone_map: Option<PathBuf>,
- #[arg(long)]
- animation_rotation_y: Option<f32>,
- #[arg(long)]
- animation_scale: Option<f32>,
- #[arg(long)]
- animation_apply_ibm: bool,
-
- /// Spins the object
- #[arg(long)]
- debug_spin: bool,
- /// Adds a light
- #[arg(long)]
- debug_light: bool,
- #[arg(long)]
- no_particles: bool,
- #[arg(long)]
- no_animations: bool,
-}
-
-fn main() -> Result<()> {
- env_logger::init_from_env("LOG");
- let args = Args::parse();
-
- let store = if args.use_cache && !args.pack.is_some() {
- ResourceStore::new_env()?
- } else {
- ResourceStore::new_memory()
- };
-
- let mut prefabs = Vec::new();
- let texture_cache = Arc::new(Mutex::new(HashMap::new()));
-
- for scenepath in &args.scene {
- prefabs.push(import_prefab(&store, &texture_cache, scenepath, &args)?);
- }
-
- let mut size = 0;
- store.iter(|_k, len| size += len).unwrap();
- info!(
- "prefab has network size of {}",
- humansize::format_size(size, BINARY)
- );
-
- if args.dry_run {
- return Ok(());
- }
- if let Some(outpath) = args.pack {
- let entry = store.set(&RespackEntry { name: None })?;
- let mut resources = Vec::new();
- store.iter(|r, _| resources.push(r))?;
- save_respack(
- BufWriter::new(File::create(outpath)?),
- &store,
- &resources,
- Some(entry),
- )?;
- } else if let Some(address) = args.address {
- let mut sock = TcpStream::connect(address)?;
- Packet::Connect(random()).write(&mut sock)?;
- for p in &prefabs {
- Packet::AnnouncePrefab(p.clone()).write(&mut sock)?;
- }
- sock.flush()?;
-
- let mut obs = Vec::new();
- if args.add {
- for (i, p) in prefabs.iter().enumerate() {
- let ob = Object::new();
- info!("adding object {ob}");
- Packet::Add(ob, p.clone()).write(&mut sock)?;
- if args.line_up {
- Packet::Position(ob, vec3a(i as f32 * 1.2, 0., i as f32 * 0.3), Vec3A::ZERO)
- .write(&mut sock)?;
- }
- obs.push(ob);
- }
- sock.flush()?;
- }
-
- if args.debug_spin {
- let ob = obs[0];
- let mut sock2 = sock.try_clone().unwrap();
- thread::spawn(move || {
- let mut x = 0.;
- loop {
- Packet::Position(ob, Vec3A::ZERO, vec3a(0., x * 0.1, 0.))
- .write(&mut sock2)
- .unwrap();
- sock2.flush().unwrap();
- x += 0.1;
- sleep(Duration::from_millis(50));
- }
- });
- }
- if args.push {
- if args.use_cache {
- return Ok(());
- }
- store.iter(|k, _| {
- Packet::RespondResource(k, Data(store.get_raw(k).unwrap().unwrap()))
- .write(&mut sock)
- .unwrap();
- })?;
- sock.flush()?;
- } else {
- loop {
- let packet = Packet::read(&mut sock)?;
- match packet {
- Packet::RequestResource(hash) => {
- if let Some(d) = store.get_raw(hash)? {
- Packet::RespondResource(hash, Data(d)).write(&mut sock)?;
- sock.flush()?;
- }
- }
- Packet::Add(ob_a, _) => {
- if args.clear && !obs.contains(&ob_a) {
- info!("removing object {ob_a}");
- Packet::Remove(ob_a).write(&mut sock)?;
- sock.flush()?;
- }
- }
- _ => (),
- }
- }
- }
- } else {
- bail!("no output option specified. either provide an address to a server or use --pack")
- }
- Ok(())
-}
-
-pub type TextureCache = Arc<Mutex<HashMap<String, Resource<Image<'static>>>>>;
-fn load_texture(
- name: &str,
- store: &ResourceStore,
- path: &Path,
- buffers: &[gltf::buffer::Data],
- source: &Source,
- webp: bool,
- texture_cache: &TextureCache,
-) -> Result<Resource<Image<'static>>> {
- let (mut image, uri) = match source {
- gltf::image::Source::View { view, mime_type } => {
- debug!("{name} texture is embedded and of type {mime_type:?}");
- let buf =
- &buffers[view.buffer().index()].0[view.offset()..view.offset() + view.length()];
- (Image(Cow::Borrowed(buf)), None)
- }
- gltf::image::Source::Uri {
- uri,
- mime_type: Some(mime_type),
- } => {
- debug!("{name} texture is {uri:?} and of type {mime_type:?}");
- if let Some(res) = texture_cache.lock().unwrap().get(*uri) {
- return Ok(res.to_owned());
- }
- let path = path.join(uri);
- let mut buf = Vec::new();
- File::open(path)?.read_to_end(&mut buf)?;
- (Image(buf.into()), Some(uri.to_string()))
- }
- gltf::image::Source::Uri {
- uri,
- mime_type: None,
- } => {
- debug!("{name} texture is {uri:?} and has no type");
- if let Some(res) = texture_cache.lock().unwrap().get(*uri) {
- return Ok(res.to_owned());
- }
- let path = path.join(uri);
- let mut buf = Vec::new();
- File::open(path)?.read_to_end(&mut buf)?;
- (Image(buf.into()), Some(uri.to_string()))
- }
- };
-
- if webp {
- let mut image_out = 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))?;
- debug!("webp encode: {len} -> {}", image_out.len());
- image = Image(Cow::Owned(image_out));
- }
- let res = Resource(store.set(&image)?.0, PhantomData);
- if let Some(uri) = uri {
- texture_cache.lock().unwrap().insert(uri, res.clone());
- }
- Ok(res)
-}
-
-pub fn transform_to_affine(trans: Transform) -> Affine3A {
- let mat = trans.matrix();
- Affine3A::from_cols_array_2d(&[
- [mat[0][0], mat[0][1], mat[0][2]],
- [mat[1][0], mat[1][1], mat[1][2]],
- [mat[2][0], mat[2][1], mat[2][2]],
- [mat[3][0], mat[3][1], mat[3][2]],
- ])
-}