diff --git a/benches/bitcode_packing/Cargo.toml b/benches/bitcode_packing/Cargo.toml index bfcb8e408..046f1b9e8 100644 --- a/benches/bitcode_packing/Cargo.toml +++ b/benches/bitcode_packing/Cargo.toml @@ -15,4 +15,4 @@ lz4_flex.workspace = true rand.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/benches/criterion/Cargo.toml b/benches/criterion/Cargo.toml index e5f346cdd..f97782bdf 100644 --- a/benches/criterion/Cargo.toml +++ b/benches/criterion/Cargo.toml @@ -42,4 +42,3 @@ harness = false name = "message" path = "src/message.rs" harness = false - diff --git a/examples/README.md b/examples/README.md index b983c83e2..a23e49b72 100644 --- a/examples/README.md +++ b/examples/README.md @@ -37,13 +37,15 @@ The top level `Cargo.toml` workspace defines the deps that examples can use and ## Running an example -- Run the server: `cargo run --features=server` -- Run client with id 1: `cargo run --features=client -- -c 1` -- Run client with id 2: `cargo run --features=client -- -c 2` (etc.) -- Run the client and server in two separate bevy Apps: `cargo run --features=server,client` -- Run the server with a gui: `cargo run --features=server,gui` -- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run --features=server,client -- -m=host-server` - +- Run the server with a gui: `cargo run server` +- Run client with id 1: `cargo run client -c 1` +- Run client with id 2: `cargo run client -c 2` +- Run the client and server in two separate bevy Apps: `cargo run` or `cargo run separate` +- Run the server without a gui: `cargo run --no-default-features --features=server` +- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run host-server` + +You can control the behaviour of the example by changing the list of features. By default, all features are enabled (client, server, gui). +For example you can run the server in headless mode (without gui) by running `cargo run --no-default-features --features=server`. You can modify the file `assets/settings.ron` to modify some networking settings. ### Testing in wasm with webtransport diff --git a/examples/auth/README.md b/examples/auth/README.md index d57c5efd9..687669fad 100644 --- a/examples/auth/README.md +++ b/examples/auth/README.md @@ -17,13 +17,15 @@ to the client. The client can then use the `ConnectToken` to start the `lightyea ## Running the example -- Run the server: `cargo run --features=server` -- Run client with id 1: `cargo run --features=client -- -c 1` -- Run client with id 2: `cargo run --features=client -- -c 2` (etc.) -- Run the client and server in two separate bevy Apps: `cargo run --features=server,client` -- Run the server with a gui: `cargo run --features=server,gui` -- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run --features=server,client -- -m=host-server` - +- Run the server with a gui: `cargo run server` +- Run client with id 1: `cargo run client -c 1` +- Run client with id 2: `cargo run client -c 2` +- Run the client and server in two separate bevy Apps: `cargo run` or `cargo run separate` +- Run the server without a gui: `cargo run --no-default-features --features=server` +- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run host-server` + +You can control the behaviour of the example by changing the list of features. By default, all features are enabled (client, server, gui). +For example you can run the server in headless mode (without gui) by running `cargo run --no-default-features --features=server`. You can modify the file `assets/settings.ron` to modify some networking settings. ### Testing in wasm with webtransport diff --git a/examples/auth/src/settings.rs b/examples/auth/src/settings.rs index b35e3b458..21aef5f87 100644 --- a/examples/auth/src/settings.rs +++ b/examples/auth/src/settings.rs @@ -35,6 +35,7 @@ pub(crate) fn get_settings() -> MySettings { }, }, ServerTransports::Udp { local_port: 5001 }, + #[cfg(feature = "websocket")] ServerTransports::WebSocket { local_port: 5002 }, #[cfg(feature = "steam")] ServerTransports::Steam { diff --git a/examples/avian_3d_character/Cargo.toml b/examples/avian_3d_character/Cargo.toml index e1624be44..8b8ff8497 100644 --- a/examples/avian_3d_character/Cargo.toml +++ b/examples/avian_3d_character/Cargo.toml @@ -6,7 +6,8 @@ edition = "2021" publish = false [features] -default = ["lightyear_examples_common/websocket"] +default = ["client", "server", "gui", "lightyear_examples_common/default"] +websocket = ["lightyear_examples_common/websocket"] client = ["lightyear_examples_common/client", "gui"] server = ["lightyear_examples_common/server"] gui = ["lightyear_examples_common/gui"] diff --git a/examples/avian_3d_character/README.md b/examples/avian_3d_character/README.md index 744f0e882..004e25eaa 100644 --- a/examples/avian_3d_character/README.md +++ b/examples/avian_3d_character/README.md @@ -16,13 +16,15 @@ This is an example of a server containing server-authoritative, physics-based, 3 ## Running the example -- Run the server: `cargo run --features=server` -- Run client with id 1: `cargo run --features=client -- -c 1` -- Run client with id 2: `cargo run --features=client -- -c 2` (etc.) -- Run the client and server in two separate bevy Apps: `cargo run --features=server,client` -- Run the server with a gui: `cargo run --features=server,gui` -- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run --features=server,client -- -m=host-server` - +- Run the server with a gui: `cargo run server` +- Run client with id 1: `cargo run client -c 1` +- Run client with id 2: `cargo run client -c 2` +- Run the client and server in two separate bevy Apps: `cargo run` or `cargo run separate` +- Run the server without a gui: `cargo run --no-default-features --features=server` +- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run host-server` + +You can control the behaviour of the example by changing the list of features. By default, all features are enabled (client, server, gui). +For example you can run the server in headless mode (without gui) by running `cargo run --no-default-features --features=server`. You can modify the file `assets/settings.ron` to modify some networking settings. ### Testing in wasm with webtransport diff --git a/examples/avian_3d_character/src/main.rs b/examples/avian_3d_character/src/main.rs index 8835541aa..417dfbb2f 100644 --- a/examples/avian_3d_character/src/main.rs +++ b/examples/avian_3d_character/src/main.rs @@ -4,7 +4,7 @@ use crate::shared::SharedPlugin; use bevy::prelude::*; use lightyear::prelude::client::PredictionConfig; -use lightyear_examples_common::app::{Apps, Cli}; +use lightyear_examples_common::app::{Apps, Cli, Mode}; use lightyear_examples_common::settings::Settings; use serde::{Deserialize, Serialize}; diff --git a/examples/avian_3d_character/src/settings.rs b/examples/avian_3d_character/src/settings.rs index 109494db1..144d595b8 100644 --- a/examples/avian_3d_character/src/settings.rs +++ b/examples/avian_3d_character/src/settings.rs @@ -44,6 +44,7 @@ pub(crate) fn get_settings() -> MySettings { }, }, ServerTransports::Udp { local_port: 5001 }, + #[cfg(feature = "websocket")] ServerTransports::WebSocket { local_port: 5002 }, #[cfg(feature = "steam")] ServerTransports::Steam { diff --git a/examples/avian_physics/Cargo.toml b/examples/avian_physics/Cargo.toml index a1d968f7b..524e65973 100644 --- a/examples/avian_physics/Cargo.toml +++ b/examples/avian_physics/Cargo.toml @@ -6,7 +6,8 @@ edition = "2021" publish = false [features] -default = ["lightyear_examples_common/websocket"] +default = ["client", "server", "gui", "lightyear_examples_common/default"] +websocket = ["lightyear_examples_common/websocket"] client = ["lightyear_examples_common/client", "gui"] server = ["lightyear_examples_common/server"] gui = ["lightyear_examples_common/gui"] diff --git a/examples/avian_physics/README.md b/examples/avian_physics/README.md index e1b032533..0ad371130 100644 --- a/examples/avian_physics/README.md +++ b/examples/avian_physics/README.md @@ -29,13 +29,15 @@ enabled.* ## Running the example -- Run the server: `cargo run --features=server` -- Run client with id 1: `cargo run --features=client -- -c 1` -- Run client with id 2: `cargo run --features=client -- -c 2` (etc.) -- Run the client and server in two separate bevy Apps: `cargo run --features=server,client` -- Run the server with a gui: `cargo run --features=server,gui` -- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run --features=server,client -- -m=host-server` - +- Run the server with a gui: `cargo run server` +- Run client with id 1: `cargo run client -c 1` +- Run client with id 2: `cargo run client -c 2` +- Run the client and server in two separate bevy Apps: `cargo run` or `cargo run separate` +- Run the server without a gui: `cargo run --no-default-features --features=server` +- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run host-server` + +You can control the behaviour of the example by changing the list of features. By default, all features are enabled (client, server, gui). +For example you can run the server in headless mode (without gui) by running `cargo run --no-default-features --features=server`. You can modify the file `assets/settings.ron` to modify some networking settings. ### Testing in wasm with webtransport diff --git a/examples/avian_physics/src/settings.rs b/examples/avian_physics/src/settings.rs index 10e6b1eb5..e3746215f 100644 --- a/examples/avian_physics/src/settings.rs +++ b/examples/avian_physics/src/settings.rs @@ -53,6 +53,7 @@ pub(crate) fn get_settings() -> MySettings { }, }, ServerTransports::Udp { local_port: 5001 }, + #[cfg(feature = "websocket")] ServerTransports::WebSocket { local_port: 5002 }, #[cfg(feature = "steam")] ServerTransports::Steam { diff --git a/examples/bullet_prespawn/Cargo.toml b/examples/bullet_prespawn/Cargo.toml index a3e7009b4..01136693d 100644 --- a/examples/bullet_prespawn/Cargo.toml +++ b/examples/bullet_prespawn/Cargo.toml @@ -6,7 +6,8 @@ edition = "2021" publish = false [features] -default = ["lightyear_examples_common/websocket"] +default = ["client", "server", "gui", "lightyear_examples_common/default"] +websocket = ["lightyear_examples_common/websocket"] client = ["lightyear_examples_common/client", "gui"] server = ["lightyear_examples_common/server"] gui = ["lightyear_examples_common/gui"] diff --git a/examples/bullet_prespawn/README.md b/examples/bullet_prespawn/README.md index 2e43eb9b7..54a5dcece 100644 --- a/examples/bullet_prespawn/README.md +++ b/examples/bullet_prespawn/README.md @@ -11,13 +11,15 @@ https://github.com/cBournhonesque/lightyear/assets/8112632/ee547c32-1f14-4bdc-9e ## Running the example -- Run the server: `cargo run --features=server` -- Run client with id 1: `cargo run --features=client -- -c 1` -- Run client with id 2: `cargo run --features=client -- -c 2` (etc.) -- Run the client and server in two separate bevy Apps: `cargo run --features=server,client` -- Run the server with a gui: `cargo run --features=server,gui` -- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run --features=server,client -- -m=host-server` - +- Run the server with a gui: `cargo run server` +- Run client with id 1: `cargo run client -c 1` +- Run client with id 2: `cargo run client -c 2` +- Run the client and server in two separate bevy Apps: `cargo run` or `cargo run separate` +- Run the server without a gui: `cargo run --no-default-features --features=server` +- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run host-server` + +You can control the behaviour of the example by changing the list of features. By default, all features are enabled (client, server, gui). +For example you can run the server in headless mode (without gui) by running `cargo run --no-default-features --features=server`. You can modify the file `assets/settings.ron` to modify some networking settings. ### Testing in wasm with webtransport diff --git a/examples/bullet_prespawn/src/settings.rs b/examples/bullet_prespawn/src/settings.rs index 2a350bb93..c067d1a79 100644 --- a/examples/bullet_prespawn/src/settings.rs +++ b/examples/bullet_prespawn/src/settings.rs @@ -44,6 +44,7 @@ pub(crate) fn get_settings() -> MySettings { }, }, ServerTransports::Udp { local_port: 5001 }, + #[cfg(feature = "websocket")] ServerTransports::WebSocket { local_port: 5002 }, #[cfg(feature = "steam")] ServerTransports::Steam { diff --git a/examples/client_replication/Cargo.toml b/examples/client_replication/Cargo.toml index 3e4670f2e..fcce64540 100644 --- a/examples/client_replication/Cargo.toml +++ b/examples/client_replication/Cargo.toml @@ -12,7 +12,8 @@ license = "MIT OR Apache-2.0" publish = false [features] -default = ["lightyear_examples_common/websocket"] +default = ["client", "server", "gui", "lightyear_examples_common/default"] +websocket = ["lightyear_examples_common/websocket"] client = ["lightyear_examples_common/client", "gui"] server = ["lightyear_examples_common/server"] gui = ["lightyear_examples_common/gui"] diff --git a/examples/client_replication/README.md b/examples/client_replication/README.md index 7a3877ba0..7a78441ab 100644 --- a/examples/client_replication/README.md +++ b/examples/client_replication/README.md @@ -22,13 +22,15 @@ https://github.com/cBournhonesque/lightyear/assets/8112632/718bfa44-80b5-4d83-a3 ## Running the example -- Run the server: `cargo run --features=server` -- Run client with id 1: `cargo run --features=client -- -c 1` -- Run client with id 2: `cargo run --features=client -- -c 2` (etc.) -- Run the client and server in two separate bevy Apps: `cargo run --features=server,client` -- Run the server with a gui: `cargo run --features=server,gui` -- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run --features=server,client -- -m=host-server` - +- Run the server with a gui: `cargo run server` +- Run client with id 1: `cargo run client -c 1` +- Run client with id 2: `cargo run client -c 2` +- Run the client and server in two separate bevy Apps: `cargo run` or `cargo run separate` +- Run the server without a gui: `cargo run --no-default-features --features=server` +- Run the client and server in "HostServer" mode, where the server is also a client (there is only one App): `cargo run host-server` + +You can control the behaviour of the example by changing the list of features. By default, all features are enabled (client, server, gui). +For example you can run the server in headless mode (without gui) by running `cargo run --no-default-features --features=server`. You can modify the file `assets/settings.ron` to modify some networking settings. ### Testing in wasm with webtransport diff --git a/examples/client_replication/src/settings.rs b/examples/client_replication/src/settings.rs index 5d393718a..48976a16b 100644 --- a/examples/client_replication/src/settings.rs +++ b/examples/client_replication/src/settings.rs @@ -25,6 +25,7 @@ pub(crate) fn get_settings() -> Settings { }, }, ServerTransports::Udp { local_port: 5001 }, + #[cfg(feature = "websocket")] ServerTransports::WebSocket { local_port: 5002 }, #[cfg(feature = "steam")] ServerTransports::Steam { diff --git a/examples/common/src/app.rs b/examples/common/src/app.rs index 05074d22d..77e74527d 100644 --- a/examples/common/src/app.rs +++ b/examples/common/src/app.rs @@ -14,7 +14,7 @@ use bevy::prelude::*; use bevy::diagnostic::{DiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::state::app::StatesPlugin; use bevy::DefaultPlugins; -use clap::{Parser, ValueEnum}; +use clap::{Parser, Subcommand, ValueEnum}; use lightyear::prelude::client::ClientConfig; use lightyear::prelude::*; use lightyear::prelude::{client, server}; @@ -26,32 +26,59 @@ use crate::settings::*; use crate::shared::{shared_config, REPLICATION_INTERVAL}; #[cfg(feature = "gui")] -use crate::renderer::ExampleRendererPlugin; +use crate::client_renderer::ExampleClientRendererPlugin; +#[cfg(feature = "gui")] +use crate::server_renderer::ExampleServerRendererPlugin; #[cfg(feature = "gui")] use bevy::window::PresentMode; /// CLI options to create an [`App`] -#[derive(Parser, PartialEq, Debug)] +#[derive(Parser, Debug)] +#[command(version, about)] pub struct Cli { - #[cfg(feature = "client")] - #[arg(short, long, default_value = None)] - client_id: Option, + #[command(subcommand)] + pub mode: Option, +} +#[derive(Subcommand, Debug)] +pub enum Mode { + #[cfg(feature = "client")] + /// Runs the app in client mode + Client { + #[arg(short, long, default_value = None)] + client_id: Option, + }, + #[cfg(feature = "server")] + /// Runs the app in server mode + Server, + #[cfg(all(feature = "client", feature = "server"))] + /// Creates two bevy apps: a client app and a server app. + /// Data gets passed between the two via channels. + Separate { + #[arg(short, long, default_value = None)] + client_id: Option, + }, #[cfg(all(feature = "client", feature = "server"))] - #[arg(short, long, default_value = "separate")] - pub mode: ServerMode, + /// Run the app in host-server mode. + /// The client and the server will run inside the same app. The peer acts both as a client and a server. + HostServer { + #[arg(short, long, default_value = None)] + client_id: Option, + }, } -#[derive(ValueEnum, Clone, Default, Debug, PartialEq)] -pub enum ServerMode { - #[default] - /// We will create two bevy Apps: a client app and a server app. - /// Data gets passed between the two via channels. - Separate, - /// Run the app in headless mode - /// We have the client and the server running inside the same app. - /// The server will also act as a client. (i.e. one client acts as the 'host') - HostServer, +impl Default for Mode { + fn default() -> Self { + cfg_if::cfg_if! { + if #[cfg(all(feature = "client", feature = "server"))] { + return Mode::HostServer { client_id: None }; + } else if #[cfg(feature = "server")] { + return Mode::Server; + } else { + return Mode::Client { client_id: None }; + } + } + } } /// App that is Send. @@ -79,7 +106,8 @@ pub fn cli() -> Cli { if #[cfg(target_family = "wasm")] { let client_id = rand::random::(); Cli { - client_id: Some(client_id) + client_id: Some(client_id), + mode: Mode::Client, } } else { Cli::parse() @@ -113,77 +141,91 @@ pub enum Apps { impl Apps { /// Build the apps with the given settings and CLI options. pub fn new(settings: Settings, cli: Cli, name: String) -> Self { - cfg_if::cfg_if! { - if #[cfg(all(feature = "client", feature = "server"))] { - match cli.mode { - ServerMode::HostServer => { - let client_net_config = client::NetConfig::Local { - id: cli.client_id.unwrap_or(settings.client.client_id), - }; - let (mut app, client_config, server_config) = - combined_app(settings, vec![], client_net_config); - app.add_plugins(ExampleRendererPlugin::new(name)); - Apps::HostServer { - app, - client_config, - server_config, - } - } - ServerMode::Separate => { - // we will communicate between the client and server apps via channels - let (from_server_send, from_server_recv) = crossbeam_channel::unbounded(); - let (to_server_send, to_server_recv) = crossbeam_channel::unbounded(); - let transport_config = client::ClientTransport::LocalChannel { - recv: from_server_recv, - send: to_server_send, - }; - - // create client app - let net_config = build_client_netcode_config( - cli.client_id.unwrap_or(settings.client.client_id), - // when communicating via channels, we need to use the address `LOCAL_SOCKET` for the server - LOCAL_SOCKET, - settings.client.conditioner.as_ref(), - &settings.shared, - transport_config, - ); - let (mut client_app, client_config) = client_app(settings.clone(), net_config); - client_app.add_plugins(ExampleRendererPlugin::new(name)); - - // create server app, which will be headless when we have client app in same process - let extra_transport_configs = vec![server::ServerTransport::Channels { - // even if we communicate via channels, we need to provide a socket address for the client - channels: vec![(LOCAL_SOCKET, to_server_recv, from_server_send)], - }]; - let (server_app, server_config) = server_app(settings, extra_transport_configs); - Apps::ClientAndServer { - client_app, - client_config, - server_app, - server_config, - } - } + match cli.mode { + #[cfg(all(feature = "client", feature = "server"))] + Some(Mode::HostServer { client_id }) => { + let client_net_config = client::NetConfig::Local { + id: client_id.unwrap_or(settings.client.client_id), + }; + let (mut app, client_config, server_config) = + combined_app(settings, vec![], client_net_config); + app.add_plugins(ExampleClientRendererPlugin::new(name)); + Apps::HostServer { + app, + client_config, + server_config, } - } else if #[cfg(feature = "server")] { - // server only - #[allow(unused_mut)] - let (mut app, config) = server_app(settings, vec![]); - #[cfg(feature = "gui")] - app.add_plugins(ExampleRendererPlugin::new(name)); - Apps::Server { app, config } - } else { - // client only + } + #[cfg(all(feature = "client", feature = "server"))] + Some(Mode::Separate { client_id }) => { + // we will communicate between the client and server apps via channels + let (from_server_send, from_server_recv) = crossbeam_channel::unbounded(); + let (to_server_send, to_server_recv) = crossbeam_channel::unbounded(); + let transport_config = client::ClientTransport::LocalChannel { + recv: from_server_recv, + send: to_server_send, + }; + + // create client app + let net_config = build_client_netcode_config( + client_id.unwrap_or(settings.client.client_id), + // when communicating via channels, we need to use the address `LOCAL_SOCKET` for the server + LOCAL_SOCKET, + settings.client.conditioner.as_ref(), + &settings.shared, + transport_config, + ); + let (mut client_app, client_config) = client_app(settings.clone(), net_config); + client_app.add_plugins(ExampleClientRendererPlugin::new(name)); + + // create server app, which will be headless when we have client app in same process + let extra_transport_configs = vec![server::ServerTransport::Channels { + // even if we communicate via channels, we need to provide a socket address for the client + channels: vec![(LOCAL_SOCKET, to_server_recv, from_server_send)], + }]; + let (server_app, server_config) = server_app(settings, extra_transport_configs); + Apps::ClientAndServer { + client_app, + client_config, + server_app, + server_config, + } + } + #[cfg(feature = "client")] + Some(Mode::Client { client_id }) => { let server_addr = SocketAddr::new( settings.client.server_addr.into(), settings.client.server_port, ); // use the cli-provided client id if it exists, otherwise use the settings client id - let client_id = cli.client_id.unwrap_or(settings.client.client_id); + let client_id = client_id.unwrap_or(settings.client.client_id); let net_config = get_client_net_config(&settings, client_id); let (mut app, config) = client_app(settings, net_config); - app.add_plugins(ExampleRendererPlugin::new(name)); + app.add_plugins(ExampleClientRendererPlugin::new(name)); Apps::Client { app, config } } + #[cfg(feature = "server")] + Some(Mode::Server) => { + #[allow(unused_mut)] + let (mut app, config) = server_app(settings, vec![]); + // we keep gui a parameter so that we can easily disable server gui even with all default features + // enabled + #[cfg(feature = "gui")] + app.add_plugins(ExampleServerRendererPlugin::new(name)); + Apps::Server { app, config } + } + None => { + cfg_if::cfg_if! { + if #[cfg(all(feature = "client", feature = "server"))] { + let mode = Mode::HostServer { client_id: None }; + } else if #[cfg(feature = "server")] { + let mode = Mode::Server; + } else { + let mode = Mode::Client { client_id: None }; + } + }; + Apps::new(settings, Cli { mode: Some(mode) }, name) + } } } @@ -349,24 +391,6 @@ impl Apps { self } - /// Add the client, server, and shared user-provided plugins to the app - pub fn add_user_plugins( - &mut self, - client_plugin: impl Plugin, - server_plugin: impl Plugin, - shared_plugin: impl Plugin + Clone, - renderer_plugin: impl Plugin, - ) -> &mut Self { - self.add_user_shared_plugin(shared_plugin); - #[cfg(feature = "client")] - self.add_user_client_plugin(client_plugin); - #[cfg(feature = "server")] - self.add_user_server_plugin(server_plugin); - #[cfg(feature = "gui")] - self.add_user_renderer_plugin(renderer_plugin); - self - } - /// Apply a function to update the [`ClientConfig`] pub fn update_lightyear_client_config( &mut self, @@ -494,7 +518,7 @@ fn client_app(settings: Settings, net_config: client::NetConfig) -> (App, Client let app = new_gui_app(settings.client.inspector); let client_config = ClientConfig { - shared: shared_config(Mode::Separate), + shared: shared_config(lightyear::shared::config::Mode::Separate), net: net_config, replication: ReplicationConfig { send_interval: REPLICATION_INTERVAL, @@ -511,20 +535,11 @@ fn server_app( settings: Settings, extra_transport_configs: Vec, ) -> (App, ServerConfig) { - use cfg_if::cfg_if; - + #[cfg(feature = "gui")] + let app = new_gui_app(settings.server.inspector); + #[cfg(not(feature = "gui"))] + let app = new_headless_app(); info!("server_app. gui={}", cfg!(feature = "gui")); - cfg_if::cfg_if! { - // If there's a client app, the server needs to be headless. - // Winit doesn't support two event loops in the same thread. - if #[cfg(feature = "client")] { - let app = new_headless_app(); - } else if #[cfg(feature = "gui")] { - let app = new_gui_app(settings.server.inspector); - } else { - let app = new_headless_app(); - } - } // configure the network configuration let mut net_configs = get_server_net_configs(&settings); let extra_net_configs = extra_transport_configs.into_iter().map(|c| { @@ -532,7 +547,7 @@ fn server_app( }); net_configs.extend(extra_net_configs); let server_config = ServerConfig { - shared: shared_config(Mode::Separate), + shared: shared_config(lightyear::shared::config::Mode::Separate), net: net_configs, replication: ReplicationConfig { send_interval: REPLICATION_INTERVAL, @@ -558,7 +573,7 @@ fn combined_app( }); net_configs.extend(extra_net_configs); let server_config = ServerConfig { - shared: shared_config(Mode::HostServer), + shared: shared_config(lightyear::shared::config::Mode::HostServer), net: net_configs, replication: ReplicationConfig { send_interval: REPLICATION_INTERVAL, @@ -569,7 +584,7 @@ fn combined_app( // client config let client_config = ClientConfig { - shared: shared_config(Mode::HostServer), + shared: shared_config(lightyear::shared::config::Mode::HostServer), net: client_net_config, ..default() }; diff --git a/examples/common/src/bevygap_shared.rs b/examples/common/src/bevygap_shared.rs index 349c0f77f..e5ec3f505 100644 --- a/examples/common/src/bevygap_shared.rs +++ b/examples/common/src/bevygap_shared.rs @@ -60,7 +60,7 @@ fn on_server_metadata_changed(metadata: ResMut, mut commands: Co return; } let msg = format!("{} in {}", metadata.fqdn, metadata.location); - commands.trigger(crate::renderer::UpdateStatusMessage(msg)); + commands.trigger(crate::client_renderer::UpdateStatusMessage(msg)); } #[cfg(feature = "bevygap_server")] @@ -91,5 +91,5 @@ fn on_bevygap_state_change( BevygapClientState::Finished => "Finished connection setup.".to_string(), BevygapClientState::Error(code, msg) => format!("ERR {code}: {msg}"), }; - commands.trigger(crate::renderer::UpdateStatusMessage(msg)); + commands.trigger(crate::client_renderer::UpdateStatusMessage(msg)); } diff --git a/examples/common/src/renderer.rs b/examples/common/src/client_renderer.rs similarity index 75% rename from examples/common/src/renderer.rs rename to examples/common/src/client_renderer.rs index e4c892168..e068c6419 100644 --- a/examples/common/src/renderer.rs +++ b/examples/common/src/client_renderer.rs @@ -1,18 +1,16 @@ -#[cfg(feature = "client")] use bevy::picking::prelude::{Click, Pointer}; use bevy::prelude::*; #[cfg(feature = "bevygap_client")] use bevygap_client_plugin::prelude::*; use lightyear::prelude::client::*; use lightyear::prelude::MainSet; -// TODO split into server/client renderer plugins? -pub struct ExampleRendererPlugin { +pub struct ExampleClientRendererPlugin { /// The name of the example, which must also match the edgegap application name. pub name: String, } -impl ExampleRendererPlugin { +impl ExampleClientRendererPlugin { pub fn new(name: String) -> Self { Self { name } } @@ -21,43 +19,35 @@ impl ExampleRendererPlugin { #[derive(Resource)] struct GameName(String); -impl Plugin for ExampleRendererPlugin { +impl Plugin for ExampleClientRendererPlugin { fn build(&self, app: &mut App) { app.insert_resource(GameName(self.name.clone())); app.insert_resource(ClearColor::default()); // TODO common shortcuts for enabling the egui world inspector etc. // TODO handle bevygap ui things. - // TODO for clients, provide a "connect" button? - #[cfg(feature = "gui")] app.add_systems(Startup, set_window_title); - #[cfg(feature = "client")] + #[cfg(feature = "bevygap_client")] { - #[cfg(feature = "bevygap_client")] - { - let bevygap_client_config = BevygapClientConfig { - matchmaker_url: crate::settings::get_matchmaker_url(), - game_name: self.name.clone(), - game_version: "1".to_string(), - ..default() - }; - info!("{bevygap_client_config:?}"); - app.insert_resource(bevygap_client_config); - } - - spawn_connect_button(app); - app.add_systems( - PreUpdate, - (handle_connection, handle_disconnection).after(MainSet::Receive), - ); - app.add_systems(OnEnter(NetworkingState::Disconnected), on_disconnect); - - app.add_systems(Update, update_button_text); - app.add_observer(on_update_status_message); + let bevygap_client_config = BevygapClientConfig { + matchmaker_url: crate::settings::get_matchmaker_url(), + game_name: self.name.clone(), + game_version: "1".to_string(), + ..default() + }; + info!("{bevygap_client_config:?}"); + app.insert_resource(bevygap_client_config); } - #[cfg(all(feature = "server", not(feature = "client")))] - app.add_systems(Startup, spawn_server_text); + spawn_connect_button(app); + app.add_systems( + PreUpdate, + (handle_connection, handle_disconnection).after(MainSet::Receive), + ); + app.add_systems(OnEnter(NetworkingState::Disconnected), on_disconnect); + + app.add_systems(Update, update_button_text); + app.add_observer(on_update_status_message); } } @@ -66,25 +56,9 @@ fn set_window_title(mut window: Query<&mut Window>, game_name: Res) { window.title = format!("Lightyear Example: {}", game_name.0); } -/// Spawns a text element that displays "Server" -#[cfg(all(feature = "server", not(feature = "client")))] -fn spawn_server_text(mut commands: Commands) { - commands.spawn(( - Text("Server".to_string()), - TextFont::from_font_size(30.0), - TextColor(Color::WHITE.with_alpha(0.5)), - Node { - align_self: AlignSelf::End, - ..default() - }, - )); -} - -#[cfg(feature = "client")] #[derive(Event, Debug)] pub struct UpdateStatusMessage(pub String); -#[cfg(feature = "client")] fn on_update_status_message( trigger: Trigger, mut q: Query<&mut Text, With>, @@ -94,11 +68,9 @@ fn on_update_status_message( } } -#[cfg(feature = "client")] #[derive(Component)] struct StatusMessageMarker; -#[cfg(feature = "client")] /// Create a button that allow you to connect/disconnect to a server pub(crate) fn spawn_connect_button(app: &mut App) { app.world_mut() @@ -161,7 +133,6 @@ pub(crate) fn spawn_connect_button(app: &mut App) { }); } -#[cfg(feature = "client")] pub(crate) fn update_button_text( state: Res>, mut text_query: Query<&mut Text, With