diff --git a/src/dev.rs b/src/dev.rs index 62f82d5..97a7d77 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -7,7 +7,7 @@ use bevy::{ prelude::*, }; -use crate::AppState; +use crate::game::state::AppState; pub(super) fn dev_tools(app: &mut App) { app.add_plugins(FpsOverlayPlugin::default()); diff --git a/src/game/mod.rs b/src/game/mod.rs index cd239ce..30eff06 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,5 +1,13 @@ mod objects; +mod plugin; mod rng; -pub mod runtime; -pub mod seed; -pub mod setup; +mod runtime; +mod seed; +mod setup; +pub mod state; + +#[allow(unused_imports)] +pub mod prelude { + pub use super::plugin::{DataSource, GamePlugin}; + pub use super::seed::Seed; +} diff --git a/src/game/objects.rs b/src/game/objects.rs index 1ede2d5..95de98f 100644 --- a/src/game/objects.rs +++ b/src/game/objects.rs @@ -1,7 +1,7 @@ use avian2d::prelude::*; use bevy::prelude::*; -use crate::AppState; +use super::state::AppState; /// Basic implementation of a physics object #[derive(Component, Default)] diff --git a/src/game/plugin.rs b/src/game/plugin.rs new file mode 100644 index 0000000..ec35bef --- /dev/null +++ b/src/game/plugin.rs @@ -0,0 +1,91 @@ +use std::net::SocketAddr; + +use avian2d::PhysicsPlugins; +use bevy::{input::common_conditions::input_pressed, prelude::*}; + +use crate::net::NetIOPlugin; + +use super::{ + runtime::{move_camera, move_player, quit, zoom_camera}, + seed::Seed, + setup::{check_for_seed, setup_balls, setup_from_seed, setup_player, setup_ui, setup_walls}, + state::AppState, +}; + +#[derive(Debug, Clone, Copy)] +pub enum DataSource { + Address(SocketAddr), + Seed(Seed), + None, +} + +impl DataSource { + pub fn try_from_options(address: Option, seed: Option) -> Option { + match (address, seed) { + (None, None) => Some(DataSource::None), + (None, Some(seed)) => Some(DataSource::Seed(seed)), + (Some(address), None) => Some(DataSource::Address(address)), + (Some(_), Some(_)) => None, + } + } + + fn try_to_address(&self) -> Option { + match self { + DataSource::Address(address) => Some(*address), + _ => None, + } + } +} + +pub struct GamePlugin { + source: DataSource, + port: u16, +} + +impl GamePlugin { + pub fn new(source: DataSource, port: u16) -> Self { + Self { source, port } + } +} + +impl Plugin for GamePlugin { + fn build(&self, app: &mut App) { + app.add_plugins(( + NetIOPlugin::new(self.port, self.source.try_to_address()), + PhysicsPlugins::default().with_length_unit(50.0), + )) + .init_state::() + .add_systems(Startup, setup_ui) + .add_systems( + OnEnter(AppState::InGame), + ( + setup_from_seed, + (setup_player, setup_balls, setup_walls).after(setup_from_seed), + ), + ) + .add_systems( + FixedUpdate, + check_for_seed.run_if(in_state(AppState::Loading)), + ) + .add_systems( + Update, + ( + ((move_player, move_camera).chain(), zoom_camera) + .run_if(in_state(AppState::InGame)), + quit.run_if(input_pressed(KeyCode::KeyQ)), + ), + ); + + match self.source { + DataSource::Address(peer) => { + info!("Will retrieve seed from peer => {peer}"); + } + DataSource::Seed(seed) => { + app.insert_resource(seed); + } + DataSource::None => { + app.insert_resource(Seed::random()); + } + }; + } +} diff --git a/src/game/seed.rs b/src/game/seed.rs index 2b1ff6b..12d6a07 100644 --- a/src/game/seed.rs +++ b/src/game/seed.rs @@ -7,7 +7,7 @@ use bevy::prelude::*; use rand::random; /// Value with which to initialize the PRNG -#[derive(Resource, Clone, Copy)] +#[derive(Resource, Debug, Clone, Copy)] pub struct Seed(u64); impl Seed { diff --git a/src/game/setup.rs b/src/game/setup.rs index 14c2d44..252e0d2 100644 --- a/src/game/setup.rs +++ b/src/game/setup.rs @@ -11,7 +11,7 @@ use bevy::{ use rand::{Rng as _, SeedableRng}; use wyrand::WyRand; -use crate::AppState; +use super::state::AppState; use super::{ objects::{Ball, Player, Radius, Wall}, diff --git a/src/game/state.rs b/src/game/state.rs new file mode 100644 index 0000000..fe219de --- /dev/null +++ b/src/game/state.rs @@ -0,0 +1,9 @@ +use bevy::prelude::*; + +#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)] +#[states(scoped_entities)] +pub enum AppState { + #[default] + Loading, + InGame, +} diff --git a/src/lib.rs b/src/lib.rs index b6783f6..3fad59d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,16 @@ use std::net::SocketAddr; use avian2d::{math::Vector, prelude::*}; -use bevy::{input::common_conditions::input_pressed, prelude::*}; +use bevy::prelude::*; use clap::{Args, Parser}; #[cfg(feature = "dev")] mod dev; - mod game; -use game::{ - runtime::{move_camera, move_player, quit, zoom_camera}, - seed::Seed, - setup::{check_for_seed, setup_balls, setup_from_seed, setup_player, setup_ui, setup_walls}, -}; - mod net; +use game::prelude::*; + /// The initial configuration passed to the game's setup functions. /// Also functions as a Bevy plugin to pass the configuration into the app. #[derive(Parser)] @@ -41,60 +36,24 @@ struct Source { connect: Option, } -#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)] -#[states(scoped_entities)] -enum AppState { - #[default] - Loading, - InGame, -} - impl Plugin for AppSettings { fn build(&self, app: &mut App) { - app.insert_resource(Gravity(Vector::ZERO)) - .add_plugins(( - DefaultPlugins.set(WindowPlugin { - primary_window: Window { - title: "Distributed physics test".into(), - fit_canvas_to_parent: true, - ..default() - } - .into(), + app.insert_resource(Gravity(Vector::ZERO)).add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Window { + title: "Distributed physics test".into(), + fit_canvas_to_parent: true, ..default() - }), - PhysicsPlugins::default().with_length_unit(50.0), - #[cfg(feature = "dev")] - dev::dev_tools, - net::NetIOPlugin::new(self.port, self.source.connect), - )) - .init_state::() - .add_systems(Startup, setup_ui) - .add_systems( - OnEnter(AppState::InGame), - ( - setup_from_seed, - (setup_player, setup_balls, setup_walls).after(setup_from_seed), - ), - ) - .add_systems( - FixedUpdate, - check_for_seed.run_if(in_state(AppState::Loading)), - ) - .add_systems( - Update, - ( - ((move_player, move_camera).chain(), zoom_camera) - .run_if(in_state(AppState::InGame)), - quit.run_if(input_pressed(KeyCode::KeyQ)), - ), - ); - - if let Some(ref seed) = self.source.seed { - app.insert_resource(*seed); - } else if let Some(ref peer) = self.source.connect { - info!("Will retrieve seed from peer => {peer}"); - } else { - app.insert_resource(Seed::random()); - } + } + .into(), + ..default() + }), + #[cfg(feature = "dev")] + dev::dev_tools, + GamePlugin::new( + DataSource::try_from_options(self.source.connect, self.source.seed).unwrap(), + self.port, + ), + )); } } diff --git a/src/net/mod.rs b/src/net/mod.rs index 286d87d..4529f49 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -1,6 +1,5 @@ mod plugin; +pub use plugin::NetIOPlugin; mod socket; mod thread; mod types; - -pub use plugin::NetIOPlugin; diff --git a/src/net/plugin.rs b/src/net/plugin.rs index 57aa8fa..183207e 100644 --- a/src/net/plugin.rs +++ b/src/net/plugin.rs @@ -2,7 +2,7 @@ use std::net::SocketAddr; use bevy::prelude::*; -use crate::game::seed::Seed; +use crate::game::prelude::Seed; use super::{ socket::bind_socket,