inventory: early return before HashSet alloc, restore doc comments

This commit is contained in:
2026-03-21 21:44:06 +00:00
parent b7b7af5560
commit f52c8ab18c
2 changed files with 46 additions and 4 deletions
+28
View File
@@ -1,4 +1,32 @@
//! PersonalInventory — slots, strength-based carry weight, encumbrance tracking.
//!
//! # Design
//! Every entity that can carry items gets a PersonalInventory. Slot count is
//! species- and age-defined. Weight limit is strength-based.
//!
//! # Weight limit
//! max_carry_weight = BASE_CARRY_WEIGHT + strength * STRENGTH_CARRY_MULTIPLIER
//! + sum(carry_weight_bonus for each Container directly in slots)
//!
//! The bonus from held containers is re-evaluated whenever the slot contents
//! change. It is NOT recursive — containers inside containers do not contribute
//! their bonus to the carrier.
//!
//! # Encumbrance
//! When current_weight > max_carry_weight, the entity is encumbered.
//! The update_encumbrance system sets Ambulatory.walk_speed to
//! base_walk_speed * ENCUMBERED_SPEED_MULTIPLIER when over limit.
//!
//! # Item placement
//! Items are always placed in the best available slot at time of pickup —
//! the smallest container whose max_item_size >= item.size with a free slot.
//! No automatic reorganisation occurs. Reorganisation is an explicit task.
//!
//! # Life stage slot counts
//! Adult: species value (e.g. DORF_ADULT_SLOTS = 8)
//! Child: floor(adult / 2), minimum 0
//! Baby: 1 if adult >= 2, else 0
//! See slots_for_age().
use bevy::prelude::*;
use smallvec::SmallVec;
+18 -4
View File
@@ -1,5 +1,19 @@
//! Encumbrance system. Fires `InventoryChangedEvent` after any inventory mutation to
//! trigger walk_speed recalculation without per-tick iteration over all carriers.
//! Encumbrance system — updates walk_speed based on carry weight.
//!
//! # Event-driven design
//! Rather than iterating all carriers every tick, encumbrance recalculates only
//! for entities that fired an InventoryChangedEvent. At 5000 entities with rare
//! inventory changes, this reduces per-tick work from O(entities) to O(changes).
//!
//! Any code that mutates a PersonalInventory or a Container held by an entity
//! MUST fire InventoryChangedEvent { carrier } after the mutation. The carrier
//! is always the top-level entity with PersonalInventory — not a nested container.
//!
//! # base_walk_speed
//! Ambulatory gains base_walk_speed: f32 — the unmodified speed. Encumbrance
//! writes walk_speed = base_walk_speed * ENCUMBERED_SPEED_MULTIPLIER.
//! Restoring writes walk_speed = base_walk_speed. base_walk_speed is never
//! modified by encumbrance.
use bevy::prelude::*;
use rustc_hash::FxHashSet;
@@ -19,10 +33,10 @@ pub fn update_encumbrance(
mut carriers: Query<(&mut PersonalInventory, &mut Ambulatory)>,
containers: Query<&Container>,
) {
let changed: FxHashSet<Entity> = events.read().map(|e| e.carrier).collect();
if changed.is_empty() {
if events.is_empty() {
return;
}
let changed: FxHashSet<Entity> = events.read().map(|e| e.carrier).collect();
for carrier_entity in changed {
let Ok((mut inventory, mut ambulatory)) = carriers.get_mut(carrier_entity) else {