parent
138a218fc5
commit
df8cc62ece
16 changed files with 234 additions and 186 deletions
@ -0,0 +1,13 @@ |
|||||||
|
//! Common module to handle asset loading and adding visual components
|
||||||
|
//! (such as [`Mesh`]) to entities when they are spawned from the server.
|
||||||
|
//!
|
||||||
|
//! This doesn't mean this is the only place assets are loaded.
|
||||||
|
//! For example UI related assets may be loaded in `ui` plugins.
|
||||||
|
|
||||||
|
use bevy::prelude::*; |
||||||
|
|
||||||
|
mod block; |
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) { |
||||||
|
app.add_plugins(block::plugin); |
||||||
|
} |
||||||
@ -1,11 +1,14 @@ |
|||||||
|
//! Handles client-side input using [`lightyear`], updating the
|
||||||
|
//! [`ActionState`] of the affected entities (such as the `Player`).
|
||||||
|
|
||||||
use bevy::prelude::*; |
use bevy::prelude::*; |
||||||
|
use common::prelude::*; |
||||||
use lightyear::prelude::input::client::*; |
use lightyear::prelude::input::client::*; |
||||||
use lightyear::prelude::input::native::*; |
use lightyear::prelude::input::native::*; |
||||||
|
|
||||||
use bevy::window::{CursorGrabMode, CursorOptions}; |
use bevy::window::{CursorGrabMode, CursorOptions}; |
||||||
|
|
||||||
use crate::camera::CameraFreeLook; |
use crate::camera::CameraFreeLook; |
||||||
use common::network::Inputs; |
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) { |
pub fn plugin(app: &mut App) { |
||||||
app.add_systems( |
app.add_systems( |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
use bevy::prelude::*; |
||||||
|
|
||||||
|
use bevy::window::{CursorGrabMode, CursorOptions}; |
||||||
|
|
||||||
|
use crate::Screen; |
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) { |
||||||
|
app.add_systems( |
||||||
|
PreUpdate, |
||||||
|
update_cursor_grab.run_if(in_state(Screen::Gameplay)), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
fn update_cursor_grab( |
||||||
|
mut mouse_button_input: ResMut<ButtonInput<MouseButton>>, |
||||||
|
key_input: Res<ButtonInput<KeyCode>>, |
||||||
|
window: Single<(&mut Window, &mut CursorOptions)>, |
||||||
|
) { |
||||||
|
let (mut window, mut cursor) = window.into_inner(); |
||||||
|
|
||||||
|
let is_grabbed = cursor.grab_mode != CursorGrabMode::None; |
||||||
|
let request_grab = mouse_button_input.any_just_pressed([MouseButton::Left, MouseButton::Right]); |
||||||
|
let request_ungrab = !window.focused || key_input.just_pressed(KeyCode::Escape); |
||||||
|
|
||||||
|
if !is_grabbed && request_grab && !request_ungrab { |
||||||
|
cursor.grab_mode = CursorGrabMode::Locked; |
||||||
|
|
||||||
|
// To prevent other systems (such as `place_break_blocks`)
|
||||||
|
// from seeing the mouse button inputs, clear the state here.
|
||||||
|
mouse_button_input.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
if is_grabbed && request_ungrab && !request_grab { |
||||||
|
cursor.grab_mode = CursorGrabMode::None; |
||||||
|
} |
||||||
|
|
||||||
|
if is_grabbed && !request_ungrab { |
||||||
|
// Set the cursor position to the center of the window, so that when
|
||||||
|
// it is ungrabbed, it will reappear there. Because `is_grabbed` is
|
||||||
|
// not updated on grab, this block is delayed by one frame.
|
||||||
|
//
|
||||||
|
// On Wayland, since the cursor is locked into place, this only needs
|
||||||
|
// to be done once. Unfortunately, for some reason this doesn't work
|
||||||
|
// in the same frame as setting `grab_mode`, and would log an error.
|
||||||
|
//
|
||||||
|
// On X11, the cursor can't be locked into place, only confined to the
|
||||||
|
// window bounds, so we repeatedly move the cursor back to the center
|
||||||
|
// while it's grabbed.
|
||||||
|
//
|
||||||
|
// On the web, the cursor can be locked, but setting its position is
|
||||||
|
// not supported at all, so this would instead log a bunch of errors.
|
||||||
|
let center = window.resolution.size() / 2.; |
||||||
|
#[cfg(not(target_family = "wasm"))] // skip on web
|
||||||
|
window.set_cursor_position(Some(center)); |
||||||
|
} |
||||||
|
|
||||||
|
// Keep cursor visbility in sync with `grab_mode`.
|
||||||
|
cursor.visible = cursor.grab_mode == CursorGrabMode::None; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn is_cursor_grabbed(cursor: Single<&CursorOptions>) -> bool { |
||||||
|
cursor.grab_mode != CursorGrabMode::None |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
use bevy::prelude::*; |
||||||
|
|
||||||
|
mod client_inputs; |
||||||
|
mod cursor_grab; |
||||||
|
|
||||||
|
pub use cursor_grab::is_cursor_grabbed; |
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) { |
||||||
|
app.add_plugins((client_inputs::plugin, cursor_grab::plugin)); |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
use bevy::prelude::*; |
||||||
|
use common::prelude::*; |
||||||
|
|
||||||
|
use bevy::window::{CursorGrabMode, CursorOptions}; |
||||||
|
|
||||||
|
use crate::Screen; |
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) { |
||||||
|
app.load_resource::<CrosshairAssets>(); |
||||||
|
app.add_systems(OnEnter(Screen::Gameplay), setup_crosshair); |
||||||
|
app.add_systems(Update, update_crosshair_visibility); |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Resource, Asset, Reflect, Clone)] |
||||||
|
#[reflect(Resource)] |
||||||
|
pub struct CrosshairAssets { |
||||||
|
#[dependency] |
||||||
|
image: Handle<Image>, |
||||||
|
} |
||||||
|
|
||||||
|
impl FromWorld for CrosshairAssets { |
||||||
|
fn from_world(world: &mut World) -> Self { |
||||||
|
let assets = world.resource::<AssetServer>(); |
||||||
|
Self { |
||||||
|
image: assets.load("crosshair.png"), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Component)] |
||||||
|
pub struct Crosshair; |
||||||
|
|
||||||
|
fn setup_crosshair(mut commands: Commands, assets: Res<CrosshairAssets>) { |
||||||
|
commands.spawn(( |
||||||
|
Node { |
||||||
|
width: percent(100), |
||||||
|
height: percent(100), |
||||||
|
align_items: AlignItems::Center, |
||||||
|
justify_content: JustifyContent::Center, |
||||||
|
..default() |
||||||
|
}, |
||||||
|
children![( |
||||||
|
Crosshair, |
||||||
|
Node { |
||||||
|
width: px(64), |
||||||
|
height: px(64), |
||||||
|
..default() |
||||||
|
}, |
||||||
|
ImageNode { |
||||||
|
image: assets.image.clone(), |
||||||
|
..default() |
||||||
|
}, |
||||||
|
// Hidden by default, because cursor shouldn't be grabbed at startup either.
|
||||||
|
Visibility::Hidden, |
||||||
|
)], |
||||||
|
)); |
||||||
|
} |
||||||
|
|
||||||
|
fn update_crosshair_visibility( |
||||||
|
cursor: Single<&CursorOptions, Changed<CursorOptions>>, |
||||||
|
crosshair: Single<&mut Visibility, With<Crosshair>>, |
||||||
|
) { |
||||||
|
let is_grabbed = cursor.grab_mode != CursorGrabMode::None; |
||||||
|
let mut crosshair_visibility = crosshair.into_inner(); |
||||||
|
*crosshair_visibility = (!is_grabbed || cursor.visible) |
||||||
|
.then_some(Visibility::Hidden) |
||||||
|
.unwrap_or_default(); |
||||||
|
} |
||||||
@ -0,0 +1,8 @@ |
|||||||
|
use bevy::prelude::*; |
||||||
|
|
||||||
|
mod crosshair; |
||||||
|
mod loading_screen; |
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) { |
||||||
|
app.add_plugins((crosshair::plugin, loading_screen::plugin)); |
||||||
|
} |
||||||
@ -1,12 +1,19 @@ |
|||||||
mod client; |
use bevy::prelude::*; |
||||||
mod protocol; |
|
||||||
mod server; |
pub(crate) mod protocol; |
||||||
|
|
||||||
|
mod client; |
||||||
mod client_webtransport; |
mod client_webtransport; |
||||||
|
mod server; |
||||||
mod server_webtransport; |
mod server_webtransport; |
||||||
|
|
||||||
pub use client::*; |
pub use crate::network::client_webtransport::ConnectWebTransportCommand; |
||||||
pub use protocol::*; |
pub use crate::network::server::StartLocalServerCommand; |
||||||
pub use server::*; |
#[cfg(not(target_family = "wasm"))] |
||||||
|
pub use crate::network::server_webtransport::StartWebTransportServerCommand; |
||||||
|
|
||||||
pub const DEFAULT_PORT: u16 = 13580; |
pub const DEFAULT_PORT: u16 = 13580; |
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) { |
||||||
|
app.add_plugins((protocol::plugin, client::plugin, server::plugin)); |
||||||
|
} |
||||||
|
|||||||
Loading…
Reference in new issue