use std::{collections::HashMap, f32::consts::PI}; use bevy::{math::vec2, prelude::*}; use bevy_rapier2d::prelude::*; use starkingdoms_common::SaveModule; use crate::{ capacity, mass, planet::PlanetType, player::component::Player, ws::WsEvent, Attach, CanAttach, LooseAttach, Packet, PartBundle, PartFlags, PartType, }; pub fn load_savefile( commands: &mut Commands, transform: Transform, player_id: Entity, parent: Entity, children: Vec>, attached_query: &mut Query< ( Entity, &PartType, &mut Transform, &mut Attach, &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags, ), (Without, Without), >, part_query: &mut Query< ( Entity, &PartType, &mut Transform, &mut Velocity, Option<&LooseAttach>, &mut PartFlags, ), (Without, Without, Without), >, player_query: &mut Query< ( Entity, &mut Player, &Transform, &Velocity, &mut Attach, &mut PartFlags, ), Without, >, player_comp: &mut Player, ) -> [Option; 4] { let mut ret = [None, None, None, None]; for (i, child) in children.iter().enumerate() { if let Some(child) = child { let part_type = PartType::from(child.part_type); //let attachable = can_attach != None; let p_pos = transform.translation; let angle = transform.rotation.to_euler(EulerRot::ZYX).0; let mut offset = Vec2::ZERO; let mut angle_offset = 0.; if i == 2 { //offset = Vec2::new(53., -53.); offset = Vec2::new(0., -1.06); angle_offset = 0.; } else if i == 0 { //offset = Vec2::new(-53., 53.); offset = Vec2::new(0., 1.06); angle_offset = PI; } else if i == 1 { //offset = Vec2::new(53., 53.); offset = Vec2::new(1.06, 0.); angle_offset = PI / 2.; } else if i == 3 { //offset = Vec2::new(-53., 53.); offset = Vec2::new(-1.06, 0.); angle_offset = -PI / 2.; } let transform = Transform::from_xyz( p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(), p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(), 0., ) .with_rotation(Quat::from_euler( EulerRot::ZYX, angle + angle_offset, 0., 0., )); let module_id = { let module = commands.spawn(PartBundle { transform: TransformBundle::from(transform), part_type: child.part_type.into(), flags: PartFlags { attached: true }, ..default() }); module.id() }; let children = if part_type != PartType::LandingThruster { load_savefile( commands, transform, player_id, module_id, child.children.clone(), attached_query, part_query, player_query, player_comp, ) } else { [None, None, None, None] }; let mut module = commands.entity(module_id); module.insert(Attach { associated_player: Some(player_id), parent: Some(parent), children, }); //module.5.attached = true; ret[i] = Some(module.id()); module .with_children(|children| { children .spawn(if part_type == PartType::Cargo { Collider::cuboid(0.375, 0.46875) } else if part_type == PartType::Hub { Collider::cuboid(0.5, 0.5) } else if part_type == PartType::LandingThruster { Collider::cuboid(0.5, 0.375) } else { Collider::cuboid(0.5, 0.5) }) .insert(TransformBundle::from(Transform::from_xyz( 0., if part_type == PartType::Cargo { 0.03125 } else if part_type == PartType::Hub { 0. } else if part_type == PartType::LandingThruster { 0.125 } else { 0. }, 0., ))); }) .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: vec2(0.0, 0.0), mass: mass!(part_type), principal_inertia: 7.5, })); if part_type == PartType::Hub { module.insert(CanAttach(15)); } let joint = FixedJointBuilder::new() .local_anchor1(vec2(offset.x, offset.y)) .local_basis1(angle_offset); module.insert(ImpulseJoint::new(parent, joint)); if part_type == PartType::LandingThruster { let joint = PrismaticJointBuilder::new(Vec2::new(0., 1.)) .set_motor(0., 0., 3000., 3000.) .limits([0., 1.]) .build(); let mut suspension = commands.spawn(PartBundle { transform: TransformBundle::from( Transform::from_xyz( p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(), p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(), 0., ) .with_rotation(Quat::from_euler( EulerRot::ZYX, angle + angle_offset, 0., 0., )), ), part_type: PartType::LandingThrusterSuspension, flags: PartFlags { attached: true }, ..default() }); suspension .with_children(|children| { children .spawn(Collider::cuboid(0.5, 0.02)) .insert(TransformBundle::from(Transform::from_xyz(0., -0.48, 0.))); }) .insert(ImpulseJoint::new(module_id, joint)) .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: vec2(0.0, 0.0), mass: 0.00000000000001, principal_inertia: 0.0000000000001, })) .insert(Attach { associated_player: Some(player_id), parent: Some(module_id), children: [None, None, None, None], }); let suspension_id = suspension.id(); let mut module = commands.entity(module_id); module.remove::(); module.insert(Attach { associated_player: Some(player_id), parent: Some(parent), children: [None, None, Some(suspension_id), None], }); } player_comp.energy_capacity += capacity!(part_type); } } ret } pub fn construct_save_data( attach: Attach, attached_query: &Query< ( Entity, &PartType, &mut Transform, &mut Attach, &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags, ), (Without, Without), >, ) -> Vec> { let mut modules = vec![None, None, None, None]; for (i, child) in attach.children.iter().enumerate() { if let Some(child) = child { let (_, part_type, _, attach, _, _, _, _) = attached_query.get(*child).unwrap(); if *part_type == PartType::LandingThrusterSuspension { continue; } let child_save_module = construct_save_data(attach.clone(), attached_query); modules[i] = Some(SaveModule { part_type: (*part_type).into(), children: child_save_module, }); } } modules } pub fn save_eligibility( rapier_context: Res, planet_query: Query<(Entity, &PlanetType, &Children)>, attached_query: Query<&Attach, (Without, Without)>, collider_query: Query<(&Collider, &Parent), (Without, Without)>, mut player_query: Query<&mut Player>, mut packet_send: EventWriter, ) { let mut player_eligibilities = HashMap::new(); for (_planet_entity, _planet_type, children) in &planet_query { for (entity1, entity2, intersecting) in rapier_context.intersection_pairs_with(*children.first().unwrap()) { if intersecting { let other = if *children.first().unwrap() == entity1 { entity2 } else { entity1 }; let player_entity = if player_query.contains(other) { other } else if attached_query.contains(other) { attached_query .get(other) .unwrap() .associated_player .unwrap() } else if collider_query.contains(other) { let parent = collider_query.get(other).unwrap().1.get(); if attached_query.contains(parent) { attached_query .get(parent) .unwrap() .associated_player .unwrap() } else { continue; } } else { continue; }; let player = player_query.get(player_entity).unwrap(); if !player.save_eligibility { if player_eligibilities.contains_key(&player_entity) { player_eligibilities.remove(&player_entity); } player_eligibilities.insert(player_entity, true); } } else { let other = if *children.first().unwrap() == entity1 { entity2 } else { entity1 }; if player_query.contains(other) { let mut player = player_query.get_mut(other).unwrap(); if player.save_eligibility && !(player_eligibilities.contains_key(&other) && *player_eligibilities.get(&other).unwrap()) { player.save_eligibility = false; player_eligibilities.insert(other, false); } } } } } for (other, eligible) in player_eligibilities.iter() { let mut player = player_query.get_mut(*other).unwrap(); player.save_eligibility = *eligible; let packet = Packet::SaveEligibility { eligible: *eligible, }; packet_send.send(WsEvent::Send { to: player.addr, message: packet.into(), }); } }