mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Improve Phyiscs speed of entity handling.
Before we had accessed velocities in a nested loop O(n²). Now we copy it only once out of the ECS system and store it in a tmp Vec. As we no longer need to hold a mut and imutable reference, we can iter of `&mut velocities` again in the outer loop. Also improved many calculations called in the loop to make the check if 2 entities are to far apart as easy as possible
This commit is contained in:
parent
e07dc51d2d
commit
bbe6e8be7c
@ -129,10 +129,32 @@ impl<'a> System<'a> for Sys {
|
||||
// terrain collision code below, although that's not trivial to do since
|
||||
// it means the step needs to take into account the speeds of both
|
||||
// entities.
|
||||
span!(guard, "Clone pushback velocities");
|
||||
//just prereserve for 1000 entities
|
||||
let mut old_velocities_times_dt = Vec::with_capacity(1000);
|
||||
for (entity, vel, _, _, _, _) in (
|
||||
&entities,
|
||||
&velocities,
|
||||
&positions,
|
||||
!&mountings,
|
||||
!&beams,
|
||||
!&shockwaves,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let id = entity.id() as usize;
|
||||
let vel_dt = vel.0.clone() * dt.0;
|
||||
if id >= old_velocities_times_dt.len() {
|
||||
old_velocities_times_dt.resize(id + 1, Vec3::zero());
|
||||
}
|
||||
old_velocities_times_dt[id] = vel_dt;
|
||||
}
|
||||
drop(guard);
|
||||
span!(guard, "Apply pushback");
|
||||
for (entity, pos, scale, mass, collider, _, _, physics, projectile) in (
|
||||
for (entity, pos, vel, scale, mass, collider, _, _, physics, projectile) in (
|
||||
&entities,
|
||||
&positions,
|
||||
&mut velocities,
|
||||
scales.maybe(),
|
||||
masses.maybe(),
|
||||
colliders.maybe(),
|
||||
@ -144,7 +166,7 @@ impl<'a> System<'a> for Sys {
|
||||
projectiles.maybe(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(_, _, _, _, _, _, sticky, physics, _)| {
|
||||
.filter(|(_, _, _, _, _, _, _, sticky, physics, _)| {
|
||||
sticky.is_none() || (physics.on_wall.is_none() && !physics.on_ground)
|
||||
})
|
||||
{
|
||||
@ -152,6 +174,7 @@ impl<'a> System<'a> for Sys {
|
||||
let radius = collider.map(|c| c.get_radius()).unwrap_or(0.5);
|
||||
let z_limits = collider.map(|c| c.get_z_limits()).unwrap_or((-0.5, 0.5));
|
||||
let mass = mass.map(|m| m.0).unwrap_or(scale);
|
||||
let vel_dt = old_velocities_times_dt[entity.id() as usize];
|
||||
|
||||
// Resets touch_entities in physics
|
||||
physics.touch_entities.clear();
|
||||
@ -191,42 +214,46 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
|
||||
let radius_other = collider_other.map(|c| c.get_radius()).unwrap_or(0.5);
|
||||
let z_limits_other = collider_other
|
||||
.map(|c| c.get_z_limits())
|
||||
.unwrap_or((-0.5, 0.5));
|
||||
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
|
||||
if mass_other == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let collision_dist = scale * radius + scale_other * radius_other;
|
||||
let collision_dist_sqr = collision_dist * collision_dist;
|
||||
let vel_dt_other = old_velocities_times_dt[entity_other.id() as usize];
|
||||
|
||||
let vel = velocities.get(entity).copied().unwrap_or_default().0;
|
||||
let vel_other = velocities.get(entity_other).copied().unwrap_or_default().0;
|
||||
let pos_diff_squared = (pos.0 - pos_other.0).magnitude_squared();
|
||||
let vel_diff_squared = (vel_dt - vel_dt_other).magnitude_squared();
|
||||
|
||||
// Sanity check: don't try colliding entities that are too far from each other
|
||||
// Note: I think this catches all cases. If you get entity collision problems,
|
||||
// try removing this!
|
||||
if (pos.0 - pos_other.0).xy().magnitude()
|
||||
> ((vel - vel_other) * dt.0).xy().magnitude() + collision_dist
|
||||
{
|
||||
if pos_diff_squared > vel_diff_squared + collision_dist_sqr {
|
||||
continue;
|
||||
}
|
||||
|
||||
let min_collision_dist = 0.3;
|
||||
let increments = ((vel - vel_other).magnitude() * dt.0 / min_collision_dist)
|
||||
let z_limits_other = collider_other
|
||||
.map(|c| c.get_z_limits())
|
||||
.unwrap_or((-0.5, 0.5));
|
||||
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
|
||||
//This check after the pos check, as we currently don't have that many massless
|
||||
// entites [citation needed]
|
||||
if mass_other == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MIN_COLLISION_DIST: f32 = 0.3;
|
||||
let increments = (vel_diff_squared.sqrt() / MIN_COLLISION_DIST)
|
||||
.max(1.0)
|
||||
.ceil() as usize;
|
||||
let step_delta = 1.0 / increments as f32;
|
||||
let mut collided = false;
|
||||
|
||||
for i in 0..increments {
|
||||
let factor = i as f32 * step_delta;
|
||||
let pos = pos.0 + vel * dt.0 * factor;
|
||||
let pos_other = pos_other.0 + vel_other * dt.0 * factor;
|
||||
let pos = pos.0 + vel_dt * factor;
|
||||
let pos_other = pos_other.0 + vel_dt_other * factor;
|
||||
|
||||
let diff = pos.xy() - pos_other.xy();
|
||||
|
||||
if diff.magnitude_squared() <= collision_dist.powf(2.0)
|
||||
if diff.magnitude_squared() <= collision_dist_sqr
|
||||
&& pos.z + z_limits.1 * scale
|
||||
>= pos_other.z + z_limits_other.0 * scale_other
|
||||
&& pos.z + z_limits.0 * scale
|
||||
@ -250,9 +277,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Change velocity
|
||||
velocities
|
||||
.get_mut(entity)
|
||||
.map(|vel| vel.0 += vel_delta * dt.0);
|
||||
vel.0 += vel_delta * dt.0;
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
|
@ -605,7 +605,7 @@ fn handle_spawn(
|
||||
.and_then(|a| a.parse().ok())
|
||||
.filter(|x| *x > 0)
|
||||
.unwrap_or(1)
|
||||
.min(10);
|
||||
.min(50);
|
||||
|
||||
let ai = opt_ai.unwrap_or_else(|| "true".to_string());
|
||||
|
||||
|
@ -62,8 +62,8 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
});
|
||||
if already_in_same_group {
|
||||
// Inform of failure
|
||||
if let Some(general_stream) = clients.get(entity) {
|
||||
general_stream.send_fallible(ChatType::Meta.server_msg(
|
||||
if let Some(client) = clients.get(entity) {
|
||||
client.send_fallible(ChatType::Meta.server_msg(
|
||||
"Invite failed, can't invite someone already in your group".to_owned(),
|
||||
));
|
||||
}
|
||||
@ -92,8 +92,8 @@ pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupMani
|
||||
>= max_group_size as usize;
|
||||
if group_size_limit_reached {
|
||||
// Inform inviter that they have reached the group size limit
|
||||
if let Some(general_stream) = clients.get(entity) {
|
||||
general_stream.send_fallible(
|
||||
if let Some(client) = clients.get(entity) {
|
||||
client.send_fallible(
|
||||
ChatType::Meta.server_msg(
|
||||
"Invite failed, pending invites plus current group size have reached \
|
||||
the group size limit"
|
||||
|
Loading…
Reference in New Issue
Block a user