leafwing_input_manager/
systems.rs1use crate::prelude::updating::CentralInputStore;
4use bevy::ecs::query::QueryFilter;
5use bevy::log::debug;
6
7use crate::{
8 action_state::ActionState, clashing_inputs::ClashStrategy, input_map::InputMap, Actionlike,
9};
10
11use bevy::ecs::prelude::*;
12use bevy::prelude::Gamepad;
13use bevy::{
14 platform::time::Instant,
15 time::{Real, Time},
16};
17
18use crate::action_diff::{ActionDiffEvent, SummarizedActionState};
19
20pub fn swap_to_update<A: Actionlike>(
24 mut query: Query<&mut ActionState<A>>,
25 action_state: Option<ResMut<ActionState<A>>>,
26) {
27 if let Some(mut action_state) = action_state {
28 action_state.swap_to_update_state();
29 }
30
31 for mut action_state in query.iter_mut() {
32 action_state.swap_to_update_state();
33 }
34}
35
36pub fn swap_to_fixed_update<A: Actionlike>(
40 mut query: Query<&mut ActionState<A>>,
41 action_state: Option<ResMut<ActionState<A>>>,
42) {
43 if let Some(mut action_state) = action_state {
44 action_state.swap_to_fixed_update_state();
45 }
46
47 for mut action_state in query.iter_mut() {
48 action_state.swap_to_fixed_update_state();
49 }
50}
51
52pub fn tick_action_state<A: Actionlike>(
57 mut query: Query<&mut ActionState<A>>,
58 action_state: Option<ResMut<ActionState<A>>>,
59 time: Res<Time<Real>>,
60 mut stored_previous_instant: Local<Option<Instant>>,
61) {
62 let current_instant = time.last_update().unwrap_or_else(|| time.startup());
64 let previous_instant = stored_previous_instant.unwrap_or_else(|| time.startup());
65
66 if let Some(mut action_state) = action_state {
68 action_state.tick(current_instant, previous_instant);
69 }
70
71 for mut action_state in query.iter_mut() {
73 action_state.tick(current_instant, previous_instant);
76 }
77
78 *stored_previous_instant = time.last_update();
80}
81
82pub fn update_action_state<A: Actionlike>(
87 input_store: Res<CentralInputStore>,
88 clash_strategy: Res<ClashStrategy>,
89 mut gamepads: Query<Entity, With<Gamepad>>,
90 action_state: Option<ResMut<ActionState<A>>>,
91 input_map: Option<Res<InputMap<A>>>,
92 mut query: Query<(&mut ActionState<A>, &InputMap<A>)>,
93) {
94 let resources = input_map
95 .zip(action_state)
96 .map(|(input_map, action_state)| (Mut::from(action_state), input_map.into_inner()));
97
98 for (mut action_state, input_map) in query.iter_mut().chain(resources) {
99 action_state.update(input_map.process_actions(
100 Some(gamepads.reborrow()),
101 &input_store,
102 *clash_strategy,
103 ));
104 }
105}
106
107#[cfg(feature = "ui")]
108pub fn filter_captured_input(
110 mut mouse_buttons: ResMut<bevy::input::ButtonInput<bevy::input::mouse::MouseButton>>,
111 #[cfg(feature = "ui")] interactions: Query<&bevy::ui::Interaction>,
112) {
113 #[cfg(feature = "ui")]
115 if interactions
116 .iter()
117 .any(|&interaction| interaction != bevy::ui::Interaction::None)
118 {
119 mouse_buttons.clear();
120 }
121}
122
123pub fn generate_action_diffs<A: Actionlike>(
129 global_action_state: Option<Res<ActionState<A>>>,
130 action_state_query: Query<(Entity, &ActionState<A>)>,
131 previous_action_state: Local<SummarizedActionState<A>>,
132 action_diff_events: EventWriter<ActionDiffEvent<A>>,
133) {
134 generate_action_diffs_filtered(
135 global_action_state,
136 action_state_query,
137 previous_action_state,
138 action_diff_events,
139 )
140}
141
142pub fn generate_action_diffs_filtered<A: Actionlike, F: QueryFilter>(
150 global_action_state: Option<Res<ActionState<A>>>,
151 action_state_query: Query<(Entity, &ActionState<A>), F>,
152 mut previous_action_state: Local<SummarizedActionState<A>>,
153 mut action_diff_events: EventWriter<ActionDiffEvent<A>>,
154) {
155 let current_action_state =
156 SummarizedActionState::summarize_filtered(global_action_state, action_state_query);
157 current_action_state.send_diffs(&previous_action_state, &mut action_diff_events);
158 debug!("previous_action_state: {:?}", previous_action_state);
159 debug!("current_action_state: {:?}", current_action_state);
160 *previous_action_state = current_action_state;
161}
162
163pub fn release_on_input_map_removed<A: Actionlike>(
169 mut removed_components: RemovedComponents<InputMap<A>>,
170 input_map_resource: Option<ResMut<InputMap<A>>>,
171 action_state_resource: Option<ResMut<ActionState<A>>>,
172 mut input_map_resource_existed: Local<bool>,
173 mut action_state_query: Query<&mut ActionState<A>>,
174) {
175 let mut iter = action_state_query.iter_many_mut(removed_components.read());
176 while let Some(mut action_state) = iter.fetch_next() {
177 action_state.reset_all();
178 }
179
180 if input_map_resource.is_some() {
182 *input_map_resource_existed = true;
184 } else if *input_map_resource_existed {
185 if let Some(mut action_state) = action_state_resource {
189 action_state.reset_all();
190 }
191
192 *input_map_resource_existed = false;
194 }
195}
196
197pub fn clear_central_input_store(mut input_store: ResMut<CentralInputStore>) {
200 input_store.clear();
201}