mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Hatch a ghastling with its own setup, not an adult's
DriedGhastBlock.spawnGhastling calls setBaby(true) before addFreshEntity. AgeableMob.setBaby -> setAge crosses the age boundary there, so HappyGhast.ageBoundaryReached runs babyGhastSetup while the mob is still being hatched: its box, its flying navigation and its brain are a ghastling's before it joins the level. Horizon's hatch path wrote extra.age directly after spawn_mob had already registered the adult's goals (HappyGhastFloat, the tempt goal, FloatAround) with a ground navigation and the brain stopped, so the ghastling spent its first tick flying adult goals and only its first aiStep (ensure_setup) corrected that. age_boundary_reached also had no HappyGhast arm, so the crossing ran nothing for it at all. The hatch now goes through finalize::set_age, which dispatches the crossing to happy_ghast::ensure_setup like the other ageable species' ageBoundaryReached arms. The port_map row for HappyGhast.ageBoundaryReached named ensure_setup without the dispatch that reaches it; it now points at the dispatch.
This commit is contained in:
1 parent
7504abf07f
commit
f395135ea5
4 files changed
+48
-2
No files matched your search
@@ -155,7 +155,12 @@ impl Game<'_> {
|
||||
if let Some(id) = self.spawn_mob("minecraft:happy_ghast", at, true)
|
||||
&& let Some(m) = self.mobs.iter_mut().find(|m| m.id == id)
|
||||
{
|
||||
m.extra.age = -24000;
|
||||
// DriedGhastBlock.spawnGhastling sets the baby age before
|
||||
// addFreshEntity, so ageBoundaryReached runs the ghastling setup
|
||||
// (`babyGhastSetup`) while the mob is still being hatched: its
|
||||
// goals, navigation and brain are a ghastling's before its first
|
||||
// tick, not an adult's until the next aiStep.
|
||||
horizon_client::mobs::finalize::set_age(m, -24000);
|
||||
m.yaw = yaw;
|
||||
m.body_yaw = yaw;
|
||||
m.head_yaw = yaw;
|
||||
|
||||
@@ -863,6 +863,11 @@ fn age_boundary_reached(m: &mut Mob) {
|
||||
Species::Goat => set_base(m, Attr::AttackDamage, if baby { 1.0 } else { 2.0 }),
|
||||
Species::Hoglin => set_base(m, Attr::AttackDamage, if baby { 0.5 } else { 6.0 }),
|
||||
Species::SulfurCube if !baby => sulfur_size(m, 2),
|
||||
// HappyGhast.ageBoundaryReached: adultGhastSetup or babyGhastSetup,
|
||||
// then Animal's no-op. A hatched ghastling needs it before it is in
|
||||
// the level (DriedGhastBlock.spawnGhastling sets the baby age before
|
||||
// addFreshEntity), or its first tick flies the adult goals.
|
||||
Species::HappyGhast => super::happy_ghast::ensure_setup(m),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,4 +667,40 @@ mod tests {
|
||||
fn travel_speed_is_five_thirds_of_the_flying_speed() {
|
||||
assert!((f64::from(AIR_SPEED) - FLYING_SPEED * 5.0 / 3.0).abs() < 1e-7);
|
||||
}
|
||||
|
||||
/// `HappyGhast.ageBoundaryReached` runs the setup at the age crossing, not
|
||||
/// at the next tick: `DriedGhastBlock.spawnGhastling` makes its ghastling a
|
||||
/// baby before `addFreshEntity`, and `AgeableMob.setAge` calls
|
||||
/// `ageBoundaryReached` there. Without it the hatched ghastling joins the
|
||||
/// level with the adult's three goals, its ground navigation and its brain
|
||||
/// stopped, and only its first `aiStep` (`ensure_setup`) fixes that.
|
||||
#[test]
|
||||
fn a_hatched_ghastling_is_set_up_as_one_at_the_age_crossing() {
|
||||
use crate::mobs::Species;
|
||||
let mut t = (*crate::mobs::sensor_scan_tests::kind()).clone();
|
||||
t.species = Species::HappyGhast;
|
||||
let mut m = Mob::new(
|
||||
1,
|
||||
std::sync::Arc::new(t),
|
||||
horizon_core::geometry::Vec3::ZERO,
|
||||
0.0,
|
||||
);
|
||||
// `Mob::new` registers the adult's goals (HappyGhastFloat, its tempt
|
||||
// goal and FloatAround) for the age-zero ghast it makes.
|
||||
assert_eq!(m.extra.scratch[0], 2, "an adult's setup at construction");
|
||||
assert!(m.ai.goals.has("HappyGhastFloatGoal"));
|
||||
|
||||
crate::mobs::finalize::set_age(&mut m, -24000);
|
||||
|
||||
assert!(m.is_baby());
|
||||
assert_eq!(m.extra.scratch[0], 1, "babyGhastSetup ran");
|
||||
assert!(
|
||||
!m.ai.goals.has("HappyGhastFloatGoal")
|
||||
&& !m.ai.goals.has("RandomFloatAroundGoal")
|
||||
&& !m.ai.goals.has("ForNonPathfinders"),
|
||||
"a ghastling has no goals: its brain drives it"
|
||||
);
|
||||
assert_eq!(m.ai.nav.kind, crate::mobs::nav::NavKind::Flying);
|
||||
assert!(m.ai.nav.can_float);
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ HappyGhast.setServerStillTimeout inline crates/horizon-client/src/mobs/happy_gha
|
||||
HappyGhast.registerGoals port crates/horizon-client/src/mobs/happy_ghast.rs::setup adult goals: float, tempt (harness and food for a bare adult, food otherwise), float around within 16
|
||||
HappyGhast.adultGhastSetup port crates/horizon-client/src/mobs/happy_ghast.rs::setup adult half: ghast move control, happy ghast look control, goals, brain stopped
|
||||
HappyGhast.babyGhastSetup port crates/horizon-client/src/mobs/happy_ghast.rs::setup baby half: flying move control, baby flying navigation, no goals, timeout cleared
|
||||
HappyGhast.ageBoundaryReached port crates/horizon-client/src/mobs/happy_ghast.rs::ensure_setup reruns setup when the age sign changes
|
||||
HappyGhast.ageBoundaryReached port crates/horizon-client/src/mobs/finalize.rs::age_boundary_reached reruns the setup (happy_ghast::ensure_setup) when the age sign changes, so a hatched ghastling flies its own goals before its first tick
|
||||
HappyGhast.createAttributes skip:data attributes come from entity-types.json
|
||||
HappyGhast.getAmbientSoundInterval port crates/horizon-client/src/mobs.rs::Mob::ambient_interval six times as long while it carries a rider
|
||||
HappyGhast.canUseSlot inline crates/horizon-client/src/game/ghasts.rs::Game::interact_happy_ghast a harness goes only on a living adult without one; shears take it off
|
||||
|
||||
|
Reference in new issue
Block a user