/* 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::{ packets::{Object, Packet, Resource}, resources::Prefab, }; use glam::Vec3A; use log::warn; use std::collections::{BTreeSet, HashMap}; #[derive(Default)] pub struct SceneTree { pub objects: HashMap, } pub struct ObjectData { pub pos: Vec3A, pub rot: Vec3A, pub parent: Object, pub children: BTreeSet, pub pose: Vec, pub res: Resource, } impl SceneTree { pub fn packet(&mut self, p: &Packet) { match p { Packet::Add(object, res) => { self.add(*object, res.to_owned()); } Packet::Remove(object) => { self.remove_reparent(*object, &mut ()); } Packet::Position(object, pos, rot) => { if let Some(o) = self.objects.get_mut(object) { o.pos = *pos; o.rot = *rot; } } // Packet::Pose(object, pose) => { // if let Some(o) = self.objects.get_mut(object) { // o.pose = pose.to_vec(); // } // } Packet::Parent(parent, child) => { self.reparent(*parent, *child); } _ => (), } } pub fn add(&mut self, object: Object, res: Resource) { self.objects.insert(object, ObjectData { parent: Object(0), pos: Vec3A::ZERO, rot: Vec3A::ZERO, pose: Vec::new(), res: res.clone(), children: BTreeSet::new(), }); } pub fn reparent(&mut self, parent: Object, child: Object) { fn check_parent_loop(tree: &SceneTree, o: Object, test: Object) -> bool { if o == test { true } else { let parent = tree.objects[&o].parent; if parent == Object::ROOT { false } else { check_parent_loop(tree, parent, test) } } } if !self.objects.contains_key(&parent) || !self.objects.contains_key(&child) { warn!("reparent of missing objects"); return; } if check_parent_loop(self, parent, child) { warn!("cyclic parenting prevented"); return; } if let Some(co) = self.objects.get(&child) { let old_parent = co.parent; if let Some(po) = self.objects.get_mut(&old_parent) { po.children.remove(&child); } } if let Some(po) = self.objects.get_mut(&parent) { po.children.insert(child); } if let Some(co) = self.objects.get_mut(&child) { co.parent = parent; } } pub fn remove_reparent(&mut self, object: Object, ps: &mut dyn PacketSink) { if let Some(o) = self.objects.remove(&object) { for c in o.children { self.reparent(o.parent, c); ps.push(Packet::Parent(o.parent, c)); } ps.push(Packet::Remove(object)); } } pub fn remove_recursive(&mut self, object: Object, ps: &mut dyn PacketSink) { if let Some(o) = self.objects.remove(&object) { for c in o.children { self.remove_recursive(c, ps); } ps.push(Packet::Remove(object)); } } pub fn prime_client(&self) -> impl Iterator { self.objects.iter().flat_map(|(object, data)| { [ Packet::Add(*object, data.res.clone()), Packet::Parent(*object, data.parent), Packet::Position(*object, data.pos, data.rot), ] .into_iter() // .chain(if data.pose.is_empty() { // None // } else { // Some(Packet::Pose(*object, data.pose.clone())) // }) }) } } pub trait PacketSink { fn push(&mut self, p: Packet); } impl PacketSink for Vec { fn push(&mut self, p: Packet) { Vec::push(self, p); } } impl PacketSink for () { fn push(&mut self, _: Packet) {} }