/* 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::{camera::Camera, download::Downloader, network::Network, renderer::Renderer}; use anyhow::{Context, Result}; use glam::{Vec2, Vec3}; use log::{info, warn}; use std::{net::TcpStream, sync::Arc, time::Instant}; use weareshared::{ packets::{Packet, Resource}, resources::PrefabIndex, store::ResourceStore, tree::SceneTree, }; use winit::event::MouseButton; pub struct State<'a> { pub network: Arc, pub downloader: Arc, pub renderer: Renderer<'a>, pub tree: SceneTree, pub camera: Camera, pub delta: DeltaState, pub prefab_index: PrefabIndex, pub prefab_index_res_loaded: Option>, pub prefab_index_res: Option>, } pub struct DeltaState { time: Instant, pub move_dir: Vec3, pub mouse_acc: Vec2, pub cursor_pos: Vec2, } impl<'a> State<'a> { pub fn new(conn: TcpStream, window: &'a winit::window::Window) -> Result> { info!("new state"); let downloader = Arc::new(Downloader::new(ResourceStore::new_memory())); Ok(Self { camera: Camera::new(), network: Network::new(conn).into(), tree: SceneTree::default(), renderer: Renderer::new(window, downloader.clone())?, downloader, delta: DeltaState { time: Instant::now(), move_dir: Vec3::ZERO, mouse_acc: Vec2::ZERO, cursor_pos: Vec2::ZERO, }, prefab_index_res: None, prefab_index_res_loaded: None, prefab_index: PrefabIndex::default(), }) } pub fn draw(&mut self) { if let Err(e) = self.renderer.draw(&self.tree, &self.camera) { warn!("draw failed: {e:?}"); } } pub fn resize(&mut self, width: u32, height: u32) { self.renderer.resize(width, height); self.camera.aspect = width as f32 / height as f32; } pub fn click(&mut self, button: MouseButton, down: bool) { if !down || button != MouseButton::Right { return; } self.renderer .ui_renderer .add_surface(self.camera.new_ui_affine(), |ctx| { egui::Window::new("Funny window") .default_open(true) .show(ctx, |ui| { ui.label("world space ui actually kinda works now"); ui.label("Does input work?"); ui.button("Yes").clicked(); }); }); } pub fn update(&mut self) -> Result<()> { let now = Instant::now(); let dt = (now - self.delta.time).as_secs_f32(); self.delta.time = now; self.camera .update(self.delta.move_dir, self.delta.mouse_acc, dt); self.delta.mouse_acc = Vec2::ZERO; for p in self.network.packet_recv.try_iter() { self.downloader.packet(&p)?; self.tree.packet(&p); if let Packet::PrefabIndex(res) = &p { self.prefab_index_res = Some(res.to_owned()); } } self.downloader .update(&self.network) .context("downloader state")?; if self.prefab_index_res != self.prefab_index_res_loaded { if let Some(res) = &self.prefab_index_res { if let Some(index) = self.downloader.try_get(res.to_owned())? { info!("prefab index loaded"); self.prefab_index = index; self.prefab_index_res_loaded = Some(res.to_owned()); } } } Ok(()) } }