Skip to content

Commit

Permalink
Fix inverted control flow
Browse files Browse the repository at this point in the history
  • Loading branch information
janhohenheim committed Jul 6, 2024
1 parent d8c23f4 commit 7ee3501
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 56 deletions.
88 changes: 32 additions & 56 deletions src/pull_object.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::prelude::*;

mod candidate;
mod find_in_cone;

use self::{candidate::*, find_in_cone::*};

pub(super) fn plugin(app: &mut App) {
app.add_event::<PullObject>()
.observe(on_pull_object.pipe(pull_object));
.observe(on_pull_object.pipe(find_object));
}

#[derive(Debug, Event)]
Expand All @@ -14,8 +17,8 @@ fn on_pull_object(trigger: Trigger<PullObject>) -> Entity {
trigger.entity()
}

/// Inspired by [`CWeaponPhysCannon::FindObjectInCone`](https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/game/server/hl2/weapon_physcannon.cpp#L2690)
fn pull_object(
/// Inspired by [`CWeaponPhysCannon::FindObject`](https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/hl2/weapon_physcannon.cpp#L2497)
fn find_object(
In(actor_entity): In<Entity>,
spatial_query: SpatialQuery,
q_actor: Query<(&GlobalTransform, &AvianPickupActor)>,
Expand All @@ -25,60 +28,33 @@ fn pull_object(
let (origin, config) = q_actor.get(actor_entity).unwrap();

let origin = origin.compute_transform();
let candidate = get_object_candidate(&spatial_query, origin, &config);

// TODO: [`CWeaponPhysCannon::FindObject`](https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/hl2/weapon_physcannon.cpp#L2497)
let candidate = candidate::get_object_candidate(&spatial_query, origin, &config);

let mut nearest_dist = config.trace_length + 1.0;
let box_collider = Cuboid::from_size(Vec3::splat(2.0 * nearest_dist)).into();

let colliders = spatial_query.shape_intersections(
&box_collider,
origin.translation,
origin.rotation,
config.spatial_query_filter.clone(),
);
let mut nearest_entity = None;

for collider in colliders {
let rigid_body_entity = q_collider
.get(collider)
.expect("`shape_intersections` returned something without a `Collider`")
.get();
let (&rigid_body, object_transform) = q_rigid_body
.get(rigid_body_entity)
.expect("Failed to get `RigidBody` for entity");
if rigid_body != RigidBody::Dynamic {
continue;
}
let object_translation = object_transform.translation();

// Closer than other objects
let los = object_translation - origin.translation;
let (los, dist) = Dir3::new_and_length(los).expect("Failed to normalize line of sight");
if dist >= nearest_dist {
continue;
}

// Cull to the cone
let max_dot = config.cone;
if los.dot(origin.forward().into()) <= max_dot {
continue;
}

// Make sure it isn't occluded!
if let Some(hit) = spatial_query.cast_ray(
origin.translation,
los,
dist,
true,
config.spatial_query_filter.clone(),
) {
if hit.entity == rigid_body_entity {
nearest_dist = dist;
nearest_entity.replace(rigid_body_entity);
}
let reaction = if let Some(candidate) = candidate {
if candidate.toi_fraction < 0.25 {
ObjectReaction::Hold
} else {
ObjectReaction::Pull
}
} else {
ObjectReaction::None
};

if reaction == ObjectReaction::None || true {
let object = find_object_in_cone(
In(actor_entity),
spatial_query,
q_actor,
q_collider,
q_rigid_body,
);
info!("Found object: {object:?}");
}
info!("Nearest entity: {:?}", nearest_entity)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
enum ObjectReaction {
None,
Pull,
Hold,
}
67 changes: 67 additions & 0 deletions src/pull_object/find_in_cone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::prelude::*;

/// Inspired by [`CWeaponPhysCannon::FindObjectInCone`](https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/game/server/hl2/weapon_physcannon.cpp#L2690)
pub(super) fn find_object_in_cone(
In(actor_entity): In<Entity>,
spatial_query: SpatialQuery,
q_actor: Query<(&GlobalTransform, &AvianPickupActor)>,
q_collider: Query<&ColliderParent>,
q_rigid_body: Query<(&RigidBody, &GlobalTransform)>,
) -> Option<Entity> {
let (origin, config) = q_actor.get(actor_entity).unwrap();

let origin = origin.compute_transform();

let mut nearest_dist = config.trace_length + 1.0;
let box_collider = Cuboid::from_size(Vec3::splat(2.0 * nearest_dist)).into();

let colliders = spatial_query.shape_intersections(
&box_collider,
origin.translation,
origin.rotation,
config.spatial_query_filter.clone(),
);
let mut nearest_entity = None;

for collider in colliders {
let rigid_body_entity = q_collider
.get(collider)
.expect("`shape_intersections` returned something without a `Collider`")
.get();
let (&rigid_body, object_transform) = q_rigid_body
.get(rigid_body_entity)
.expect("Failed to get `RigidBody` for entity");
if rigid_body != RigidBody::Dynamic {
continue;
}
let object_translation = object_transform.translation();

// Closer than other objects
let los = object_translation - origin.translation;
let (los, dist) = Dir3::new_and_length(los).expect("Failed to normalize line of sight");
if dist >= nearest_dist {
continue;
}

// Cull to the cone
let max_dot = config.cone;
if los.dot(origin.forward().into()) <= max_dot {
continue;
}

// Make sure it isn't occluded!
if let Some(hit) = spatial_query.cast_ray(
origin.translation,
los,
dist,
true,
config.spatial_query_filter.clone(),
) {
if hit.entity == rigid_body_entity {
nearest_dist = dist;
nearest_entity.replace(rigid_body_entity);
}
}
}
nearest_entity
}

0 comments on commit 7ee3501

Please sign in to comment.