mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'isse/rtsim_fixes' into 'master'
Somewhat fix airships See merge request veloren/veloren!3869
This commit is contained in:
commit
913eda4b7f
@ -880,7 +880,7 @@ impl Body {
|
||||
Body::BirdLarge(_) => 50.0,
|
||||
Body::BirdMedium(_) => 40.0,
|
||||
Body::Dragon(_) => 60.0,
|
||||
Body::Ship(ship) if ship.can_fly() => 60.0,
|
||||
Body::Ship(ship) => ship.flying_height(),
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,8 @@ impl Body {
|
||||
matches!(self, Body::DefaultAirship | Body::AirBalloon | Body::Volume)
|
||||
}
|
||||
|
||||
pub fn flying_height(&self) -> f32 { if self.can_fly() { 200.0 } else { 0.0 } }
|
||||
|
||||
pub fn has_water_thrust(&self) -> bool {
|
||||
!self.can_fly() // TODO: Differentiate this more carefully
|
||||
}
|
||||
|
@ -227,6 +227,7 @@ pub enum ServerEvent {
|
||||
},
|
||||
CreateShip {
|
||||
pos: Pos,
|
||||
ori: Ori,
|
||||
ship: comp::ship::Body,
|
||||
rtsim_entity: Option<RtSimVehicle>,
|
||||
driver: Option<NpcBuilder>,
|
||||
|
@ -466,7 +466,9 @@ impl Chaser {
|
||||
/*if traversal_cfg.can_fly {
|
||||
Some(((tgt - pos) , 1.0))
|
||||
} else */
|
||||
if !walking_towards_edge || traversal_cfg.can_fly {
|
||||
if traversal_cfg.can_fly {
|
||||
Some(((tgt - pos) * Vec3::new(1.0, 1.0, 0.5), 1.0))
|
||||
} else if !walking_towards_edge {
|
||||
Some(((tgt - pos) * Vec3::new(1.0, 1.0, 0.0), 1.0))
|
||||
} else {
|
||||
// This is unfortunately where an NPC will stare blankly
|
||||
|
@ -262,6 +262,7 @@ pub enum VehicleKind {
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Vehicle {
|
||||
pub wpos: Vec3<f32>,
|
||||
pub dir: Vec2<f32>,
|
||||
|
||||
pub body: comp::ship::Body,
|
||||
|
||||
@ -283,6 +284,7 @@ impl Vehicle {
|
||||
pub fn new(wpos: Vec3<f32>, body: comp::ship::Body) -> Self {
|
||||
Self {
|
||||
wpos,
|
||||
dir: Vec2::unit_y(),
|
||||
body,
|
||||
chunk_pos: None,
|
||||
driver: None,
|
||||
@ -295,10 +297,10 @@ impl Vehicle {
|
||||
/// Max speed in block/s
|
||||
pub fn get_speed(&self) -> f32 {
|
||||
match self.body {
|
||||
comp::ship::Body::DefaultAirship => 15.0,
|
||||
comp::ship::Body::AirBalloon => 16.0,
|
||||
comp::ship::Body::SailBoat => 12.0,
|
||||
comp::ship::Body::Galleon => 13.0,
|
||||
comp::ship::Body::DefaultAirship => 7.0,
|
||||
comp::ship::Body::AirBalloon => 8.0,
|
||||
comp::ship::Body::SailBoat => 5.0,
|
||||
comp::ship::Body::Galleon => 6.0,
|
||||
_ => 10.0,
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ fn path_in_site(start: Vec2<i32>, end: Vec2<i32>, site: &site2::Site) -> PathRes
|
||||
TileKind::Empty => 3.0,
|
||||
TileKind::Hazard(_) => 50.0,
|
||||
TileKind::Field => 8.0,
|
||||
TileKind::Plaza | TileKind::Road { .. } | TileKind::Path => 1.0,
|
||||
TileKind::Plaza | TileKind::Road { .. } | TileKind::Path | TileKind::Bridge => 1.0,
|
||||
|
||||
TileKind::Building
|
||||
| TileKind::Castle
|
||||
@ -95,13 +95,14 @@ fn path_in_site(start: Vec2<i32>, end: Vec2<i32>, site: &site2::Site) -> PathRes
|
||||
distance * terrain + building
|
||||
};
|
||||
|
||||
astar.poll(
|
||||
1000,
|
||||
heuristic,
|
||||
|&tile| CARDINALS.iter().map(move |c| tile + *c),
|
||||
transition,
|
||||
|tile| *tile == end || site.tiles.get_known(*tile).is_none(),
|
||||
)
|
||||
let neighbors = |tile: &Vec2<i32>| {
|
||||
let tile = *tile;
|
||||
CARDINALS.iter().map(move |c| tile + *c)
|
||||
};
|
||||
|
||||
astar.poll(1000, heuristic, neighbors, transition, |tile| {
|
||||
*tile == end || site.tiles.get_known(*tile).is_none()
|
||||
})
|
||||
}
|
||||
|
||||
fn path_between_sites(
|
||||
@ -136,23 +137,23 @@ fn path_between_sites(
|
||||
|
||||
let neighbors = |site: &Id<civ::Site>| world.civs().neighbors(*site);
|
||||
|
||||
let track_between = |a: Id<civ::Site>, b: Id<civ::Site>| {
|
||||
let transition = |a: &Id<civ::Site>, b: &Id<civ::Site>| {
|
||||
world
|
||||
.civs()
|
||||
.tracks
|
||||
.get(world.civs().track_between(a, b).unwrap().0)
|
||||
.track_between(*a, *b)
|
||||
.map(|(id, _)| world.civs().tracks.get(id).cost)
|
||||
.unwrap_or(f32::INFINITY)
|
||||
};
|
||||
|
||||
let transition = |a: &Id<civ::Site>, b: &Id<civ::Site>| track_between(*a, *b).cost;
|
||||
|
||||
let path = astar.poll(250, heuristic, neighbors, transition, |site| *site == end);
|
||||
|
||||
path.map(|path| {
|
||||
let path = path
|
||||
.into_iter()
|
||||
.tuple_windows::<(_, _)>()
|
||||
.map(|(a, b)| world.civs().track_between(a, b).unwrap())
|
||||
.collect_vec();
|
||||
// Since we get a, b from neighbors, track_between shouldn't return None.
|
||||
.filter_map(|(a, b)| world.civs().track_between(a, b))
|
||||
.collect();
|
||||
Path { nodes: path }
|
||||
})
|
||||
}
|
||||
@ -279,13 +280,9 @@ fn idle() -> impl Action { just(|ctx| ctx.controller.do_idle()).debug(|| "idle")
|
||||
fn goto(wpos: Vec3<f32>, speed_factor: f32, goal_dist: f32) -> impl Action {
|
||||
const STEP_DIST: f32 = 24.0;
|
||||
const WAYPOINT_DIST: f32 = 12.0;
|
||||
|
||||
let mut waypoint = None;
|
||||
|
||||
just(move |ctx| {
|
||||
let rpos = wpos - ctx.npc.wpos;
|
||||
let len = rpos.magnitude();
|
||||
|
||||
// If we're close to the next waypoint, complete it
|
||||
if waypoint.map_or(false, |waypoint: Vec3<f32>| {
|
||||
ctx.npc.wpos.xy().distance_squared(waypoint.xy()) < WAYPOINT_DIST.powi(2)
|
||||
@ -295,6 +292,8 @@ fn goto(wpos: Vec3<f32>, speed_factor: f32, goal_dist: f32) -> impl Action {
|
||||
|
||||
// Get the next waypoint on the route toward the goal
|
||||
let waypoint = waypoint.get_or_insert_with(|| {
|
||||
let rpos = wpos - ctx.npc.wpos;
|
||||
let len = rpos.magnitude();
|
||||
let wpos = ctx.npc.wpos + (rpos / len) * len.min(STEP_DIST);
|
||||
|
||||
wpos.with_z(
|
||||
@ -313,6 +312,49 @@ fn goto(wpos: Vec3<f32>, speed_factor: f32, goal_dist: f32) -> impl Action {
|
||||
.map(|_| {})
|
||||
}
|
||||
|
||||
/// Try to walk fly a 3D position following the terrain altitude at an offset
|
||||
/// without caring for obstacles.
|
||||
fn goto_flying(
|
||||
wpos: Vec3<f32>,
|
||||
speed_factor: f32,
|
||||
goal_dist: f32,
|
||||
step_dist: f32,
|
||||
waypoint_dist: f32,
|
||||
height_offset: f32,
|
||||
) -> impl Action {
|
||||
let mut waypoint = None;
|
||||
|
||||
just(move |ctx| {
|
||||
// If we're close to the next waypoint, complete it
|
||||
if waypoint.map_or(false, |waypoint: Vec3<f32>| {
|
||||
ctx.npc.wpos.distance_squared(waypoint) < waypoint_dist.powi(2)
|
||||
}) {
|
||||
waypoint = None;
|
||||
}
|
||||
|
||||
// Get the next waypoint on the route toward the goal
|
||||
let waypoint = waypoint.get_or_insert_with(|| {
|
||||
let rpos = wpos - ctx.npc.wpos;
|
||||
let len = rpos.magnitude();
|
||||
let wpos = ctx.npc.wpos + (rpos / len) * len.min(step_dist);
|
||||
|
||||
wpos.with_z(
|
||||
ctx.world
|
||||
.sim()
|
||||
.get_surface_alt_approx(wpos.xy().as_())
|
||||
.map(|alt| alt + height_offset)
|
||||
.unwrap_or(wpos.z),
|
||||
)
|
||||
});
|
||||
|
||||
ctx.controller.do_goto(*waypoint, speed_factor);
|
||||
})
|
||||
.repeat()
|
||||
.stop_if(move |ctx| ctx.npc.wpos.xy().distance_squared(wpos.xy()) < goal_dist.powi(2))
|
||||
.debug(move || format!("goto {}, {}, {}", wpos.x, wpos.y, wpos.z))
|
||||
.map(|_| {})
|
||||
}
|
||||
|
||||
/// Try to walk toward a 2D position on the terrain without caring for
|
||||
/// obstacles.
|
||||
fn goto_2d(wpos2d: Vec2<f32>, speed_factor: f32, goal_dist: f32) -> impl Action {
|
||||
@ -322,6 +364,30 @@ fn goto_2d(wpos2d: Vec2<f32>, speed_factor: f32, goal_dist: f32) -> impl Action
|
||||
})
|
||||
}
|
||||
|
||||
/// Try to fly toward a 2D position following the terrain altitude at an offset
|
||||
/// without caring for obstacles.
|
||||
fn goto_2d_flying(
|
||||
wpos2d: Vec2<f32>,
|
||||
speed_factor: f32,
|
||||
goal_dist: f32,
|
||||
step_dist: f32,
|
||||
waypoint_dist: f32,
|
||||
height_offset: f32,
|
||||
) -> impl Action {
|
||||
now(move |ctx| {
|
||||
let wpos = wpos2d
|
||||
.with_z(ctx.world.sim().get_alt_approx(wpos2d.as_()).unwrap_or(0.0) + height_offset);
|
||||
goto_flying(
|
||||
wpos,
|
||||
speed_factor,
|
||||
goal_dist,
|
||||
step_dist,
|
||||
waypoint_dist,
|
||||
height_offset,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn traverse_points<F>(mut next_point: F, speed_factor: f32) -> impl Action
|
||||
where
|
||||
F: FnMut(&mut NpcCtx) -> Option<Vec2<f32>> + Send + Sync + 'static,
|
||||
@ -345,7 +411,7 @@ where
|
||||
|
||||
if let Some(path) = path_site(wpos, site_exit, site, ctx.index) {
|
||||
Some(Either::Left(
|
||||
seq(path.into_iter().map(|wpos| goto_2d(wpos, 1.0, 8.0))).then(goto_2d(
|
||||
seq(path.into_iter().map(move |wpos| goto_2d(wpos, 1.0, 8.0))).then(goto_2d(
|
||||
site_exit,
|
||||
speed_factor,
|
||||
8.0,
|
||||
@ -821,53 +887,9 @@ fn follow(npc: NpcId, distance: f32) -> impl Action {
|
||||
}
|
||||
*/
|
||||
|
||||
fn chunk_path(
|
||||
from: Vec2<i32>,
|
||||
to: Vec2<i32>,
|
||||
chunk_height: impl Fn(Vec2<i32>) -> Option<i32>,
|
||||
) -> Box<dyn Action> {
|
||||
let heuristics =
|
||||
|(p, _): &(Vec2<i32>, i32), _: &(Vec2<i32>, i32)| p.distance_squared(to) as f32;
|
||||
let start = (from, chunk_height(from).unwrap());
|
||||
let mut astar = Astar::new(1000, start, BuildHasherDefault::<FxHasher64>::default());
|
||||
|
||||
let path = astar.poll(
|
||||
1000,
|
||||
heuristics,
|
||||
|&(p, _)| {
|
||||
NEIGHBORS
|
||||
.into_iter()
|
||||
.map(move |n| p + n)
|
||||
.filter_map(|p| Some((p, chunk_height(p)?)))
|
||||
},
|
||||
|(p0, h0), (p1, h1)| {
|
||||
let diff = (p0 - p1).as_().cpos_to_wpos().with_z((h0 - h1) as f32);
|
||||
|
||||
diff.magnitude_squared()
|
||||
},
|
||||
|(e, _)| *e == to,
|
||||
);
|
||||
let path = match path {
|
||||
PathResult::Exhausted(p) | PathResult::Path(p) => p,
|
||||
_ => return finish().boxed(),
|
||||
};
|
||||
let len = path.len();
|
||||
seq(path
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(move |(i, (chunk_pos, height))| {
|
||||
let wpos = TerrainChunkSize::center_wpos(chunk_pos)
|
||||
.with_z(height)
|
||||
.as_();
|
||||
goto(wpos, 1.0, 5.0)
|
||||
.debug(move || format!("chunk path {i}/{len} chunk: {chunk_pos}, height: {height}"))
|
||||
}))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn pilot() -> impl Action {
|
||||
fn pilot(ship: common::comp::ship::Body) -> impl Action {
|
||||
// Travel between different towns in a straight line
|
||||
now(|ctx| {
|
||||
now(move |ctx| {
|
||||
let data = &*ctx.state.data();
|
||||
let site = data
|
||||
.sites
|
||||
@ -880,16 +902,19 @@ fn pilot() -> impl Action {
|
||||
})
|
||||
.choose(&mut ctx.rng);
|
||||
if let Some((_id, site)) = site {
|
||||
let start_chunk = ctx.npc.wpos.xy().as_().wpos_to_cpos();
|
||||
let end_chunk = site.wpos.wpos_to_cpos();
|
||||
chunk_path(start_chunk, end_chunk, |chunk| {
|
||||
ctx.world
|
||||
.sim()
|
||||
.get_alt_approx(TerrainChunkSize::center_wpos(chunk))
|
||||
.map(|f| (f + 150.0) as i32)
|
||||
})
|
||||
Either::Right(
|
||||
goto_2d_flying(
|
||||
site.wpos.as_(),
|
||||
1.0,
|
||||
50.0,
|
||||
150.0,
|
||||
110.0,
|
||||
ship.flying_height(),
|
||||
)
|
||||
.then(goto_2d_flying(site.wpos.as_(), 1.0, 10.0, 32.0, 16.0, 10.0)),
|
||||
)
|
||||
} else {
|
||||
finish().boxed()
|
||||
Either::Left(finish())
|
||||
}
|
||||
})
|
||||
.repeat()
|
||||
@ -990,7 +1015,7 @@ fn humanoid() -> impl Action {
|
||||
if let Some(vehicle) = ctx.state.data().npcs.vehicles.get(riding.vehicle) {
|
||||
match vehicle.body {
|
||||
common::comp::ship::Body::DefaultAirship
|
||||
| common::comp::ship::Body::AirBalloon => important(pilot()),
|
||||
| common::comp::ship::Body::AirBalloon => important(pilot(vehicle.body)),
|
||||
common::comp::ship::Body::SailBoat | common::comp::ship::Body::Galleon => {
|
||||
important(captain())
|
||||
},
|
||||
@ -1024,6 +1049,16 @@ fn bird_large() -> impl Action {
|
||||
let data = ctx.state.data();
|
||||
if let Some(home) = ctx.npc.home {
|
||||
let is_home = ctx.npc.current_site.map_or(false, |site| home == site);
|
||||
let goto = |wpos| {
|
||||
casual(goto_2d_flying(
|
||||
wpos,
|
||||
1.0,
|
||||
20.0,
|
||||
32.0,
|
||||
22.0,
|
||||
ctx.npc.body.flying_height(),
|
||||
))
|
||||
};
|
||||
if is_home {
|
||||
if let Some((_, site)) = data
|
||||
.sites
|
||||
@ -1036,32 +1071,12 @@ fn bird_large() -> impl Action {
|
||||
})
|
||||
.choose(&mut ctx.rng)
|
||||
{
|
||||
casual(goto(
|
||||
site.wpos.as_::<f32>().with_z(
|
||||
ctx.world
|
||||
.sim()
|
||||
.get_surface_alt_approx(site.wpos)
|
||||
.unwrap_or(0.0)
|
||||
+ ctx.npc.body.flying_height(),
|
||||
),
|
||||
1.0,
|
||||
20.0,
|
||||
))
|
||||
goto(site.wpos.as_::<f32>())
|
||||
} else {
|
||||
casual(idle())
|
||||
}
|
||||
} else if let Some(site) = data.sites.get(home) {
|
||||
casual(goto(
|
||||
site.wpos.as_::<f32>().with_z(
|
||||
ctx.world
|
||||
.sim()
|
||||
.get_surface_alt_approx(site.wpos)
|
||||
.unwrap_or(0.0)
|
||||
+ ctx.npc.body.flying_height(),
|
||||
),
|
||||
1.0,
|
||||
20.0,
|
||||
))
|
||||
goto(site.wpos.as_::<f32>())
|
||||
} else {
|
||||
casual(idle())
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use common::{
|
||||
use rand::prelude::*;
|
||||
use rand_chacha::ChaChaRng;
|
||||
use tracing::{error, warn};
|
||||
use vek::Vec2;
|
||||
use world::site::SiteKind;
|
||||
|
||||
pub struct SimulateNpcs;
|
||||
@ -166,12 +167,11 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
||||
let dist2 = diff.magnitude_squared();
|
||||
|
||||
if dist2 > 0.5f32.powi(2) {
|
||||
let mut wpos = vehicle.wpos
|
||||
let wpos = vehicle.wpos
|
||||
+ (diff
|
||||
* (vehicle.get_speed() * speed_factor * ctx.event.dt
|
||||
/ dist2.sqrt())
|
||||
.min(1.0))
|
||||
.with_z(0.0);
|
||||
.min(1.0));
|
||||
|
||||
let is_valid = match vehicle.body {
|
||||
common::comp::ship::Body::DefaultAirship
|
||||
@ -188,33 +188,11 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
||||
};
|
||||
|
||||
if is_valid {
|
||||
match vehicle.body {
|
||||
common::comp::ship::Body::DefaultAirship
|
||||
| common::comp::ship::Body::AirBalloon => {
|
||||
if let Some(alt) = ctx
|
||||
.world
|
||||
.sim()
|
||||
.get_alt_approx(wpos.xy().as_())
|
||||
.filter(|alt| wpos.z < *alt)
|
||||
{
|
||||
wpos.z = alt;
|
||||
}
|
||||
},
|
||||
common::comp::ship::Body::SailBoat
|
||||
| common::comp::ship::Body::Galleon => {
|
||||
wpos.z = ctx
|
||||
.world
|
||||
.sim()
|
||||
.get_interpolated(
|
||||
wpos.xy().map(|e| e as i32),
|
||||
|chunk| chunk.water_alt,
|
||||
)
|
||||
.unwrap_or(0.0);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
vehicle.wpos = wpos;
|
||||
}
|
||||
vehicle.dir = (target.xy() - vehicle.wpos.xy())
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::unit_y());
|
||||
}
|
||||
},
|
||||
// When riding, other actions are disabled
|
||||
@ -264,7 +242,6 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
||||
NpcAction::Attack(_) => {}, // TODO: Implement simulated combat
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure NPCs remain on the surface
|
||||
npc.wpos.z = ctx
|
||||
.world
|
||||
|
@ -247,7 +247,7 @@ impl<'a> AgentData<'a> {
|
||||
self.vel.0,
|
||||
chase_tgt,
|
||||
TraversalConfig {
|
||||
min_tgt_dist: 1.25,
|
||||
min_tgt_dist: self.traversal_config.min_tgt_dist * 1.25,
|
||||
..self.traversal_config
|
||||
},
|
||||
) {
|
||||
|
@ -1572,19 +1572,14 @@ fn handle_spawn_airship(
|
||||
pos.0.z += 50.0;
|
||||
const DESTINATION_RADIUS: f32 = 2000.0;
|
||||
let angle = angle.map(|a| a * std::f32::consts::PI / 180.0);
|
||||
let destination = angle.map(|a| {
|
||||
pos.0
|
||||
+ Vec3::new(
|
||||
DESTINATION_RADIUS * a.cos(),
|
||||
DESTINATION_RADIUS * a.sin(),
|
||||
200.0,
|
||||
)
|
||||
});
|
||||
let dir = angle.map(|a| Vec3::new(a.cos(), a.sin(), 0.0));
|
||||
let destination = dir.map(|dir| pos.0 + dir * DESTINATION_RADIUS + Vec3::new(0.0, 0.0, 200.0));
|
||||
let mut rng = thread_rng();
|
||||
let ship = comp::ship::Body::random_airship_with(&mut rng);
|
||||
let ori = comp::Ori::from(common::util::Dir::new(dir.unwrap_or(Vec3::unit_y())));
|
||||
let mut builder = server
|
||||
.state
|
||||
.create_ship(pos, ship, |ship| ship.make_collider())
|
||||
.create_ship(pos, ori, ship, |ship| ship.make_collider())
|
||||
.with(LightEmitter {
|
||||
col: Rgb::new(1.0, 0.65, 0.2),
|
||||
strength: 2.0,
|
||||
@ -1621,19 +1616,14 @@ fn handle_spawn_ship(
|
||||
pos.0.z += 50.0;
|
||||
const DESTINATION_RADIUS: f32 = 2000.0;
|
||||
let angle = angle.map(|a| a * std::f32::consts::PI / 180.0);
|
||||
let destination = angle.map(|a| {
|
||||
pos.0
|
||||
+ Vec3::new(
|
||||
DESTINATION_RADIUS * a.cos(),
|
||||
DESTINATION_RADIUS * a.sin(),
|
||||
200.0,
|
||||
)
|
||||
});
|
||||
let dir = angle.map(|a| Vec3::new(a.cos(), a.sin(), 0.0));
|
||||
let destination = dir.map(|dir| pos.0 + dir * DESTINATION_RADIUS + Vec3::new(0.0, 0.0, 200.0));
|
||||
let mut rng = thread_rng();
|
||||
let ship = comp::ship::Body::random_ship_with(&mut rng);
|
||||
let ori = comp::Ori::from(common::util::Dir::new(dir.unwrap_or(Vec3::unit_y())));
|
||||
let mut builder = server
|
||||
.state
|
||||
.create_ship(pos, ship, |ship| ship.make_collider())
|
||||
.create_ship(pos, ori, ship, |ship| ship.make_collider())
|
||||
.with(LightEmitter {
|
||||
col: Rgb::new(1.0, 0.65, 0.2),
|
||||
strength: 2.0,
|
||||
@ -1683,9 +1673,12 @@ fn handle_make_volume(
|
||||
};
|
||||
server
|
||||
.state
|
||||
.create_ship(comp::Pos(pos.0 + Vec3::unit_z() * 50.0), ship, move |_| {
|
||||
collider
|
||||
})
|
||||
.create_ship(
|
||||
comp::Pos(pos.0 + Vec3::unit_z() * 50.0),
|
||||
comp::Ori::default(),
|
||||
ship,
|
||||
move |_| collider,
|
||||
)
|
||||
.build();
|
||||
|
||||
server.notify_client(
|
||||
|
@ -194,6 +194,7 @@ pub fn handle_create_npc(server: &mut Server, pos: Pos, mut npc: NpcBuilder) ->
|
||||
pub fn handle_create_ship(
|
||||
server: &mut Server,
|
||||
pos: Pos,
|
||||
ori: Ori,
|
||||
ship: comp::ship::Body,
|
||||
rtsim_vehicle: Option<RtSimVehicle>,
|
||||
driver: Option<NpcBuilder>,
|
||||
@ -201,7 +202,7 @@ pub fn handle_create_ship(
|
||||
) {
|
||||
let mut entity = server
|
||||
.state
|
||||
.create_ship(pos, ship, |ship| ship.make_collider());
|
||||
.create_ship(pos, ori, ship, |ship| ship.make_collider());
|
||||
/*
|
||||
if let Some(mut agent) = agent {
|
||||
let (kp, ki, kd) = pid_coefficients(&Body::Ship(ship));
|
||||
|
@ -193,10 +193,11 @@ impl Server {
|
||||
},
|
||||
ServerEvent::CreateShip {
|
||||
pos,
|
||||
ori,
|
||||
ship,
|
||||
rtsim_entity,
|
||||
driver,
|
||||
} => handle_create_ship(self, pos, ship, rtsim_entity, driver, Vec::new()),
|
||||
} => handle_create_ship(self, pos, ori, ship, rtsim_entity, driver, Vec::new()),
|
||||
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
|
||||
ServerEvent::ClientDisconnect(entity, reason) => {
|
||||
frontend_events.push(handle_client_disconnect(self, entity, reason, false))
|
||||
|
@ -11,6 +11,7 @@ use common::{
|
||||
slowjob::SlowJobPool,
|
||||
terrain::CoordinateConversions,
|
||||
trade::{Good, SiteInformation},
|
||||
util::Dir,
|
||||
LoadoutBuilder,
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
@ -315,6 +316,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
emitter.emit(ServerEvent::CreateShip {
|
||||
pos: comp::Pos(vehicle.wpos),
|
||||
ori: comp::Ori::from(Dir::new(vehicle.dir.with_z(0.0))),
|
||||
ship: vehicle.body,
|
||||
rtsim_entity: Some(RtSimVehicle(vehicle_id)),
|
||||
driver: vehicle.driver.and_then(&mut actor_info),
|
||||
@ -330,6 +332,8 @@ impl<'a> System<'a> for Sys {
|
||||
// loaded
|
||||
if matches!(npc.mode, SimulationMode::Simulated)
|
||||
&& chunk_states.0.get(chunk).map_or(false, |c| c.is_some())
|
||||
// Riding npcs will be spawned by the vehicle.
|
||||
&& npc.riding.is_none()
|
||||
{
|
||||
npc.mode = SimulationMode::Loaded;
|
||||
let entity_info = get_npc_entity_info(npc, &data.sites, index.as_index_ref());
|
||||
|
@ -64,6 +64,7 @@ pub trait StateExt {
|
||||
fn create_ship<F: FnOnce(comp::ship::Body) -> comp::Collider>(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
ori: comp::Ori,
|
||||
ship: comp::ship::Body,
|
||||
make_collider: F,
|
||||
) -> EcsEntityBuilder;
|
||||
@ -338,6 +339,7 @@ impl StateExt for State {
|
||||
fn create_ship<F: FnOnce(comp::ship::Body) -> comp::Collider>(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
ori: comp::Ori,
|
||||
ship: comp::ship::Body,
|
||||
make_collider: F,
|
||||
) -> EcsEntityBuilder {
|
||||
@ -347,7 +349,7 @@ impl StateExt for State {
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori::default())
|
||||
.with(ori)
|
||||
.with(body.mass())
|
||||
.with(body.density())
|
||||
.with(make_collider(ship))
|
||||
|
@ -107,6 +107,10 @@ impl<'a> System<'a> for Sys {
|
||||
.unwrap_or(entity);
|
||||
|
||||
let moving_body = read_data.bodies.get(moving_entity);
|
||||
let physics_state = read_data
|
||||
.physics_states
|
||||
.get(moving_entity)
|
||||
.unwrap_or(physics_state);
|
||||
|
||||
// Hack, replace with better system when groups are more sophisticated
|
||||
// Override alignment if in a group unless entity is owned already
|
||||
@ -136,7 +140,10 @@ impl<'a> System<'a> for Sys {
|
||||
controller.inputs.look_dir = ori.look_dir();
|
||||
}
|
||||
|
||||
let scale = read_data.scales.get(entity).map_or(1.0, |Scale(s)| *s);
|
||||
let scale = read_data
|
||||
.scales
|
||||
.get(moving_entity)
|
||||
.map_or(1.0, |Scale(s)| *s);
|
||||
|
||||
let glider_equipped = inventory
|
||||
.equipped(EquipSlot::Glider)
|
||||
@ -180,7 +187,7 @@ impl<'a> System<'a> for Sys {
|
||||
slow_factor,
|
||||
on_ground: physics_state.on_ground.is_some(),
|
||||
in_liquid: physics_state.in_liquid().is_some(),
|
||||
min_tgt_dist: 1.0,
|
||||
min_tgt_dist: scale * moving_body.map_or(1.0, |body| body.max_radius()),
|
||||
can_climb: moving_body.map_or(false, Body::can_climb),
|
||||
can_fly: moving_body.map_or(false, |b| b.fly_thrust().is_some()),
|
||||
};
|
||||
|
@ -1067,7 +1067,7 @@ impl Site {
|
||||
});
|
||||
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
kind: TileKind::Bridge,
|
||||
plot: Some(plot),
|
||||
hard_alt: None,
|
||||
});
|
||||
|
@ -191,6 +191,7 @@ pub enum TileKind {
|
||||
Keep(KeepKind),
|
||||
Gate,
|
||||
GnarlingFortification,
|
||||
Bridge,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
|
Loading…
Reference in New Issue
Block a user