Sync reloading and cash (#66)
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
use super::{Backpack, UiHeadState};
|
||||
#[cfg(feature = "server")]
|
||||
use super::Backpack;
|
||||
use super::UiHeadState;
|
||||
use crate::{
|
||||
GameState, HEDZ_GREEN, backpack::BackbackSwapEvent, control::ControlState, heads::HeadsImages,
|
||||
loading_assets::UIAssets, sounds::PlaySound,
|
||||
GameState, HEDZ_GREEN, loading_assets::UIAssets, protocol::PlayBackpackSound, sounds::PlaySound,
|
||||
};
|
||||
#[cfg(feature = "server")]
|
||||
use crate::{backpack::BackbackSwapEvent, control::ControlState};
|
||||
#[cfg(feature = "client")]
|
||||
use crate::{global_observer, heads::HeadsImages};
|
||||
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
||||
use lightyear::prelude::input::native::ActionState;
|
||||
#[cfg(feature = "server")]
|
||||
use lightyear::prelude::{ActionsChannel, TriggerSender, input::native::ActionState};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
static HEAD_SLOTS: usize = 5;
|
||||
|
||||
@@ -14,18 +21,21 @@ struct BackpackMarker;
|
||||
#[derive(Component, Default)]
|
||||
struct BackpackCountText;
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Component, Default)]
|
||||
struct HeadSelector(pub usize);
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Component, Default)]
|
||||
struct HeadImage(pub usize);
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Component, Default)]
|
||||
struct HeadDamage(pub usize);
|
||||
|
||||
#[derive(Resource, Default, Debug, Reflect)]
|
||||
#[reflect(Resource, Default)]
|
||||
struct BackpackUiState {
|
||||
#[derive(Component, Default, Debug, Reflect, Serialize, Deserialize, PartialEq)]
|
||||
#[reflect(Component, Default)]
|
||||
pub struct BackpackUiState {
|
||||
heads: [Option<UiHeadState>; 5],
|
||||
scroll: usize,
|
||||
count: usize,
|
||||
@@ -33,6 +43,7 @@ struct BackpackUiState {
|
||||
open: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
impl BackpackUiState {
|
||||
fn relative_current_slot(&self) -> usize {
|
||||
self.current_slot.saturating_sub(self.scroll)
|
||||
@@ -41,14 +52,22 @@ impl BackpackUiState {
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.register_type::<BackpackUiState>();
|
||||
app.init_resource::<BackpackUiState>();
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
#[cfg(feature = "server")]
|
||||
app.add_systems(
|
||||
Update,
|
||||
(update, sync_on_change, update_visibility, update_count)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
FixedUpdate,
|
||||
sync_on_change.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
#[cfg(feature = "client")]
|
||||
app.add_systems(
|
||||
FixedUpdate,
|
||||
(update, update_visibility, update_count).run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
#[cfg(feature = "server")]
|
||||
app.add_systems(FixedUpdate, swap_head_inputs);
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
global_observer!(app, play_backpack_sound);
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, assets: Res<UIAssets>) {
|
||||
@@ -185,80 +204,75 @@ fn spawn_head_ui(
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
fn update_visibility(
|
||||
state: Res<BackpackUiState>,
|
||||
mut backpack: Query<&mut Visibility, (With<BackpackMarker>, Without<BackpackCountText>)>,
|
||||
mut count: Query<&mut Visibility, (Without<BackpackMarker>, With<BackpackCountText>)>,
|
||||
state: Single<&BackpackUiState, Changed<BackpackUiState>>,
|
||||
mut backpack: Single<&mut Visibility, (With<BackpackMarker>, Without<BackpackCountText>)>,
|
||||
mut count: Single<&mut Visibility, (Without<BackpackMarker>, With<BackpackCountText>)>,
|
||||
) {
|
||||
if state.is_changed() {
|
||||
for mut vis in backpack.iter_mut() {
|
||||
*vis = if state.open {
|
||||
Visibility::Visible
|
||||
} else {
|
||||
Visibility::Hidden
|
||||
};
|
||||
}
|
||||
**backpack = if state.open {
|
||||
Visibility::Visible
|
||||
} else {
|
||||
Visibility::Hidden
|
||||
};
|
||||
|
||||
for mut vis in count.iter_mut() {
|
||||
*vis = if !state.open {
|
||||
Visibility::Visible
|
||||
} else {
|
||||
Visibility::Hidden
|
||||
};
|
||||
}
|
||||
}
|
||||
**count = if !state.open {
|
||||
Visibility::Visible
|
||||
} else {
|
||||
Visibility::Hidden
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
fn update_count(
|
||||
state: Res<BackpackUiState>,
|
||||
text: Query<Entity, With<BackpackCountText>>,
|
||||
state: Single<&BackpackUiState, Changed<BackpackUiState>>,
|
||||
text: Option<Single<Entity, With<BackpackCountText>>>,
|
||||
mut writer: TextUiWriter,
|
||||
) {
|
||||
if state.is_changed() {
|
||||
let Some(text) = text.iter().next() else {
|
||||
return;
|
||||
};
|
||||
let Some(text) = text else {
|
||||
return;
|
||||
};
|
||||
|
||||
*writer.text(text, 0) = state.count.to_string();
|
||||
}
|
||||
*writer.text(*text, 0) = state.count.to_string();
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
fn update(
|
||||
state: Res<BackpackUiState>,
|
||||
state: Single<&BackpackUiState, Changed<BackpackUiState>>,
|
||||
heads_images: Res<HeadsImages>,
|
||||
mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without<HeadSelector>>,
|
||||
mut head_damage: Query<(&HeadDamage, &mut Node), Without<HeadSelector>>,
|
||||
mut head_selector: Query<(&HeadSelector, &mut Visibility), Without<HeadImage>>,
|
||||
) {
|
||||
if state.is_changed() {
|
||||
for (HeadImage(head), mut vis, mut image) in head_image.iter_mut() {
|
||||
if let Some(head) = &state.heads[*head] {
|
||||
*vis = Visibility::Inherited;
|
||||
image.image = heads_images.heads[head.head].clone();
|
||||
} else {
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
for (HeadImage(head), mut vis, mut image) in head_image.iter_mut() {
|
||||
if let Some(head) = &state.heads[*head] {
|
||||
*vis = Visibility::Inherited;
|
||||
image.image = heads_images.heads[head.head].clone();
|
||||
} else {
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
for (HeadDamage(head), mut node) in head_damage.iter_mut() {
|
||||
if let Some(head) = &state.heads[*head] {
|
||||
node.height = Val::Percent(head.damage() * 100.0);
|
||||
}
|
||||
}
|
||||
for (HeadDamage(head), mut node) in head_damage.iter_mut() {
|
||||
if let Some(head) = &state.heads[*head] {
|
||||
node.height = Val::Percent(head.damage() * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
for (HeadSelector(head), mut vis) in head_selector.iter_mut() {
|
||||
*vis = if *head == state.relative_current_slot() {
|
||||
Visibility::Inherited
|
||||
} else {
|
||||
Visibility::Hidden
|
||||
};
|
||||
}
|
||||
for (HeadSelector(head), mut vis) in head_selector.iter_mut() {
|
||||
*vis = if *head == state.relative_current_slot() {
|
||||
Visibility::Inherited
|
||||
} else {
|
||||
Visibility::Hidden
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
fn swap_head_inputs(
|
||||
player: Query<(&ActionState<ControlState>, Ref<Backpack>)>,
|
||||
mut trigger: Single<&mut TriggerSender<PlayBackpackSound>>,
|
||||
mut commands: Commands,
|
||||
mut state: ResMut<BackpackUiState>,
|
||||
mut state: Single<&mut BackpackUiState>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
for (controls, backpack) in player.iter() {
|
||||
@@ -268,7 +282,7 @@ fn swap_head_inputs(
|
||||
|
||||
if controls.backpack_toggle {
|
||||
state.open = !state.open;
|
||||
commands.trigger(PlaySound::Backpack { open: state.open });
|
||||
trigger.trigger::<ActionsChannel>(PlayBackpackSound { open: state.open });
|
||||
}
|
||||
|
||||
if !state.open {
|
||||
@@ -295,9 +309,17 @@ fn swap_head_inputs(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
fn play_backpack_sound(trigger: Trigger<PlayBackpackSound>, mut commands: Commands) {
|
||||
commands.trigger(PlaySound::Backpack {
|
||||
open: trigger.event().open,
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
fn sync_on_change(
|
||||
backpack: Query<Ref<Backpack>>,
|
||||
mut state: ResMut<BackpackUiState>,
|
||||
mut state: Single<&mut BackpackUiState>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
for backpack in backpack.iter() {
|
||||
@@ -307,7 +329,8 @@ fn sync_on_change(
|
||||
}
|
||||
}
|
||||
|
||||
fn sync(backpack: &Backpack, state: &mut ResMut<BackpackUiState>, time: f32) {
|
||||
#[cfg(feature = "server")]
|
||||
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));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod backpack_ui;
|
||||
mod ui_head_state;
|
||||
pub mod backpack_ui;
|
||||
pub mod ui_head_state;
|
||||
|
||||
use crate::{
|
||||
cash::CashCollectEvent, global_observer, head_drop::HeadCollected, heads::HeadState,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#[cfg(feature = "server")]
|
||||
use crate::heads::HeadState;
|
||||
use bevy::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Reflect, Default)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Reflect, Default, Serialize, Deserialize)]
|
||||
pub struct UiHeadState {
|
||||
pub head: usize,
|
||||
pub health: f32,
|
||||
@@ -22,6 +24,7 @@ impl UiHeadState {
|
||||
self.reloading
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub(crate) fn new(value: HeadState, time: f32) -> Self {
|
||||
let reloading = if value.has_ammo() {
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user