use aeronet::io::{Session, SessionEndpoint};
use aeronet::io::connection::{DisconnectReason, Disconnected};
use aeronet_transport::lane::LaneKind;
//use aeronet_replicon::client::AeronetRepliconClient;
use aeronet_transport::{Transport, TransportConfig};
use aeronet_websocket::client::{ClientConfig, WebSocketClient};
use crate::client::crafting::ui::crafting_ui_plugin;
use crate::client::key_input::key_input_plugin;
use crate::client::parts::parts_plugin;
use crate::client::planet::indicators::indicators_plugin;
use crate::client::starfield::starfield_plugin;
use crate::client::starguide::orbit::starguide_orbit_plugin;
use crate::client::ui::ui_plugin;
use crate::client::zoom::zoom_plugin;
use crate::client::starguide::init::starguide_init_plugin;
use crate::client::starguide::input::starguide_input_plugin;
use starguide::components::StarguideGizmos;
use bevy::dev_tools::picking_debug::DebugPickingMode;
use crate::prelude::*;
use planet::incoming_planets::incoming_planets_plugin;
use crate::client::components::Me;
use crate::client::ship::attachment::client_attachment_plugin;
use crate::shared::ecs::{GameplayState, TimeOffset};
use crate::shared::gravity::update_gravity;
use crate::shared::net::{Hi, ClientMessageRegistry, ServerMessageRegistry, ServerEntityMap, TransportLanes};
use crate::shared::orbit::OrbitPlugin;
pub mod colors;
pub mod key_input;
pub mod parts;
pub mod planet;
pub mod starfield;
pub mod ui;
pub mod zoom;
pub mod ship;
pub mod rendering;
pub mod input;
pub mod starguide;
pub mod crafting;
pub mod components;
pub mod plugins;
mod net;
pub struct ClientPlugin {
pub server: Option<String>
}
impl Plugin for ClientPlugin {
fn build(&self, app: &mut App) {
app
.init_gizmo_group::<StarguideGizmos>()
.add_plugins(net::net_plugin)
.add_plugins(rendering::render_plugin)
.add_plugins(OrbitPlugin)
.add_systems(FixedUpdate, update_gravity.before(PhysicsSystems::Prepare))
.add_plugins(input::input_plugin)
.add_plugins(ship::thrusters::client_thrusters_plugin)
.add_plugins((incoming_planets_plugin, indicators_plugin))
.add_plugins(parts_plugin)
.add_plugins(key_input_plugin)
.add_plugins(starfield_plugin)
.add_plugins(ui_plugin)
.add_plugins(zoom_plugin)
.add_plugins(client_attachment_plugin)
.add_plugins(starguide_init_plugin)
.add_plugins(starguide_input_plugin)
.add_plugins(starguide_orbit_plugin)
.add_plugins(crafting_ui_plugin)
.insert_resource(HeartyEntityId(None))
.add_systems(Update, (handle_hi, find_me))
.insert_state(GameplayState::Main)
.insert_resource(DebugPickingMode::Disabled)
.insert_resource(TimeOffset::default());
let server = self.server.clone();
app.add_systems(PostStartup, move |mut commands: Commands| {
#[cfg(target_arch = "wasm32")]
let config = ClientConfig {};
#[cfg(not(target_arch = "wasm32"))]
let config = ClientConfig::builder().with_no_cert_validation();
let Some(server) = server.as_ref() else { return };
commands.spawn((Name::new("default-session"), TransportConfig { max_memory_usage: 536_870_912, ..default() }, /*AeronetRepliconClient*/))
.queue(
WebSocketClient::connect(config, server.clone()));
});
if self.server.is_some() {
app.add_observer(on_connecting);
app.add_observer(on_connected);
app.add_observer(on_disconnected);
}
}
}
pub fn on_connecting(
trigger: On<Add, SessionEndpoint>,
names: Query<&Name>,
mut commands: Commands,
) {
let entity = trigger.event_target();
let name = names.get(entity).unwrap();
info!("{name} is connecting");
}
pub fn on_connected(
trigger: On<Add, Session>,
names: Query<&Name>,
sessions: Query<&Session>,
lanes: Res<TransportLanes>,
mut commands: Commands,
) {
let entity = trigger.event_target();
let name = names.get(entity).unwrap();
let Ok(session) = sessions.get(entity) else {
return;
};
let transport = Transport::new(
session,
lanes.lanes.iter().map(|u| u.clone()),
lanes.lanes.iter().map(|u| u.clone()),
bevy::platform::time::Instant::now(),
).expect("packet MTU too small to support transport");
commands.entity(entity).insert(transport);
info!("{name} is connected");
}
pub fn on_disconnected(trigger: On<Disconnected>, names: Query<&Name>) {
let session = trigger.event_target();
let name = names.get(session).unwrap();
match &trigger.reason {
DisconnectReason::ByUser(reason) => {
info!(?name, ?reason, "session disconnected by user");
}
DisconnectReason::ByPeer(reason) => {
info!(?name, ?reason, "session disconnected by peer");
}
DisconnectReason::ByError(err) => {
warn!(?name, "session disconnected due to error: {err:?}");
}
}
}
#[derive(Resource)]
pub struct HeartyEntityId(Option<Entity>);
pub fn handle_hi(
mut msgs: MessageReader<Hi>,
mut res: ResMut<HeartyEntityId>,
mut time_offset: ResMut<TimeOffset>,
) {
for msg in msgs.read() {
let we_are = msg.you_are;
res.0 = Some(we_are);
time_offset.0 = msg.time_offset;
}
}
pub fn find_me(
entity_map: Res<ServerEntityMap>,
mut res: ResMut<HeartyEntityId>,
mut commands: Commands,
) {
let Some(server_entity) = res.0 else { return; };
let Some(local_entity) = entity_map.server_to_client.get(&server_entity) else { return; };
let Ok(mut e) = commands.get_entity(*local_entity) else { return; };
info!(?local_entity, ?server_entity, "joined successfully");
e.insert(Me);
res.0 = None;
}