Files
phos-neo/game/buildings/src/assets/building_asset.rs
Amatsugu ebae1599f1
Some checks failed
Rust / build (push) Failing after 4s
building spawning update
2026-03-18 15:15:11 -04:00

159 lines
4.1 KiB
Rust

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<Gltf>,
pub base_mesh_path: String,
pub cost: Vec<ResourceIdentifier>,
pub consumption: Vec<ResourceIdentifier>,
pub production: Vec<ResourceIdentifier>,
pub health: u32,
pub building_type: BuildingType,
pub components: Option<Vec<ComponentDefination>>,
}
impl BuildingAsset
{
#[allow(unused)]
pub fn spawn(
&self,
pos: Vec3,
rot: Quat,
gltf: &Gltf,
commands: &mut Commands,
meshes: &Assets<GltfMesh>,
nodes: &Assets<GltfNode>,
) -> Option<Entity>
{
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<GltfMesh>,
nodes: &Assets<GltfNode>,
commands: &mut RelatedSpawnerCommands<ChildOf>,
parent: &String,
) -> Option<Entity>
{
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
;?
);