Hurt crammed mobs by 6 at the max entity cramming limit

Mobs only drew the cramming random and never took damage, so a crowd was never thinned. Vanilla's LivingEntity.pushEntities hurts a mob by 6 on a quarter of the ticks while max_entity_cramming or more non-riding entities are pushable around it.
This commit is contained in:
Kacpherek committed 2026-10-28 10:47:13 +01:00
1 parent b6c936f82b
commit f6b467eba9
4 files changed
+25 -8

No files matched your search

@@ -1121,6 +1121,7 @@ pub fn main() -> horizon_client::Result<()> {
biomes: &biomes,
mob_griefing: true,
mob_drops: true,
max_entity_cramming: 24,
difficulty: LocalDifficulty::new(s.difficulty, world.day_time, 0, 0.0),
end: false,
world_seed: 0,
@@ -456,6 +456,7 @@ impl Game<'_> {
biomes: self.res.biomes(),
mob_griefing: self.ui.rules.bool("mob_griefing"),
mob_drops: self.ui.rules.bool("mob_drops"),
max_entity_cramming: self.ui.rules.int("max_entity_cramming"),
end: self.dim == Dim::End,
world_seed: self.level.seed,
sea_level: if self.dim == Dim::Nether { 32 } else { 63 },
@@ -4561,6 +4562,7 @@ pub(super) fn damage_type(kind: horizon_client::mobs::DamageKind, player: bool)
K::SonicBoom => "minecraft:sonic_boom",
K::Freeze => "minecraft:freeze",
K::OutOfWorld => "minecraft:out_of_world",
K::Cramming => "minecraft:cramming",
}
}
/// A Horizon item stack as a loot stack (id, count, damage, enchantments).
+7
View File
@@ -538,6 +538,8 @@ pub enum DamageKind {
Freeze,
/// `fell_out_of_world`: below the world's floor.
OutOfWorld,
/// `cramming`: too many entities in one place (`maxEntityCramming`).
Cramming,
}
/// A damage source: its type, the attacking entity and where it came from.
#[derive(Clone, Copy, Debug)]
@@ -616,6 +618,7 @@ impl Damage {
| DamageKind::SonicBoom
| DamageKind::Freeze
| DamageKind::OutOfWorld
| DamageKind::Cramming
)
}
pub fn is_fire(&self) -> bool {
@@ -642,6 +645,7 @@ impl Damage {
| DamageKind::InWall
| DamageKind::Freeze
| DamageKind::OutOfWorld
| DamageKind::Cramming
)
}
pub fn is_projectile(&self) -> bool {
@@ -1811,6 +1815,8 @@ pub struct MobWorld<'a> {
pub mob_griefing: bool,
/// The `mob_drops` game rule (`shouldDropLoot`).
pub mob_drops: bool,
/// The `max_entity_cramming` game rule.
pub max_entity_cramming: i32,
/// `getCurrentDifficultyAt` at the mob being ticked (near the player
/// outside the mob tick).
pub difficulty: spawning::LocalDifficulty,
@@ -2183,6 +2189,7 @@ impl Mob {
| DamageKind::InWall
| DamageKind::Thorns
| DamageKind::OutOfWorld
| DamageKind::Cramming
| DamageKind::Generic
)
}
+15 -8
View File
@@ -1058,7 +1058,8 @@ fn push_entities(m: &mut Mob, w: &MobWorld, events: &mut Vec<MobEvent>) {
&& m.species() != Species::Shulker
&& !on_climbable(m, w)
&& (m.species() != Species::Creaking || super::creaking::can_move(m));
let mut targets: Vec<(Who, Vec3)> = Vec::new();
// Each with whether it rides a vehicle (`Entity.isPassenger`).
let mut targets: Vec<(Who, Vec3, bool)> = Vec::new();
if let Some(p) = &w.player
// Entity.push: passengers of the same vehicle never push each other.
&& m.rider.is_none()
@@ -1066,21 +1067,27 @@ fn push_entities(m: &mut Mob, w: &MobWorld, events: &mut Vec<MobEvent>) {
&& !p.spectator
&& p.bounds.intersects(bounds)
{
targets.push((Who::Player, p.position));
targets.push((Who::Player, p.position, p.passenger));
}
for o in w.others_near(bounds) {
if o.id != m.id && o.alive && o.pushable && o.bounds.intersects(bounds) {
targets.push((Who::Mob(o.id), o.position));
targets.push((Who::Mob(o.id), o.position, o.passenger));
}
}
// EntitySelector.pushableBy(this): the teams' collision rules.
let own = w.teams.of(Who::Mob(m.id));
targets.retain(|(who, _)| crate::scoreboard::pushable_by(own, w.teams.of(*who), true));
// Cramming (maxEntityCramming 24).
if targets.len() > 23 {
let _ = m.random.next_int_bound(4);
targets.retain(|(who, ..)| crate::scoreboard::pushable_by(own, w.teams.of(*who), true));
// Cramming: a quarter of the ticks spent with `maxEntityCramming` or more
// others around that are not riding anything hurts it by 6.
let limit = w.max_entity_cramming;
if limit > 0
&& targets.len() as i64 > i64::from(limit) - 1
&& m.random.next_int_bound(4).unwrap_or(1) == 0
&& targets.iter().filter(|t| !t.2).count() as i64 > i64::from(limit) - 1
{
m.damage(6.0, Damage::of(DamageKind::Cramming));
}
for (who, at) in targets {
for (who, at, _) in targets {
// Warden.doPush: touching it angers it, then the push itself.
if m.species() == Species::Warden {
super::warden::do_push(m, w, who, events);