mirror of
https://github.com/Xevion/smart-rgb.git
synced 2025-12-05 23:16:23 -06:00
105 lines
4.5 KiB
Rust
105 lines
4.5 KiB
Rust
//! UI/Frontend module for rendering and user interaction
|
|
//!
|
|
//! This module contains all frontend-related concerns including:
|
|
//! - Protocol definitions for frontend-backend communication
|
|
//! - Input handling
|
|
//! - Leaderboard management
|
|
//! - Platform transport abstraction
|
|
|
|
pub mod input;
|
|
pub mod leaderboard;
|
|
pub mod plugin;
|
|
pub mod protocol;
|
|
pub mod transport;
|
|
|
|
// Re-export commonly used types
|
|
pub use input::{InputEvent, InputState, KeyCode, MouseButton, TileCoord, WorldPos, tile_from_index, tile_to_index};
|
|
pub use leaderboard::{LastAttacksDigest, LastLeaderboardDigest, LeaderboardThrottle, build_attacks_update, build_leaderboard_snapshot, emit_attacks_update_system, emit_leaderboard_snapshot_system};
|
|
pub use plugin::FrontendPlugin;
|
|
pub use protocol::{AttackEntry, AttacksUpdatePayload, BackendMessage, CameraCommand, CameraStateUpdate, FrontendMessage, GameOutcome, LeaderboardEntry, LeaderboardSnapshot, MapQuery, MapQueryResponse, PaletteInit, RenderInit, RenderInputEvent, RgbColor, ShipUpdateVariant, ShipsUpdatePayload, SpawnCountdown, TerrainInit, TerrainPalette, TerrainType, TerritoryDelta, TerritorySnapshot, TileChange};
|
|
pub use transport::{FrontendTransport, RenderBridge, handle_camera_update, handle_render_input};
|
|
|
|
use crate::networking::GameView;
|
|
use bevy_ecs::prelude::*;
|
|
use std::collections::HashMap;
|
|
|
|
/// Resource to track currently highlighted nation for visual feedback
|
|
#[derive(Resource, Default, Debug)]
|
|
pub struct NationHighlightState {
|
|
pub highlighted_nation: Option<u16>,
|
|
}
|
|
|
|
/// System that tracks hovered nation and emits highlight events
|
|
pub fn emit_nation_highlight_system(input_state: NonSend<std::sync::Arc<std::sync::Mutex<InputState>>>, game_view: Res<GameView>, mut highlight_state: ResMut<NationHighlightState>, mut backend_messages: MessageWriter<BackendMessage>) {
|
|
let Ok(input) = input_state.lock() else {
|
|
return;
|
|
};
|
|
|
|
let new_highlighted = if let Some(tile_coord) = input.cursor_tile() {
|
|
let tile_index = tile_to_index(tile_coord, game_view.width());
|
|
let owner_id = game_view.get_owner(tile_index as u32);
|
|
|
|
// Water (65535) and unclaimed (65534) should clear highlight
|
|
if owner_id >= 65534 { None } else { Some(owner_id) }
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// Only emit if highlight changed
|
|
if new_highlighted != highlight_state.highlighted_nation {
|
|
highlight_state.highlighted_nation = new_highlighted;
|
|
backend_messages.write(BackendMessage::HighlightNation { nation_id: new_highlighted });
|
|
}
|
|
}
|
|
|
|
/// Resource to track previous ship states for delta updates
|
|
#[derive(Resource, Default)]
|
|
pub struct ShipStateTracker {
|
|
/// Map of ship ID to current_path_index
|
|
ship_indices: HashMap<u32, u32>,
|
|
}
|
|
|
|
/// System that emits ship update variants to the frontend (delta-based)
|
|
/// - Create: sent when ship first appears
|
|
/// - Move: sent only when current_path_index changes
|
|
/// - Destroy: sent when ship disappears
|
|
pub fn emit_ships_update_system(game_view: Res<GameView>, mut ship_tracker: ResMut<ShipStateTracker>, mut backend_messages: MessageWriter<BackendMessage>) {
|
|
let current_ship_ids: std::collections::HashSet<u32> = game_view.ships.iter().map(|s| s.id).collect();
|
|
|
|
let mut updates = Vec::new();
|
|
|
|
// Detect destroyed ships
|
|
for &ship_id in ship_tracker.ship_indices.keys() {
|
|
if !current_ship_ids.contains(&ship_id) {
|
|
updates.push(ShipUpdateVariant::Destroy { id: ship_id });
|
|
}
|
|
}
|
|
|
|
// Detect new ships and moved ships
|
|
for ship in &game_view.ships {
|
|
match ship_tracker.ship_indices.get(&ship.id) {
|
|
None => {
|
|
// New ship - send Create
|
|
updates.push(ShipUpdateVariant::Create { id: ship.id, owner_id: ship.owner_id, path: ship.path.clone(), troops: ship.troops });
|
|
ship_tracker.ship_indices.insert(ship.id, ship.path_progress);
|
|
}
|
|
Some(&prev_index) if prev_index != ship.path_progress => {
|
|
// Ship moved to next tile - send Move
|
|
updates.push(ShipUpdateVariant::Move { id: ship.id, current_path_index: ship.path_progress });
|
|
ship_tracker.ship_indices.insert(ship.id, ship.path_progress);
|
|
}
|
|
_ => {
|
|
// No change, do nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up destroyed ships from tracker
|
|
ship_tracker.ship_indices.retain(|id, _| current_ship_ids.contains(id));
|
|
|
|
// Only send if there are updates
|
|
if !updates.is_empty() {
|
|
backend_messages.write(BackendMessage::ShipsUpdate(ShipsUpdatePayload { turn: game_view.turn_number, updates }));
|
|
}
|
|
}
|