Merge pull request #8736 from TheMrZZ/fix/noai-ravager-counters

🤖 Agent: the NoAI branch now runs ravager::ai_step after ageable_step, as Ravager.aiStep does outside serverAiStep. The corpus group pins the stun-to-roar boundary at tick 2 for both AI modes.
This commit is contained in:
Ludovic Marie authored and GitHub committed 2026-11-04 08:17:53 +01:00
commit 69ab59ef00
2 files changed
+80

No files matched your search

+54
View File
@@ -668,6 +668,11 @@ pub fn tick(
if horse {
super::equine::ai_step(m, w, events);
}
// Ravager.aiStep runs outside serverAiStep: NoAI still advances
// attack/stun/roar, including the stun-to-roar transition.
if m.species() == Species::Ravager {
super::ravager::ai_step(m, w, events);
}
} else {
ai_step(m, w, level_random, events);
}
@@ -4390,3 +4395,52 @@ mod iron_golem_push_tests {
}
}
}
#[cfg(test)]
mod ravager_noai_tests {
use super::*;
use std::sync::Arc;
#[test]
fn ravager_counters_tick_without_ai_and_stun_starts_a_full_roar() {
crate::mobs::world::with_test_world(&[], |w, types| {
for no_ai in [false, true] {
for initial in [(20, 30, 5), (0, 0, 0), (-2, -3, -4), (2, 2, 0)] {
let kind = Arc::new(types.types["minecraft:ravager"].clone());
let mut mob = Mob::new(1, kind, Vec3::new(10.5, 200.0, 10.5), 0.0);
mob.no_ai = no_ai;
mob.no_gravity = true;
mob.persistent = true;
mob.extra.counter = initial.0;
mob.extra.counter2 = initial.1;
mob.extra.anim_ticks = initial.2;
let mut random = LegacyRandom::new(0);
let mut events = Vec::new();
for elapsed in 1..=22 {
tick(&mut mob, w, &mut random, &mut events);
let attack = if initial.0 > 0 {
(initial.0 - elapsed).max(0)
} else {
initial.0
};
let stun = if initial.1 > 0 {
(initial.1 - elapsed).max(0)
} else {
initial.1
};
let roar = match initial {
(20, 30, 5) => (5 - elapsed).max(0),
(2, 2, 0) if elapsed >= 2 => (22 - elapsed).max(0),
_ => initial.2,
};
assert_eq!(
(mob.extra.counter, mob.extra.counter2, mob.extra.anim_ticks),
(attack, stun, roar),
"NoAI={no_ai}, initial={initial:?}, tick={elapsed}"
);
}
}
}
});
}
}
+26
View File
@@ -2377,6 +2377,31 @@ def creeper_custom_fuse():
return ops + setup('/gamerule mob_griefing true')
def ravager_noai_counters():
ops = setup('/difficulty normal', '/gamerule spawn_mobs false',
'/gamerule mob_griefing false', '/forceload add 0 0 31 31',
'/fill 0 199 0 15 199 15 stone', '/fill 0 200 0 15 206 15 air')
case = 0
for no_ai in (0, 1):
for attack, stun, roar in ((20, 30, 5), (0, 0, 0), (-2, -3, -4), (2, 2, 0)):
case += 1
tag = f'h179_{case}'
target = f'@e[type=minecraft:ravager,tag={tag},limit=1]'
ops += setup('/summon ravager 10.5 200 10.5 '
f'{{Tags:["{tag}"],NoAI:{no_ai}b,NoGravity:1b,Silent:1b,'
f'PersistenceRequired:1b,AttackTick:{attack},StunTick:{stun},RoarTick:{roar}}}')
elapsed = 0
for tick in (0, 1, 2, 3, 10, 12, 22):
if tick > elapsed:
ops.append({'op': 'tick', 'n': tick - elapsed})
ops.append(cmd(f'/execute if entity {target}'))
for field in ('AttackTick', 'StunTick', 'RoarTick'):
ops.append(cmd(f'/data get entity {target} {field}'))
elapsed = tick
ops += setup(f'/kill {target}')
return ops + setup('/gamerule mob_griefing true', '/forceload remove 0 0 31 31')
def groups():
return [
('setup', group_setup()),
@@ -2389,6 +2414,7 @@ def groups():
('setblock destroy air', setblock_destroy_air()),
('forceload query order', forceload_query_order()),
('entities', entities()),
('ravager NoAI counters', ravager_noai_counters()),
('aquatic FromBucket', aquatic_from_bucket()),
('villager command names', villager_command_names()),
('item lifetime counters', item_lifetime_counters()),