Clientside Backpack UI (#84)

This commit is contained in:
PROMETHIA-27
2025-12-10 18:31:42 -05:00
committed by GitHub
parent 668ed93475
commit 65663f682f
12 changed files with 178 additions and 270 deletions

View File

@@ -1,8 +1,7 @@
use super::UiHeadState;
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
pub static HEAD_SLOTS: usize = 5;
pub static BACKPACK_HEAD_SLOTS: usize = 5;
#[derive(Component, Default)]
pub struct BackpackMarker;
@@ -19,7 +18,7 @@ pub struct HeadImage(pub usize);
#[derive(Component, Default)]
pub struct HeadDamage(pub usize);
#[derive(Component, Default, Debug, Reflect, Serialize, Deserialize, PartialEq)]
#[derive(Component, Default, Debug, Reflect)]
#[reflect(Component, Default)]
pub struct BackpackUiState {
pub heads: [Option<UiHeadState>; 5],

View File

@@ -1,8 +1,15 @@
#[cfg(feature = "client")]
use crate::{
backpack::backpack_ui::BackpackUiState, control::BackpackButtonPress, player::LocalPlayer,
protocol::PlaySound,
};
use crate::{
cash::CashCollectEvent, global_observer, head_drop::HeadCollected, heads::HeadState,
heads_database::HeadsDatabase,
};
use bevy::prelude::*;
#[cfg(feature = "client")]
use bevy_replicon::prelude::ClientTriggerExt;
use serde::{Deserialize, Serialize};
pub use ui_head_state::UiHeadState;
@@ -35,17 +42,116 @@ impl Backpack {
}
}
#[derive(Event)]
pub struct BackbackSwapEvent(pub usize);
#[derive(Event, Serialize, Deserialize)]
pub struct BackpackSwapEvent(pub usize);
pub fn plugin(app: &mut App) {
app.register_type::<Backpack>();
app.add_plugins(backpack_ui::plugin);
#[cfg(feature = "client")]
app.add_systems(FixedUpdate, (backpack_inputs, sync_on_change));
global_observer!(app, on_head_collect);
}
#[cfg(feature = "client")]
#[allow(clippy::too_many_arguments)]
fn backpack_inputs(
backpacks: Single<(&Backpack, &mut BackpackUiState), With<LocalPlayer>>,
mut backpack_inputs: MessageReader<BackpackButtonPress>,
mut commands: Commands,
time: Res<Time>,
) {
let (backpack, mut state) = backpacks.into_inner();
for input in backpack_inputs.read() {
match input {
BackpackButtonPress::Toggle => {
if state.count == 0 {
return;
}
state.open = !state.open;
commands.trigger(PlaySound::Backpack { open: state.open });
}
BackpackButtonPress::Swap => {
if !state.open {
return;
}
commands.client_trigger(BackpackSwapEvent(state.current_slot));
}
BackpackButtonPress::Left => {
if !state.open {
return;
}
if state.current_slot > 0 {
state.current_slot -= 1;
commands.trigger(PlaySound::Selection);
sync_backpack_ui(backpack, &mut state, time.elapsed_secs());
}
}
BackpackButtonPress::Right => {
if !state.open {
return;
}
if state.current_slot < state.count.saturating_sub(1) {
state.current_slot += 1;
commands.trigger(PlaySound::Selection);
sync_backpack_ui(backpack, &mut state, time.elapsed_secs());
}
}
}
}
}
#[cfg(feature = "client")]
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_ui(&backpack, &mut state, time.elapsed_secs());
}
}
}
#[cfg(feature = "client")]
fn sync_backpack_ui(backpack: &Backpack, state: &mut BackpackUiState, time: f32) {
use crate::backpack::backpack_ui::BACKPACK_HEAD_SLOTS;
state.count = backpack.heads.len();
state.scroll = state
.scroll
.min(state.count.saturating_sub(BACKPACK_HEAD_SLOTS));
if state.current_slot >= state.scroll + BACKPACK_HEAD_SLOTS {
state.scroll = state.current_slot.saturating_sub(BACKPACK_HEAD_SLOTS - 1);
}
if state.current_slot < state.scroll {
state.scroll = state.current_slot;
}
for i in 0..BACKPACK_HEAD_SLOTS {
if let Some(head) = backpack.heads.get(i + state.scroll) {
use crate::backpack::ui_head_state::UiHeadState;
state.heads[i] = Some(UiHeadState::new(*head, time));
} else {
state.heads[i] = None;
}
}
}
fn on_head_collect(
trigger: On<HeadCollected>,
mut cmds: Commands,