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<FromClient<CraftPartRequest>>,
part_query: Query<(&Transform, &Part, &PartInShip)>,
player_query: Query<(Entity, &Transform, &Part), With<Player>>,
parts_query: Query<&Parts>,
mut storage_query: Query<(&mut SingleStorage)>,
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
'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::<Vec<_>>();
(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::<Vec<_>>();
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)),
});
}
}