Improved commands, fixed tether orientation

This commit is contained in:
Joshua Barretto 2023-05-27 16:08:26 +01:00
parent 2d4278e94a
commit 1ac1c900c9
6 changed files with 43 additions and 49 deletions

View File

@ -688,12 +688,12 @@ impl ServerChatCommand {
.collect(), .collect(),
Optional, Optional,
), ),
Float("destination_degrees_ccw_of_east", 90.0, Optional),
Boolean( Boolean(
"Whether the ship should be tethered to the target (or its mount)", "Whether the ship should be tethered to the target (or its mount)",
"false".to_string(), "false".to_string(),
Optional, Optional,
), ),
Float("destination_degrees_ccw_of_east", 90.0, Optional),
], ],
"Spawns a ship", "Spawns a ship",
Some(Admin), Some(Admin),

View File

@ -88,7 +88,7 @@ impl Body {
Body::Skiff => Vec3::new(7.0, 15.0, 10.0), Body::Skiff => Vec3::new(7.0, 15.0, 10.0),
Body::Submarine => Vec3::new(2.0, 15.0, 8.0), Body::Submarine => Vec3::new(2.0, 15.0, 8.0),
Body::Carriage => Vec3::new(5.0, 12.0, 2.0), Body::Carriage => Vec3::new(5.0, 12.0, 2.0),
Body::Cart => Vec3::new(5.0, 8.0, 5.0), Body::Cart => Vec3::new(3.0, 6.0, 1.0),
} }
} }
@ -122,14 +122,21 @@ impl Body {
match self { match self {
Body::DefaultAirship | Body::AirBalloon | Body::Volume => Density(AIR_DENSITY), Body::DefaultAirship | Body::AirBalloon | Body::Volume => Density(AIR_DENSITY),
Body::Submarine => Density(WATER_DENSITY), // Neutrally buoyant Body::Submarine => Density(WATER_DENSITY), // Neutrally buoyant
Body::Carriage => Density(AIR_DENSITY * 1.5), Body::Carriage => Density(WATER_DENSITY * 0.5),
Body::Cart => Density(AIR_DENSITY * 1.2), Body::Cart => Density(500.0 / self.dimensions().product()), /* Carts get a constant
* mass */
_ => Density(AIR_DENSITY * 0.95 + WATER_DENSITY * 0.05), /* Most boats should be very _ => Density(AIR_DENSITY * 0.95 + WATER_DENSITY * 0.05), /* Most boats should be very
* buoyant */ * buoyant */
} }
} }
pub fn mass(&self) -> Mass { Mass((self.hull_vol() + self.balloon_vol()) * self.density().0) } pub fn mass(&self) -> Mass {
if self.can_fly() {
Mass((self.hull_vol() + self.balloon_vol()) * self.density().0)
} else {
Mass(self.density().0 * self.dimensions().product())
}
}
pub fn can_fly(&self) -> bool { pub fn can_fly(&self) -> bool {
matches!(self, Body::DefaultAirship | Body::AirBalloon | Body::Volume) matches!(self, Body::DefaultAirship | Body::AirBalloon | Body::Volume)

View File

@ -150,7 +150,7 @@ impl Body {
quadruped_low::Species::Driggle => 120.0, quadruped_low::Species::Driggle => 120.0,
quadruped_low::Species::HermitAlligator => 120.0, quadruped_low::Species::HermitAlligator => 120.0,
}, },
Body::Ship(ship::Body::Carriage) => 35.0, Body::Ship(ship::Body::Carriage) => 40.0,
Body::Ship(_) => 0.0, Body::Ship(_) => 0.0,
Body::Arthropod(arthropod) => match arthropod.species { Body::Arthropod(arthropod) => match arthropod.species {
arthropod::Species::Tarantula => 135.0, arthropod::Species::Tarantula => 135.0,

View File

@ -1,14 +1,11 @@
use crate::{ use crate::{
comp, comp,
link::{Is, Link, LinkHandle, Role}, link::{Is, Link, LinkHandle, Role},
mounting::{Mount, Rider, VolumeRider}, mounting::{Rider, VolumeRider},
uid::{Uid, UidAllocator}, uid::{Uid, UidAllocator},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{ use specs::{saveload::MarkerAllocator, Entities, Read, ReadStorage, WriteStorage};
saveload::MarkerAllocator, storage::GenericWriteStorage, Component, DenseVecStorage, Entities,
Entity, Read, ReadExpect, ReadStorage, Write, WriteStorage,
};
use vek::*; use vek::*;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -44,25 +41,20 @@ impl Link for Tethered {
WriteStorage<'a, Is<Leader>>, WriteStorage<'a, Is<Leader>>,
WriteStorage<'a, Is<Follower>>, WriteStorage<'a, Is<Follower>>,
ReadStorage<'a, Is<Rider>>, ReadStorage<'a, Is<Rider>>,
ReadStorage<'a, Is<Mount>>,
ReadStorage<'a, Is<VolumeRider>>, ReadStorage<'a, Is<VolumeRider>>,
); );
type DeleteData<'a> = ( type DeleteData<'a> = (
Read<'a, UidAllocator>, Read<'a, UidAllocator>,
WriteStorage<'a, Is<Leader>>, WriteStorage<'a, Is<Leader>>,
WriteStorage<'a, Is<Follower>>, WriteStorage<'a, Is<Follower>>,
WriteStorage<'a, comp::Pos>,
WriteStorage<'a, comp::ForceUpdate>,
); );
type Error = TetherError; type Error = TetherError;
type PersistData<'a> = ( type PersistData<'a> = (
Read<'a, UidAllocator>, Read<'a, UidAllocator>,
Entities<'a>, Entities<'a>,
ReadStorage<'a, comp::Health>, ReadStorage<'a, comp::Health>,
ReadStorage<'a, comp::Body>,
ReadStorage<'a, Is<Leader>>, ReadStorage<'a, Is<Leader>>,
ReadStorage<'a, Is<Follower>>, ReadStorage<'a, Is<Follower>>,
ReadStorage<'a, comp::CharacterState>,
); );
fn create( fn create(
@ -72,7 +64,6 @@ impl Link for Tethered {
is_leaders, is_leaders,
is_followers, is_followers,
is_riders, is_riders,
is_mounts,
is_volume_rider, is_volume_rider,
): &mut Self::CreateData<'_>, ): &mut Self::CreateData<'_>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
@ -103,7 +94,7 @@ impl Link for Tethered {
fn persist( fn persist(
this: &LinkHandle<Self>, this: &LinkHandle<Self>,
(uid_allocator, entities, healths, bodies, is_leaders, is_followers, character_states): &mut Self::PersistData<'_>, (uid_allocator, entities, healths, is_leaders, is_followers): &mut Self::PersistData<'_>,
) -> bool { ) -> bool {
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into());
@ -124,9 +115,7 @@ impl Link for Tethered {
fn delete( fn delete(
this: &LinkHandle<Self>, this: &LinkHandle<Self>,
(uid_allocator, is_leaders, is_followers, positions, force_update): &mut Self::DeleteData< (uid_allocator, is_leaders, is_followers): &mut Self::DeleteData<'_>,
'_,
>,
) { ) {
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into());

View File

@ -1,17 +1,16 @@
use common::{ use common::{
comp::{Body, Collider, InputKind, Mass, Ori, Pos, Scale, Vel}, comp::{Body, Mass, Ori, Pos, Scale, Vel},
link::Is, link::Is,
resources::DeltaTime, resources::DeltaTime,
tether::{Follower, Leader}, tether::Follower,
uid::UidAllocator, uid::UidAllocator,
util::Dir, util::Dir,
}; };
use common_ecs::{Job, Origin, Phase, System}; use common_ecs::{Job, Origin, Phase, System};
use specs::{ use specs::{
saveload::{Marker, MarkerAllocator}, saveload::{Marker, MarkerAllocator},
Entities, Join, Read, ReadExpect, ReadStorage, WriteStorage, Entities, Join, Read, ReadStorage, WriteStorage,
}; };
use tracing::error;
use vek::*; use vek::*;
/// This system is responsible for controlling mounts /// This system is responsible for controlling mounts
@ -22,14 +21,12 @@ impl<'a> System<'a> for Sys {
Read<'a, UidAllocator>, Read<'a, UidAllocator>,
Entities<'a>, Entities<'a>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
ReadStorage<'a, Is<Leader>>,
ReadStorage<'a, Is<Follower>>, ReadStorage<'a, Is<Follower>>,
WriteStorage<'a, Pos>, WriteStorage<'a, Pos>,
WriteStorage<'a, Vel>, WriteStorage<'a, Vel>,
WriteStorage<'a, Ori>, WriteStorage<'a, Ori>,
ReadStorage<'a, Body>, ReadStorage<'a, Body>,
ReadStorage<'a, Scale>, ReadStorage<'a, Scale>,
ReadStorage<'a, Collider>,
ReadStorage<'a, Mass>, ReadStorage<'a, Mass>,
); );
@ -43,19 +40,17 @@ impl<'a> System<'a> for Sys {
uid_allocator, uid_allocator,
entities, entities,
dt, dt,
is_leaders,
is_followers, is_followers,
mut positions, positions,
mut velocities, mut velocities,
mut orientations, mut orientations,
bodies, bodies,
scales, scales,
colliders,
masses, masses,
): Self::SystemData, ): Self::SystemData,
) { ) {
for (follower, is_follower, follower_body) in for (follower, is_follower, follower_body, scale) in
(&entities, &is_followers, bodies.maybe()).join() (&entities, &is_followers, bodies.maybe(), scales.maybe()).join()
{ {
let Some(leader) = uid_allocator let Some(leader) = uid_allocator
.retrieve_entity_internal(is_follower.leader.id()) .retrieve_entity_internal(is_follower.leader.id())
@ -75,13 +70,15 @@ impl<'a> System<'a> for Sys {
let tether_offset = orientations let tether_offset = orientations
.get(follower) .get(follower)
.map(|ori| { .map(|ori| {
ori.to_quat() * follower_body.map(|b| b.tether_offset()).unwrap_or_default() ori.to_quat()
* follower_body
.map(|b| b.tether_offset() * scale.copied().unwrap_or(Scale(1.0)).0)
.unwrap_or_default()
}) })
.unwrap_or_default(); .unwrap_or_default();
let tether_pos = follower_pos.0 + tether_offset; let tether_pos = follower_pos.0 + tether_offset;
let pull_factor = (leader_pos.0.distance(tether_pos) - is_follower.tether_length) let pull_factor =
.clamp(0.0, 1.0) (leader_pos.0.distance(tether_pos) - is_follower.tether_length).max(0.0);
.powf(2.0);
let strength = pull_factor * 50000.0; let strength = pull_factor * 50000.0;
let pull_dir = (leader_pos.0 - follower_pos.0) let pull_dir = (leader_pos.0 - follower_pos.0)
.try_normalized() .try_normalized()
@ -93,9 +90,10 @@ impl<'a> System<'a> for Sys {
velocities.get_mut(leader).unwrap().0 -= impulse / leader_mass.0; velocities.get_mut(leader).unwrap().0 -= impulse / leader_mass.0;
if let Some(follower_ori) = orientations.get_mut(follower) { if let Some(follower_ori) = orientations.get_mut(follower) {
let turn_strength = pull_factor.min(0.2) let turn_strength = pull_factor
// * (tether_offset.magnitude() - tether_offset.dot(pull_dir).abs()) * (tether_offset.magnitude() * (leader_pos.0 - tether_pos).magnitude()
* 50.0; - tether_offset.dot(leader_pos.0 - tether_pos).abs())
* 2.0;
let target_ori = follower_ori.yawed_towards(Dir::new(pull_dir)); let target_ori = follower_ori.yawed_towards(Dir::new(pull_dir));
*follower_ori = follower_ori.slerped_towards(target_ori, turn_strength * dt.0); *follower_ori = follower_ori.slerped_towards(target_ori, turn_strength * dt.0);
} }

View File

@ -1778,7 +1778,7 @@ fn handle_spawn_ship(
args: Vec<String>, args: Vec<String>,
_action: &ServerChatCommand, _action: &ServerChatCommand,
) -> CmdResult<()> { ) -> CmdResult<()> {
let (body_name, angle, tethered) = parse_cmd_args!(args, String, f32, bool); let (body_name, tethered, angle) = parse_cmd_args!(args, String, bool, f32);
let mut pos = position(server, target, "target")?; let mut pos = position(server, target, "target")?;
pos.0.z += 2.0; pos.0.z += 2.0;
const DESTINATION_RADIUS: f32 = 2000.0; const DESTINATION_RADIUS: f32 = 2000.0;
@ -1798,15 +1798,15 @@ fn handle_spawn_ship(
.state .state
.create_ship(pos, ori, ship, |ship| ship.make_collider()); .create_ship(pos, ori, ship, |ship| ship.make_collider());
// if let Some(pos) = destination { if let Some(pos) = destination {
// let (kp, ki, kd) = let (kp, ki, kd) =
// comp::agent::pid_coefficients(&comp::Body::Ship(ship)).unwrap_or((1. comp::agent::pid_coefficients(&comp::Body::Ship(ship)).unwrap_or((1.0, 0.0, 0.0));
// 0, 0.0, 0.0)); fn pure_z(sp: Vec3<f32>, pv: Vec3<f32>) -> f32 { (sp - fn pure_z(sp: Vec3<f32>, pv: Vec3<f32>) -> f32 { (sp - pv).z }
// pv).z } let agent = comp::Agent::from_body(&comp::Body::Ship(ship)) let agent = comp::Agent::from_body(&comp::Body::Ship(ship))
// .with_destination(pos) .with_destination(pos)
// .with_position_pid_controller(comp::PidController::new(kp, ki, kd, .with_position_pid_controller(comp::PidController::new(kp, ki, kd, pos, 0.0, pure_z));
// pos, 0.0, pure_z)); builder = builder.with(agent); builder = builder.with(agent);
// } }
let new_entity = builder.build(); let new_entity = builder.build();