use crate::{
PostPhysicsAppSystems, screens::Screen, third_party::bevy_yarnspinner::is_dialogue_running,
};
use bevy::{input::common_conditions::input_just_pressed, prelude::*, window::CursorGrabMode};
#[cfg(feature = "hot_patch")]
use bevy_simple_subsecond_system::hot;
use std::any::Any;
use super::CrosshairState;
pub(super) fn plugin(app: &mut App) {
app.init_resource::<IsCursorForceUnlocked>();
app.add_systems(
Update,
(
capture_cursor_delayed.run_if(resource_exists::<CaptureCursorDelayed>),
capture_cursor.run_if(
input_just_pressed(MouseButton::Left)
.and(not(is_dialogue_running))
.and(not(is_cursor_force_unlocked))
.and(in_state(Screen::Gameplay).or(in_state(Screen::Loading))),
),
release_cursor.run_if(is_cursor_force_unlocked),
on_cursor_lock_changed,
)
.chain()
.in_set(PostPhysicsAppSystems::ChangeUi),
);
app.add_systems(OnExit(Screen::Gameplay), release_cursor);
}
#[cfg_attr(feature = "hot_patch", hot)]
fn capture_cursor(mut window: Single<&mut Window>, mut commands: Commands) {
window.cursor_options.grab_mode = CursorGrabMode::Confined;
commands.insert_resource(CaptureCursorDelayed);
}
#[cfg_attr(feature = "hot_patch", hot)]
fn capture_cursor_delayed(mut window: Single<&mut Window>, mut commands: Commands) {
window.cursor_options.grab_mode = CursorGrabMode::Locked;
commands.remove_resource::<CaptureCursorDelayed>();
}
#[derive(Resource)]
struct CaptureCursorDelayed;
#[cfg_attr(feature = "hot_patch", hot)]
fn release_cursor(mut window: Single<&mut Window>) {
window.cursor_options.grab_mode = CursorGrabMode::None;
}
#[cfg_attr(feature = "hot_patch", hot)]
fn on_cursor_lock_changed(
#[cfg_attr(not(feature = "native"), allow(unused_mut))] mut window: Single<
&mut Window,
Changed<Window>,
>,
crosshair: Option<Single<&mut CrosshairState>>,
mut last_grab_mode: Local<CursorGrabMode>,
) {
let grab_mode = window.cursor_options.grab_mode;
if grab_mode == *last_grab_mode {
return;
}
*last_grab_mode = grab_mode;
if grab_mode == CursorGrabMode::None {
if let Some(mut crosshair) = crosshair {
crosshair.wants_invisible.insert(release_cursor.type_id());
}
#[cfg(feature = "native")]
{
window.cursor_options.visible = true;
}
} else {
if let Some(mut crosshair) = crosshair {
crosshair.wants_invisible.remove(&release_cursor.type_id());
}
#[cfg(feature = "native")]
{
window.cursor_options.visible = false;
}
}
}
#[derive(Resource, Debug, Default, Reflect)]
#[reflect(Resource)]
pub(crate) struct IsCursorForceUnlocked(pub(crate) bool);
fn is_cursor_force_unlocked(val: Res<IsCursorForceUnlocked>) -> bool {
val.0
}