From e7ebff2029af83b9940cc55e73a6411fdf9c6955 Mon Sep 17 00:00:00 2001 From: extrawurst <776816+extrawurst@users.noreply.github.com> Date: Fri, 12 Dec 2025 04:36:29 +0100 Subject: [PATCH] Run trigger logic client side (#86) --- crates/shared/src/abilities/arrow.rs | 9 +- crates/shared/src/abilities/gun.rs | 11 +- crates/shared/src/abilities/mod.rs | 192 +++++++++--------- crates/shared/src/abilities/thrown.rs | 8 +- .../shared/src/control/controller_common.rs | 14 +- crates/shared/src/player.rs | 3 +- 6 files changed, 113 insertions(+), 124 deletions(-) diff --git a/crates/shared/src/abilities/arrow.rs b/crates/shared/src/abilities/arrow.rs index fe4e37f..d389797 100644 --- a/crates/shared/src/abilities/arrow.rs +++ b/crates/shared/src/abilities/arrow.rs @@ -1,12 +1,11 @@ use super::TriggerArrow; use crate::{ GameState, billboards::Billboard, global_observer, heads_database::HeadsDatabase, - hitpoints::Hit, loading_assets::GameAssets, physics_layers::GameLayer, protocol::PlaySound, + hitpoints::Hit, loading_assets::GameAssets, physics_layers::GameLayer, utils::sprite_3d_animation::AnimationTimer, }; use avian3d::prelude::*; use bevy::{light::NotShadowCaster, prelude::*}; -use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients}; use bevy_sprite3d::Sprite3d; #[derive(Component)] @@ -45,10 +44,8 @@ fn on_trigger_arrow( ) { let state = trigger.0; - commands.server_trigger(ToClients { - mode: SendMode::Broadcast, - message: PlaySound::Crossbow, - }); + #[cfg(feature = "client")] + commands.trigger(crate::protocol::PlaySound::Crossbow); let rotation = if let Some(target) = state.target { let t = query_transform diff --git a/crates/shared/src/abilities/gun.rs b/crates/shared/src/abilities/gun.rs index da6d5f0..6aaa547 100644 --- a/crates/shared/src/abilities/gun.rs +++ b/crates/shared/src/abilities/gun.rs @@ -1,12 +1,11 @@ use super::TriggerGun; use crate::{ GameState, billboards::Billboard, global_observer, heads_database::HeadsDatabase, - hitpoints::Hit, loading_assets::GameAssets, physics_layers::GameLayer, protocol::PlaySound, - tb_entities::EnemySpawn, utils::sprite_3d_animation::AnimationTimer, + hitpoints::Hit, loading_assets::GameAssets, physics_layers::GameLayer, tb_entities::EnemySpawn, + utils::sprite_3d_animation::AnimationTimer, }; use avian3d::prelude::*; use bevy::{light::NotShadowCaster, prelude::*}; -use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients}; use bevy_sprite3d::Sprite3d; #[derive(Component)] @@ -92,10 +91,8 @@ fn on_trigger_gun( ) { let state = trigger.0; - commands.server_trigger(ToClients { - mode: SendMode::Broadcast, - message: PlaySound::Gun, - }); + #[cfg(feature = "client")] + commands.trigger(crate::protocol::PlaySound::Gun); let rotation = if let Some(t) = state .target diff --git a/crates/shared/src/abilities/mod.rs b/crates/shared/src/abilities/mod.rs index 7781ba0..25b4fc7 100644 --- a/crates/shared/src/abilities/mod.rs +++ b/crates/shared/src/abilities/mod.rs @@ -12,13 +12,12 @@ use crate::{ protocol::PlaySound, utils::{billboards::Billboard, explosions::Explosion, sprite_3d_animation::AnimationTimer}, }; -#[cfg(feature = "server")] use crate::{ - aim::AimTarget, character::CharacterHierarchy, control::Inputs, head::ActiveHead, - heads::ActiveHeads, heads_database::HeadsDatabase, player::Player, + aim::AimTarget, character::CharacterHierarchy, control::Inputs, heads::ActiveHeads, + heads_database::HeadsDatabase, player::Player, }; use bevy::{light::NotShadowCaster, prelude::*}; -use bevy_replicon::prelude::{ClientState, SendMode, ServerTriggerExt, ToClients}; +use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients}; use bevy_sprite3d::Sprite3d; pub use healing::Healing; use serde::{Deserialize, Serialize}; @@ -82,14 +81,14 @@ pub struct TriggerMissile(pub TriggerData); #[derive(Event, Reflect)] pub struct TriggerCurver(pub TriggerData); -#[derive(Resource, Default)] -pub struct TriggerStateRes { - #[cfg(feature = "server")] +#[derive(Component, Default, Reflect)] +#[reflect(Component)] +pub struct PlayerTriggerState { next_trigger_timestamp: f32, active: bool, } -impl TriggerStateRes { +impl PlayerTriggerState { pub fn is_active(&self) -> bool { self.active } @@ -115,8 +114,6 @@ pub enum ExplodingProjectileSet { } pub fn plugin(app: &mut App) { - app.init_resource::(); - app.add_plugins(gun::plugin); app.add_plugins(thrown::plugin); app.add_plugins(arrow::plugin); @@ -130,9 +127,7 @@ pub fn plugin(app: &mut App) { .after(ExplodingProjectileSet::Mark) .run_if(in_state(GameState::Playing)), ); - app.add_systems(OnEnter(GameState::Playing), setup); - #[cfg(feature = "server")] app.add_systems( FixedUpdate, (on_trigger_state, update, update_heal_ability) @@ -141,9 +136,7 @@ pub fn plugin(app: &mut App) { ); app.add_systems( FixedUpdate, - explode_projectiles - .run_if(in_state(ClientState::Disconnected)) - .in_set(ExplodingProjectileSet::Explode), + explode_projectiles.in_set(ExplodingProjectileSet::Explode), ); global_observer!(app, build_explosion_sprite); @@ -183,114 +176,113 @@ fn explode_projectiles(mut commands: Commands, query: Query<(Entity, &ExplodingP } } -#[cfg(feature = "server")] -fn on_trigger_state( - mut res: ResMut, - players: Query<(&ActiveHead, &Inputs), With>, -) { - for (_, inputs) in players.iter() { - res.active = inputs.trigger; +fn on_trigger_state(mut players: Query<(&mut PlayerTriggerState, &Inputs), With>) { + for (mut trigger_state, inputs) in players.iter_mut() { + trigger_state.active = inputs.trigger; } } -#[cfg(feature = "server")] fn update( - mut res: ResMut, mut commands: Commands, - player_query: Query<(Entity, &AimTarget, &Inputs), With>, - mut active_heads: Single<&mut ActiveHeads, With>, + mut query: Query< + ( + Entity, + &mut ActiveHeads, + &mut PlayerTriggerState, + &AimTarget, + &Inputs, + ), + With, + >, + query_transform: Query<&Transform>, heads_db: Res, time: Res