use asset_loader::create_asset_loader; use bevy::{ ecs::relationship::RelatedSpawnerCommands, gltf::{GltfMesh, GltfNode}, prelude::*, }; use serde::{Deserialize, Serialize}; use shared::{component_defination::ComponentDefination, identifiers::ResourceIdentifier}; use crate::{ buildings::{ basic_building::BasicBuildingInfo, conduit_building::ResourceConduitInfo, factory_building::FactoryBuildingInfo, resource_gathering::ResourceGatheringBuildingInfo, tech_building::TechBuildingInfo, }, footprint::BuildingFootprint, prelude::Building, }; #[derive(Asset, TypePath, Debug, Serialize, Deserialize)] pub struct BuildingAsset { pub name: String, pub description: String, pub footprint: BuildingFootprint, pub prefab_path: String, #[serde(skip)] pub prefab: Handle, pub base_mesh_path: String, pub cost: Vec, pub consumption: Vec, pub production: Vec, pub health: u32, pub building_type: BuildingType, pub components: Option>, } impl BuildingAsset { #[allow(unused)] pub fn spawn( &self, pos: Vec3, rot: Quat, gltf: &Gltf, commands: &mut Commands, meshes: &Assets, nodes: &Assets, ) -> Option { let base_node = &gltf.named_nodes[&self.base_mesh_path.clone().into_boxed_str()]; if let Some(node) = nodes.get(base_node.id()) { if let Some(mesh_handle) = &node.mesh { if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) { if let Some(primitive) = gltf_mesh.primitives.first() { let mesh = primitive.mesh.clone(); let mat = primitive .material .clone() .expect(format!("Mesh '{}' does not have a meterial", primitive.name.as_str()).as_str()); let mut entity = commands.spawn(( Mesh3d(mesh), MeshMaterial3d(mat), Transform::from_translation(pos).with_rotation(rot), Building, )); entity.with_children(|b| { for child in &node.children { let child_node = nodes.get(child.id()); if child_node.is_none() { continue; } self.process_node(child_node.unwrap(), meshes, nodes, b, &node.name); } }); if let Some(component) = self.get_component_def(&format!("/{0}", &node.name)) { component.apply(&mut entity); } return Some(entity.id()); } } } } return None; } fn process_node( &self, node: &GltfNode, meshes: &Assets, nodes: &Assets, commands: &mut RelatedSpawnerCommands, parent: &String, ) -> Option { let path = format!("{0}/{1}", parent, node.name); if let Some(mesh) = &node.mesh { if let Some(gltf_mesh) = meshes.get(mesh.id()) { if let Some(primitive) = gltf_mesh.primitives.first() { let mesh = primitive.mesh.clone(); let mat = primitive .material .clone() .expect(format!("Mesh '{}' does not have a meterial", primitive.name.as_str()).as_str()); let mut entity = commands.spawn((Mesh3d(mesh), MeshMaterial3d(mat), node.transform, Building)); entity.with_children(|b| { for child in &node.children { let child_node = nodes.get(child.id()); if child_node.is_none() { continue; } self.process_node(child_node.unwrap(), meshes, nodes, b, &path); } }); if let Some(component) = self.get_component_def(&path) { component.apply(&mut entity); } return Some(entity.id()); } } } return None; } fn get_component_def(&self, path: &String) -> Option<&ComponentDefination> { if let Some(components) = &self.components { for c in components { if c.path.ends_with(path) { return Some(c); } } } return None; } } #[derive(Serialize, Deserialize, Debug, TypePath)] pub enum BuildingType { Basic(BasicBuildingInfo), Gathering(ResourceGatheringBuildingInfo), FactoryBuildingInfo(FactoryBuildingInfo), ResourceConduit(ResourceConduitInfo), Tech(TechBuildingInfo), } create_asset_loader!( BuildingAssetPlugin, BuildingAssetLoader, BuildingAsset, &["building", "building.ron"], prefab_path -> prefab ;? );