Basic UI Shell: bring back the in-game flight HUD and station info panel, and implement the missing "station mode panel swap." Implementation: - New `in_system/hud.rs` with a reactive, idempotent `sync_hud_panels` system: it shows the station info panel while the player is `Docked` and the flight HUD while in `FlightState`, spawning/despawning only when the on-screen panel disagrees with the player's state. This replaces the old fragile event-driven spawn/despawn scattered through the transition systems. - Re-enabled the docked info panel (`ui.rs`) and flight HUD (`flight_ui.rs`), restructured both as small corner-anchored overlays with NO full-screen root so they only block camera orbit input when the cursor is directly over a panel (orbit_camera_control suppresses input over any UI node). - Made the docked panel info-only (actions live in the contextual action panel, which adapts to docked/flight modes). - Fixed the broken undock chain: `start_undocking`/`start_travel` now take a real `now_ms` (was hardcoded `0.0`, completing instantly) and a new `complete_operations` bridge maps `OperationCompletedEvent::Undocking` back to `UndockEvent` so `handle_undock` actually runs. - Wired `ActionType::Dock` to fire a `DockEvent` for a targeted station / habitable planet so the flight→docked swap is reachable too. - `handle_docking` now also clears Velocity/MoveTarget/SelectedTarget so the docked ship stops cleanly. - Fixed deprecated Bevy 0.16 APIs (single_mut, EventWriter::write, despawn) and removed now-dead code, dropping total warnings 183→137. Compiles clean (`cargo check`); no new warnings in touched files.
191 lines
7.0 KiB
Rust
191 lines
7.0 KiB
Rust
//! In-system gameplay module.
|
|
//!
|
|
//! Handles the system-scale view where the player is docked at a station
|
|
//! within their selected starting system. This is the entry point to actual
|
|
//! gameplay after onboarding.
|
|
|
|
mod actions;
|
|
mod docked;
|
|
mod flight;
|
|
mod flight_ui;
|
|
mod hud;
|
|
mod operations;
|
|
mod scene;
|
|
mod target;
|
|
mod ui;
|
|
|
|
use bevy::ecs::system::SystemParam;
|
|
use bevy::prelude::*;
|
|
|
|
use crate::state::AppState;
|
|
|
|
pub use docked::{DockedState, UndockEvent};
|
|
pub use flight::{FlightState, FlightControlsPlugin};
|
|
pub use scene::ActiveSystem;
|
|
pub use target::{Targetable, TargetKind, SelectedTarget, TargetSelectionPlugin};
|
|
pub use actions::{ContextualActionPlugin, ActionType, ActionTriggeredEvent, ActionUi};
|
|
pub use operations::TimedOperationPlugin;
|
|
|
|
pub struct InSystemPlugin;
|
|
|
|
impl Plugin for InSystemPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_resource::<DockedState>()
|
|
.init_resource::<ActiveSystem>()
|
|
.add_event::<UndockEvent>()
|
|
.add_plugins(FlightControlsPlugin)
|
|
.add_plugins(TargetSelectionPlugin)
|
|
.add_plugins(ContextualActionPlugin)
|
|
.add_plugins(TimedOperationPlugin)
|
|
.add_systems(
|
|
OnEnter(AppState::InGame),
|
|
(scene::setup_in_system_view, add_targetable_to_pois).chain(),
|
|
)
|
|
.add_systems(
|
|
OnExit(AppState::InGame),
|
|
(hud::despawn_in_system_hud, scene::despawn_in_system_scene).chain(),
|
|
)
|
|
.add_systems(
|
|
Update,
|
|
(
|
|
hud::sync_hud_panels,
|
|
ui::refresh_docked_ui,
|
|
flight_ui::update_flight_ui,
|
|
complete_operations,
|
|
handle_action_triggered,
|
|
)
|
|
.chain()
|
|
.run_if(in_state(AppState::InGame)),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Bundles the resources/event-writers [`handle_action_triggered`] dispatches
|
|
/// through, keeping its parameter list under the system-argument threshold.
|
|
#[derive(SystemParam)]
|
|
struct ActionDispatch<'w> {
|
|
time: Res<'w, Time>,
|
|
durations: Res<'w, operations::OperationDurations>,
|
|
started: EventWriter<'w, operations::OperationStartedEvent>,
|
|
dock: EventWriter<'w, flight::DockEvent>,
|
|
}
|
|
|
|
/// Handle action triggered events from the contextual action buttons.
|
|
///
|
|
/// - **Undock** starts a timed operation; on completion [`complete_operations`]
|
|
/// fires the [`UndockEvent`] that drives the docked → flight transition.
|
|
/// - **Dock** fires a [`flight::DockEvent`] directly (instant) for the selected
|
|
/// station / habitable planet so the flight → docked transition (and the HUD
|
|
/// swap back to the station panel) is reachable.
|
|
fn handle_action_triggered(
|
|
mut commands: Commands,
|
|
mut events: EventReader<ActionTriggeredEvent>,
|
|
player_query: Query<Entity, With<scene::PlayerShip>>,
|
|
selected_target_query: Query<&SelectedTarget, With<scene::PlayerShip>>,
|
|
mut dispatch: ActionDispatch,
|
|
) {
|
|
let Ok(player_entity) = player_query.single() else {
|
|
return;
|
|
};
|
|
let now_ms = dispatch.time.elapsed_secs_f64() * 1000.0;
|
|
|
|
for event in events.read() {
|
|
bevy::log::info!("Action triggered: {:?}", event.action_type);
|
|
|
|
match event.action_type {
|
|
ActionType::Undock => {
|
|
operations::start_undocking(
|
|
&mut commands,
|
|
player_entity,
|
|
&dispatch.durations,
|
|
&mut dispatch.started,
|
|
now_ms,
|
|
);
|
|
}
|
|
ActionType::Approach => {
|
|
if let Ok(selected) = selected_target_query.single() {
|
|
operations::start_travel(
|
|
&mut commands,
|
|
player_entity,
|
|
selected.name.clone(),
|
|
&dispatch.durations,
|
|
&mut dispatch.started,
|
|
now_ms,
|
|
);
|
|
}
|
|
}
|
|
ActionType::Dock => {
|
|
if let Ok(selected) = selected_target_query.single() {
|
|
match selected.kind {
|
|
TargetKind::Station | TargetKind::HabitablePlanet => {
|
|
bevy::log::info!("Docking at {}", selected.name);
|
|
dispatch.dock.write(flight::DockEvent {
|
|
ship: player_entity,
|
|
station: selected.entity,
|
|
});
|
|
}
|
|
kind => {
|
|
bevy::log::info!("Cannot dock at {:?} target", kind);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ActionType::StartMining => {
|
|
bevy::log::info!("Start mining action triggered");
|
|
}
|
|
_ => {
|
|
bevy::log::info!("Other action: {:?}", event.action_type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Bridge completed timed operations back into the docked ↔ flight state
|
|
/// machine. Today only undocking is wired — when the timed undock completes it
|
|
/// fires the [`UndockEvent`] consumed by [`flight::handle_undock`]. Other
|
|
/// operation kinds are logged for future work.
|
|
fn complete_operations(
|
|
mut completed: EventReader<operations::OperationCompletedEvent>,
|
|
docked: Res<DockedState>,
|
|
mut undock_events: EventWriter<UndockEvent>,
|
|
) {
|
|
for event in completed.read() {
|
|
bevy::log::info!(
|
|
"Operation completed: {:?} on entity {:?}",
|
|
event.kind,
|
|
event.entity
|
|
);
|
|
if let operations::OperationKind::Undocking = event.kind {
|
|
undock_events.write(UndockEvent {
|
|
station_entity: docked.station_entity.unwrap_or(Entity::PLACEHOLDER),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Add Targetable components to spawned POIs (stations and asteroid belts)
|
|
/// so they can be selected by the target selection system.
|
|
fn add_targetable_to_pois(
|
|
mut commands: Commands,
|
|
station_query: Query<(Entity, &crate::gameplay::galaxy::Identifiable), (With<crate::gameplay::galaxy::Station>, Without<Targetable>)>,
|
|
belt_query: Query<(Entity, &crate::gameplay::galaxy::Identifiable), (With<crate::gameplay::galaxy::AsteroidBelt>, Without<Targetable>)>,
|
|
) {
|
|
// Add Targetable to stations
|
|
for (entity, identifiable) in station_query.iter() {
|
|
bevy::log::debug!("Adding Targetable component to station: {}", identifiable.display_name);
|
|
commands.entity(entity).insert(Targetable {
|
|
kind: TargetKind::Station,
|
|
name: identifiable.display_name.clone(),
|
|
});
|
|
}
|
|
|
|
// Add Targetable to asteroid belts
|
|
for (entity, identifiable) in belt_query.iter() {
|
|
bevy::log::debug!("Adding Targetable component to asteroid belt: {}", identifiable.display_name);
|
|
commands.entity(entity).insert(Targetable {
|
|
kind: TargetKind::AsteroidBelt,
|
|
name: identifiable.display_name.clone(),
|
|
});
|
|
}
|
|
}
|