use std::collections::HashMap; use crate::{attachment::{PartInShip, Parts}, ecs::{CraftPartRequest, Part, Player, SingleStorage}, prelude::*, server::part::{SpawnPartBundle, SpawnPartRequest}}; pub fn craft_plugin(app: &mut App) { app.add_systems(Update, receive_crafting_request); } fn receive_crafting_request( mut craft_part_request: MessageReader>, part_query: Query<(&Transform, &Part, &PartInShip)>, player_query: Query<(Entity, &Transform, &Part), With>, parts_query: Query<&Parts>, mut storage_query: Query<(&mut SingleStorage)>, mut commands: Commands, asset_server: Res, ) { 'request: for request in craft_part_request.read() { // TODO: make crafting take time let (transform, part, parts_list) = if let Ok((transform, part, part_in_ship)) = part_query.get(request.crafting_part) { // this is a normal part let Ok(parts_list) = parts_query.get(part_in_ship.0) else { warn!("Couldn't find parts list in part in ship"); continue; }; let parts_list = parts_list.iter().collect::>(); (transform, part, parts_list) } else if let Ok((entity, transform, part)) = player_query.get(request.crafting_part) { // this is a player let parts_list = if let Ok(parts_list) = parts_query.get(entity) { let mut parts_list = parts_list.iter().collect::>(); parts_list.push(entity); parts_list } else { vec![entity] }; (transform, part, parts_list) } else { warn!("When receiving a crafting request, the crafting part didn't exist."); continue; }; // find total resource in the ship let mut total_resource = HashMap::new(); for part in parts_list.iter() { let Ok(storage) = storage_query.get_mut(*part) else { continue; }; if let Some(resource) = total_resource.get_mut(&storage.resource_name) { *resource += storage.stored; } else { total_resource.insert(storage.resource_name.clone(), storage.stored); } } // check if resources in ship are sufficient for (resource_name, amount) in total_resource { if let Some(resource) = request.inputs.get(&resource_name) { if (*resource as f32) > amount { continue 'request; } } else { // resource doesn't exist in the first place, continue continue 'request; } } // ok, we have enough resources // subtract recipe resources from ship let mut inputs = request.inputs.clone(); for part in parts_list.iter() { let Ok(mut storage) = storage_query.get_mut(*part) else { continue; }; if let Some(resource) = inputs.get_mut(&storage.resource_name) { if (*resource as f32) > storage.stored { *resource -= storage.stored as u32; storage.stored = 0.0; } else { storage.stored -= *resource as f32; inputs.remove(&storage.resource_name); } } } // ok, everything is good! spawn the part commands.spawn(SpawnPartBundle { req: SpawnPartRequest(asset_server.load( format!("config/parts/{}.part.toml", request.crafted_part.to_lowercase()))), transform: transform.with_translation(transform.translation + vec3(50.0, 0.0, 0.0)), }); } }