diff --git a/crates/render_frontend/src/adapters/anim/dyn_ent_wake.rs b/crates/render_frontend/src/adapters/anim/dyn_ent_wake.rs index 3b3709b..fd1fa7b 100644 --- a/crates/render_frontend/src/adapters/anim/dyn_ent_wake.rs +++ b/crates/render_frontend/src/adapters/anim/dyn_ent_wake.rs @@ -52,6 +52,14 @@ pub struct DynEntWakeBroadphase { pub query_ms: f32, } +#[derive(Clone, Copy, Debug, Message)] +pub struct DynEntPelletHit { + pub world: frame::WorldStamp, + pub weapon: u32, + pub start: Vec3, + pub end: Vec3, +} + #[derive(Clone, Copy, Debug)] struct DynEntWakeEntry { entity: Entity, @@ -787,6 +795,59 @@ pub(crate) fn on_entity_bullet_hit( } } +#[allow(clippy::too_many_arguments)] +pub(crate) fn hit_dyn_ents_from_pellets( + mut hits: MessageReader, + weapons: Option>, + catalog: Option>, + mut broadphase: ResMut, + mut instances: Query< + ( + Entity, + &mut WorldDynEntInstance, + &Transform, + &mut Visibility, + ), + With, + >, + mut impulses: MessageWriter, + mut phys: ResMut, + mut host: Option>, + fx: Option>, + scene: Option>, + entity_marks: Res, +) { + let catalog = catalog.as_deref(); + let fx = fx.as_deref(); + let scene = scene.as_deref(); + let marks = entity_marks.as_ref(); + for hit in hits.read() { + let Some((entity, pose, bullet_scale)) = + closest_segment_hit(hit.start, hit.end, catalog, &mut broadphase, &instances) + else { + continue; + }; + let weapons = weapons + .as_deref() + .and_then(|weapons| weapons.for_event(hit.world).ok()); + hit_one_dyn_ent( + entity, + pose, + hit.start, + hit.end, + bullet_scale, + weapon_hit_damage(weapons.as_ref(), hit.weapon), + &mut instances, + &mut impulses, + phys.as_mut(), + host.as_deref_mut(), + fx, + scene, + marks, + ); + } +} + pub(crate) fn on_entity_event_sound( sound: On, weapons: Option>, @@ -917,6 +978,7 @@ fn on_physics_sphere( pub fn register_dyn_ent_wake(app: &mut App) { app.scoped::(frame::MatchScope::Live) + .scoped_message::(frame::MatchScope::Live) .add_observer(on_entity_explosion) .add_observer(on_physics_sphere) .add_observer(on_entity_bullet_hit) @@ -927,6 +989,12 @@ pub fn register_dyn_ent_wake(app: &mut App) { .in_set(frame::InMatch) .in_set(net::ClientSet::Receive), ) + .add_systems( + Update, + hit_dyn_ents_from_pellets + .in_set(frame::InMatch) + .in_set(net::ClientSet::Present), + ) .add_systems( Update, wake_player_overlap diff --git a/crates/render_frontend/src/adapters/fx/system.rs b/crates/render_frontend/src/adapters/fx/system.rs index 22e3b8a..489c68a 100644 --- a/crates/render_frontend/src/adapters/fx/system.rs +++ b/crates/render_frontend/src/adapters/fx/system.rs @@ -3261,12 +3261,13 @@ fn drain_pellet_fx( tracers: Option>, mut tracer_world: ResMut, mut gate: ResMut, - (local, generation, timeline, mut occurrences, verdicts): ( + (local, generation, timeline, mut occurrences, verdicts, mut dyn_ent_hits): ( Res, Res, Res, ResMut, Res, + MessageWriter, ), mut host: ResMut, mut cursor: ResMut, @@ -3280,6 +3281,14 @@ fn drain_pellet_fx( if world != generation.stamp() { continue; } + if domain != net::EntityEventDomain::Predicted && record.normal != [0.0; 3] { + dyn_ent_hits.write(crate::adapters::anim::dyn_ent_wake::DynEntPelletHit { + world, + weapon: record.weapon, + start: Vec3::from_array(record.start), + end: Vec3::from_array(record.end), + }); + } let now = host.0.msec_now; let request = FireFxRequest { world,