diff --git a/src/debug.rs b/src/debug.rs index b9e4a51546..088ff98702 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,10 +1,18 @@ +//! Debugging tools. +//! +//! Sets up the Bevy world inspector, and the puffin profiler. +//! +//! More debug related ui code can be found in [`ui::debug_tools`]. + use crate::prelude::*; use bevy::window::PrimaryWindow; use bevy_egui::EguiContext; use bevy_inspector_egui::{bevy_inspector, inspector_egui_impls}; +/// Debug plugin. pub struct JumpyDebugPlugin; +/// Resource that tracks whether or not the world inspector window is visible. #[derive(Resource, Deref, DerefMut, Default)] pub struct WorldInspectorEnabled(pub bool); @@ -23,6 +31,7 @@ impl Plugin for JumpyDebugPlugin { } } +/// Renders the world-inspector UI. pub fn world_inspector(world: &mut World) { if !**world.resource::() { return; diff --git a/src/input.rs b/src/input.rs index 69f85b804c..660de16258 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,5 +1,14 @@ +//! Player input types. +//! +//! We use the [`leafwing-input-manager`] plugin for collecting user input in Jumpy. This crate +//! installs the input manager plugin and registers the [`PlayerAction`] type as the collectible +//! player input. +//! +//! [`leafwing-input-manager`]: https://docs.rs/leafwing-input-manager + use crate::prelude::*; +/// Input plugin. pub struct JumpyPlayerInputPlugin; impl Plugin for JumpyPlayerInputPlugin { diff --git a/src/loading.rs b/src/loading.rs index 9479d98503..cc96dddc73 100644 --- a/src/loading.rs +++ b/src/loading.rs @@ -1,3 +1,5 @@ +//! Initial game loading implementation. + use bevy::ecs::system::SystemParam; use bevy_egui::{egui, EguiContexts}; use bevy_fluent::Locale; @@ -13,6 +15,7 @@ use crate::{ prelude::*, }; +/// Loading plugin. pub struct JumpyLoadingPlugin; impl Plugin for JumpyLoadingPlugin { @@ -99,9 +102,21 @@ fn core_assets_loaded( true } +/// Component added to the entities used to collect player input. +/// +/// The inner [`usize`] is the player index. +/// +/// The `leafwing-input-manager` tracks input for specific entities, instead of globally collecting +/// input. This usually makes things easier, but for our usje-case, we need to be able to collect +/// user input even for players that haven't, spawned yet. +/// +/// To facilitate this, for every user we spawn [`jumpy_core::MAX_PLAYERS`] entities with a +/// [`PlayerInputCollector`] and the `InputManagerBundle` that is needed for +/// `leafwing-input-manager`. #[derive(Component)] pub struct PlayerInputCollector(pub usize); +/// Systemrunonce to spawn the menu input collector. fn setup(mut commands: Commands) { commands.spawn(( Name::new("Menu Input Collector"), @@ -112,7 +127,7 @@ fn setup(mut commands: Commands) { )); } -/// System param used to load and hot reload the game +/// System param used to load and hot reload the game. #[derive(SystemParam)] pub struct GameLoader<'w, 's> { skip_next_asset_update_event: Local<'s, bool>, @@ -335,6 +350,7 @@ impl<'w, 's> GameLoader<'w, 's> { } } +/// Get the input map for the menu controls. fn menu_input_map() -> InputMap { InputMap::default() .set_gamepad(Gamepad::new(0)) @@ -404,12 +420,12 @@ fn menu_input_map() -> InputMap { .build() } -/// System to run the initial game load +/// System to run the initial game load. fn load_game(loader: GameLoader) { loader.load(false); } -/// System to check for asset changes and hot reload the game +/// System to check for asset changes and hot reload the game. fn hot_reload_game(loader: GameLoader) { loader.load(true); } diff --git a/src/localization.rs b/src/localization.rs index 6dc79e5144..2f396c9b07 100644 --- a/src/localization.rs +++ b/src/localization.rs @@ -1,3 +1,5 @@ +//! Localization utilities & initialization. + use std::borrow::Borrow; use bevy::{prelude::*, utils::HashMap}; @@ -6,6 +8,8 @@ use fluent::FluentArgs; use fluent_content::{Content, Request}; /// Plugin for initializing and loading the [`Localization`] resource. +/// +/// [`Localization`]: https://docs.rs/bevy_fluent/latest/bevy_fluent/struct.Localization.html pub struct JumpyLocalizationPlugin; impl Plugin for JumpyLocalizationPlugin { @@ -19,6 +23,8 @@ impl Plugin for JumpyLocalizationPlugin { } /// Extension trait to reduce boilerplate when getting values from a [`Localization`]. +/// +/// [`Localization`]: https://docs.rs/bevy_fluent/latest/bevy_fluent/struct.Localization.html pub trait LocalizationExt<'a, T: Into>, U: Borrow>> { /// Request message content and get an empty string if it doesn't exist. fn get(&self, request: T) -> String; @@ -44,8 +50,9 @@ where } } -/// Watch for locale [`BundleAsset`] load events and add any new bundles to the [`Localization`] -/// resource. +/// Watch for locale load events and add any new bundles to the [`Localization`] resource. +/// +/// [`Localization`]: https://docs.rs/bevy_fluent/latest/bevy_fluent/struct.Localization.html fn load_locales( locale: Res, mut loading_bundles: Local>>, diff --git a/src/platform.rs b/src/platform.rs index 35021647ff..d2f2f4d723 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -1,4 +1,8 @@ -//! Systems and utilities related to specific platform support or platform abstractions +//! Platform abstractions. +//! +//! This module contains abstractions over platform-specific details. Currently this is just the +//! [`Storage`] abstraction, which allows us to persist key-value data in a way that works on both +//! native platforms and on web. use crate::prelude::*; @@ -12,6 +16,7 @@ use native as backend; #[cfg(target_arch = "wasm32")] use wasm as backend; +/// Platform plugin. pub struct JumpyPlatformPlugin; impl Plugin for JumpyPlatformPlugin { @@ -71,6 +76,7 @@ impl FromWorld for Storage { } } +/// An error that may occur while accessing [`Storage`]. #[derive(thiserror::Error, Debug)] pub enum StorageError { #[error("Storage has not been loaded yet")] @@ -261,17 +267,18 @@ impl SaveTask { } } +/// Message type sent over a channel to the storage task. enum StorageRequest { - Load { - result_sender: Sender, - }, + /// Load the storage and send it to the `result_sender`. + Load { result_sender: Sender }, + /// Save the storage and send confirmation to the `result_sender`. Save { data: StorageData, result_sender: Sender<()>, }, } -/// Native platform support +/// Native platform support. #[cfg(not(target_arch = "wasm32"))] mod native { use std::{ @@ -288,6 +295,7 @@ mod native { use super::StorageRequest; + /// Initialize storage backend. pub(super) fn init_storage() -> Sender { trace!("Initialize platform storage backend"); let io_task_pool = IoTaskPool::get(); diff --git a/src/prelude.rs b/src/prelude.rs index 04a53fdce8..8affcb0c78 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,3 +1,5 @@ +//! Internal prelude used to easily import common types. + pub use crate::{ assets::*, audio::*, bevy_states::*, camera::*, config::*, debug::*, input::*, loading::*, localization::*, metadata::*, platform::*, session::*, ui::*, utils::*, *, diff --git a/src/session.rs b/src/session.rs index 5bc4003f69..07be2ee8d3 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,9 +1,22 @@ +//! Session management for matches. +//! +//! The [`SessionManager`] is used to create, stop, snapshot, and restore game matches. A session +//! refers to an in-progress game match. +//! +//! Right now there are two kinds of sessions: local sessions and network sessions. These are +//! implemented by the [`LocalSessionRunner`] and +//! [`GgrsSessionRunner`][crate::networking::GgrsSessionRunner] types respectively. +//! +//! Both of them implmenent [`SessionRunner`] which is a trait used by the [`SessionManager`] to +//! advance the game simulation properly. + use bevy::utils::Instant; use downcast_rs::{impl_downcast, Downcast}; use jumpy_core::input::PlayerControl; use crate::{main_menu::MenuPage, prelude::*}; +/// Session plugin. pub struct JumpySessionPlugin; /// Stage label for the game session stages @@ -64,22 +77,37 @@ impl Plugin for JumpySessionPlugin { } } -/// A resource containing an in-progress game session. +/// A resource containing the in-progress game session. #[derive(Resource, Deref, DerefMut)] pub struct Session(pub Box); +/// Trait implemented by types that know how to advance the core game simulation. +/// +/// Things like fixed frame updates are expected to be handled by the session runner. +/// +/// The [`GgrsSessionRunner`][crate::networking::GgrsSessionRunner] is an example of how a custom +/// runner can be used for running a network game. pub trait SessionRunner: Sync + Send + Downcast { + /// Get mutable access to the [`CoreSession`]. fn core_session(&mut self) -> &mut CoreSession; + /// Get mutable access to the [`bones::World`] from in the [`CoreSession`]. fn world(&mut self) -> &mut bones::World { &mut self.core_session().world } + /// Restart the session. fn restart(&mut self); + /// Get the control input for the player with the given `player_idx`. fn get_player_input(&mut self, player_idx: usize) -> PlayerControl { self.core_session() .update_input(|inputs| inputs.players[player_idx].control.clone()) } + /// Set the player input for the player with the given `player_idx`. fn set_player_input(&mut self, player_idx: usize, control: PlayerControl); + /// Advance the game simmulation. fn advance(&mut self, bevy_world: &mut World) -> Result<(), SessionError>; + /// Return whether or not the simulation should run, given the current time. + /// + /// This is used to created fixed refresh rates. fn run_criteria(&mut self, time: &Time) -> ShouldRun; /// Returns the player index of the player if we are in a network game. /// @@ -96,6 +124,10 @@ pub enum SessionError { Disconnected, } +/// Implementation of [`SessionRunner`] for local games. +/// +/// This is almost as simple as a [`SessionRunner`] can get: it just advances the game simulation at +/// the fixed [`jumpy_core::FPS`]. pub struct LocalSessionRunner { pub core: CoreSession, pub accumulator: f64, @@ -198,15 +230,16 @@ impl<'w, 's> SessionManager<'w, 's> { self.menu_camera.for_each_mut(|mut x| x.is_active = false); } + /// Start a network game session. #[cfg(not(target_arch = "wasm32"))] pub fn start_network( &mut self, core_info: CoreSessionInfo, - lan_info: crate::networking::GgrsSessionRunnerInfo, + ggrs_info: crate::networking::GgrsSessionRunnerInfo, ) { let session = Session(Box::new(crate::networking::GgrsSessionRunner::new( CoreSession::new(core_info), - lan_info, + ggrs_info, ))); self.commands.insert_resource(session); self.menu_camera.for_each_mut(|mut x| x.is_active = false); diff --git a/src/ui.rs b/src/ui.rs index 47779bf5f4..6f8b3b6966 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,3 +1,5 @@ +//! User interface. + use bevy::{ ecs::system::SystemState, window::{PrimaryWindow, WindowMode}, diff --git a/src/utils.rs b/src/utils.rs index 2a82738fd9..305b710d2e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,5 @@ +//! Miscellaneous utilities. + use async_channel::*; /// Create a bi-directional channel with a given request and response type.