* switch to events for instantaneous inputs * input simplification + improvements * fix trail crash * fix clippy warnings * qualify `Trail` in fn signature
129 lines
3.6 KiB
Rust
129 lines
3.6 KiB
Rust
use bevy::prelude::*;
|
|
use bevy_replicon::prelude::{ClientState, FromClient, SendMode, ServerTriggerExt, ToClients};
|
|
use shared::{
|
|
GameState,
|
|
backpack::{
|
|
BackbackSwapEvent, Backpack, UiHeadState,
|
|
backpack_ui::{BackpackUiState, HEAD_SLOTS},
|
|
},
|
|
control::{
|
|
BackpackLeftPressed, BackpackRightPressed, BackpackSwapPressed, BackpackTogglePressed,
|
|
},
|
|
protocol::{ClientToController, PlaySound},
|
|
};
|
|
|
|
pub fn plugin(app: &mut App) {
|
|
app.add_systems(
|
|
FixedUpdate,
|
|
sync_on_change.run_if(in_state(GameState::Playing)),
|
|
);
|
|
app.add_systems(
|
|
FixedUpdate,
|
|
swap_head_inputs.run_if(in_state(ClientState::Disconnected)),
|
|
);
|
|
}
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn swap_head_inputs(
|
|
backpacks: Query<Ref<Backpack>>,
|
|
clients: ClientToController,
|
|
mut backpack_toggles: MessageReader<FromClient<BackpackTogglePressed>>,
|
|
mut backpack_lefts: MessageReader<FromClient<BackpackLeftPressed>>,
|
|
mut backpack_rights: MessageReader<FromClient<BackpackRightPressed>>,
|
|
mut backpack_swaps: MessageReader<FromClient<BackpackSwapPressed>>,
|
|
mut commands: Commands,
|
|
mut state: Single<&mut BackpackUiState>,
|
|
time: Res<Time>,
|
|
) {
|
|
for _ in backpack_toggles.read() {
|
|
if state.count == 0 {
|
|
return;
|
|
}
|
|
|
|
state.open = !state.open;
|
|
commands.server_trigger(ToClients {
|
|
mode: SendMode::Broadcast,
|
|
message: PlaySound::Backpack { open: state.open },
|
|
});
|
|
}
|
|
|
|
for press in backpack_lefts.read() {
|
|
let player = clients.get_controller(press.client_id);
|
|
let backpack = backpacks.get(player).unwrap();
|
|
|
|
if !state.open {
|
|
return;
|
|
}
|
|
|
|
if state.current_slot > 0 {
|
|
state.current_slot -= 1;
|
|
|
|
commands.server_trigger(ToClients {
|
|
mode: SendMode::Broadcast,
|
|
message: PlaySound::Selection,
|
|
});
|
|
sync(&backpack, &mut state, time.elapsed_secs());
|
|
}
|
|
}
|
|
|
|
for press in backpack_rights.read() {
|
|
let player = clients.get_controller(press.client_id);
|
|
let backpack = backpacks.get(player).unwrap();
|
|
|
|
if !state.open {
|
|
return;
|
|
}
|
|
|
|
if state.current_slot < state.count.saturating_sub(1) {
|
|
state.current_slot += 1;
|
|
|
|
commands.server_trigger(ToClients {
|
|
mode: SendMode::Broadcast,
|
|
message: PlaySound::Selection,
|
|
});
|
|
sync(&backpack, &mut state, time.elapsed_secs());
|
|
}
|
|
}
|
|
|
|
for _ in backpack_swaps.read() {
|
|
if !state.open {
|
|
return;
|
|
}
|
|
|
|
commands.trigger(BackbackSwapEvent(state.current_slot));
|
|
}
|
|
}
|
|
|
|
fn sync_on_change(
|
|
backpack: Query<Ref<Backpack>>,
|
|
mut state: Single<&mut BackpackUiState>,
|
|
time: Res<Time>,
|
|
) {
|
|
for backpack in backpack.iter() {
|
|
if backpack.is_changed() || backpack.reloading() {
|
|
sync(&backpack, &mut state, time.elapsed_secs());
|
|
}
|
|
}
|
|
}
|
|
|
|
fn sync(backpack: &Backpack, state: &mut Single<&mut BackpackUiState>, time: f32) {
|
|
state.count = backpack.heads.len();
|
|
|
|
state.scroll = state.scroll.min(state.count.saturating_sub(HEAD_SLOTS));
|
|
|
|
if state.current_slot >= state.scroll + HEAD_SLOTS {
|
|
state.scroll = state.current_slot.saturating_sub(HEAD_SLOTS - 1);
|
|
}
|
|
if state.current_slot < state.scroll {
|
|
state.scroll = state.current_slot;
|
|
}
|
|
|
|
for i in 0..HEAD_SLOTS {
|
|
if let Some(head) = backpack.heads.get(i + state.scroll) {
|
|
state.heads[i] = Some(UiHeadState::new(*head, time));
|
|
} else {
|
|
state.heads[i] = None;
|
|
}
|
|
}
|
|
}
|