use std::{collections::HashMap, f32::consts::PI};
use bevy::{math::vec2, prelude::*};
use bevy_rapier2d::prelude::*;
use starkingdoms_common::{packet::Packet, PartType as c_PartType, SaveModule};
use crate::{
capacity, mass, planet::PlanetType, player::component::Player, ws::{PacketMessageConvert, WsEvent}, Attach, CanAttach,
LooseAttach, PartBundle, PartFlags, PartType,
};
pub fn load_savefile(
commands: &mut Commands,
transform: Transform,
player_id: Entity,
parent: Entity,
children: Vec<Option<SaveModule>>,
attached_query: &mut Query<
(
Entity,
&PartType,
&mut Transform,
&mut Attach,
&Velocity,
Option<&CanAttach>,
Option<&LooseAttach>,
&mut PartFlags,
),
(Without<PlanetType>, Without<Player>),
>,
part_query: &mut Query<
(
Entity,
&PartType,
&mut Transform,
&mut Velocity,
Option<&LooseAttach>,
&mut PartFlags,
),
(Without<PlanetType>, Without<Player>, Without<Attach>),
>,
player_query: &mut Query<
(
Entity,
&mut Player,
&Transform,
&Velocity,
&mut Attach,
&mut PartFlags,
),
Without<PlanetType>,
>,
player_comp: &mut Player,
) -> ([Option<Entity>; 4], HashMap<PartType, usize>) {
let mut ret = [None, None, None, None];
let mut module_count = HashMap::new();
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.0 != c_PartType::LandingThruster {
let (children, count) = load_savefile(
commands,
transform,
player_id,
module_id,
child.children.clone(),
attached_query,
part_query,
player_query,
player_comp,
);
for (part_type, count) in count {
match module_count.get_mut(&part_type) {
Some(old_count) => {
*old_count += count;
}
None => {
module_count.insert(part_type, count);
}
}
}
children
} else {
[None, None, None, None]
};
match module_count.get_mut(&part_type) {
Some(old_count) => {
*old_count += 1;
}
None => {
module_count.insert(part_type, 1);
}
}
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.0 == c_PartType::Chassis {
Collider::cuboid(0.375, 0.46875)
} else if part_type.0 == c_PartType::Hub {
Collider::cuboid(0.5, 0.5)
} else if part_type.0 == c_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.0 == c_PartType::Chassis {
0.03125
} else if part_type.0 == c_PartType::Hub {
0.
} else if part_type.0 == c_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.0 == c_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.0 == c_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: c_PartType::LandingThrusterSuspension.into(),
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::<Attach>();
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, module_count)
}
pub fn construct_save_data(
attach: Attach,
attached_query: &Query<
(
Entity,
&PartType,
&mut Transform,
&mut Attach,
&Velocity,
Option<&CanAttach>,
Option<&LooseAttach>,
&mut PartFlags,
),
(Without<PlanetType>, Without<Player>),
>,
) -> Vec<Option<SaveModule>> {
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.0 == c_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<RapierContext>,
planet_query: Query<(Entity, &PlanetType, &Children)>,
attached_query: Query<&Attach, (Without<PlanetType>, Without<Player>)>,
collider_query: Query<(&Collider, &Parent), (Without<Player>, Without<Attach>)>,
mut player_query: Query<&mut Player>,
mut packet_send: EventWriter<WsEvent>,
) {
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_message(),
});
}
}