From 4e92fcf1a15367e39a8a59f9a81f9f43eb3263c2 Mon Sep 17 00:00:00 2001 From: grom Date: Sat, 17 Oct 2026 18:14:17 -0600 Subject: [PATCH] corpse: each way a grave can draw no plate now says which one it was MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit He hovered a grave for the instrumentation and the log has **no** corpse line at all — which, as the earlier note said, means the question is now a different one: either no corpse object arrived, or the pick never landed on it, or the plate refused it silently. Two of those were still silent. The bone-pile refusal now logs too, though it is the reference's own answer (`0x5d76d0`: bones with `CORPSE_FIELD_DYNAMIC_FLAGS` bit 0 clear shows no name) — from the player's chair it looks identical to a miss, and it is the likeliest shape for a grave. A picked corpse with no fields logs as well. `log_new_corpses` is the third leg: one line per corpse object the server sends, with its flags, owner and chosen model, on `Added` so it touches only the frame's new arrivals. It answers whether the grave he hovered was a body or a bone pile without asking him to hover anything, and separates "nothing arrived" from the two plate-side misses. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn --- crates/benilla-app/src/entities.rs | 6 ++++- crates/benilla-app/src/entities/corpse.rs | 30 +++++++++++++++++++++++ crates/benilla-app/src/game_plugins.rs | 7 +++++- crates/benilla-app/src/ui_tooltip/mod.rs | 14 +++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/crates/benilla-app/src/entities.rs b/crates/benilla-app/src/entities.rs index 9eab7671..dc18a3fb 100644 --- a/crates/benilla-app/src/entities.rs +++ b/crates/benilla-app/src/entities.rs @@ -672,7 +672,11 @@ impl Plugin for EntitiesPlugin { (spell_fx::fire_fx_anim_events, spell_fx::advance_fx_anim), // A gear change re-dresses the standing visual in place, every attachment left // alone as in the reference; a new corpse arms its Dead or Drowned pose. - (attach::redress_player_looks, corpse::pose_corpses), + ( + attach::redress_player_looks, + corpse::pose_corpses, + corpse::log_new_corpses, + ), // A mount change re-seats the rig on the mount's attachment 0 or back, as the // reference re-parents the body model (`0x712f70`, `0x713020`). reseat_mounts, diff --git a/crates/benilla-app/src/entities/corpse.rs b/crates/benilla-app/src/entities/corpse.rs index d7ee3735..a8c6b8da 100644 --- a/crates/benilla-app/src/entities/corpse.rs +++ b/crates/benilla-app/src/entities/corpse.rs @@ -102,6 +102,36 @@ pub(in crate::entities) fn ensure_bones_display( bones.0.insert(key, dm); } +/// Say, once per corpse the server sends, what a plate over it would have to work with. +/// +/// "Mousing over a grave gives no tooltip" has three shapes and only the last is a bug in the +/// plate: no corpse object arrived at all, the mouse pick never landed on it, or the plate refused +/// it. The plate's own misses already log (`ui_tooltip::note_corpse_miss`, which now covers the +/// bone-pile refusal too), so one line per corpse object is what separates the first shape from +/// the other two — and it tells us whether the grave he hovered was a body or a bone pile, which +/// is the whole question (`0x5d76d0` shows no name over a bone pile with nothing to take). +/// +/// On `Added`, so this touches only the frame's new arrivals; a later field delta +/// re-inserts the store and may say it again, which is worth having when a flag flips. +pub(super) fn log_new_corpses( + corpses: Query<(&NetEntity, &crate::net::Guid, &ObjectStore), Added>, +) { + for (net, guid, store) in &corpses { + if net.kind != EntityKind::Corpse { + continue; + } + let s = &store.0; + info!( + "corpse: {:#x} arrives — bones={} lootable={} owner={:#x} model={:?}", + guid.0, + s.corpse_is_bones(), + s.corpse_lootable(), + s.corpse_owner().unwrap_or(0), + corpse_model(net, Some(store)), + ); + } +} + /// The corpse's pose is armed, once: `0x5d6260` caches the verdict at `[corpse+0x2ac]` and nothing /// recomputes it. #[derive(Component)] diff --git a/crates/benilla-app/src/game_plugins.rs b/crates/benilla-app/src/game_plugins.rs index d4909fc2..48f438f6 100644 --- a/crates/benilla-app/src/game_plugins.rs +++ b/crates/benilla-app/src/game_plugins.rs @@ -847,7 +847,12 @@ pub(crate) mod schedule_tests { /// unit it picks is then committed **by GUID**, so a stale yard or two cannot select something /// else. The pairs that would matter — its order against the script tick that reads what it /// publishes — are declared (`UnitFeed`, `.before(UnitFeedDispatch)`). - const UPDATE_ACTIONABLE_CEILING: usize = 4_972; + /// +1 for `entities::corpse::log_new_corpses`, which reads three components and writes + /// nothing: its one pair is against the collider finisher, an exclusive `&mut World` system + /// that pairs with everything it has no declared order against. The order can only decide + /// which frame the line prints in, and `Added` still fires exactly once either + /// way. + const UPDATE_ACTIONABLE_CEILING: usize = 4_973; const UPDATE_ACTIONABLE_SLACK: usize = 40; fn ratchet(what: &str, n: usize, ceiling: usize, slack: usize) { diff --git a/crates/benilla-app/src/ui_tooltip/mod.rs b/crates/benilla-app/src/ui_tooltip/mod.rs index 8c476393..70f335f7 100644 --- a/crates/benilla-app/src/ui_tooltip/mod.rs +++ b/crates/benilla-app/src/ui_tooltip/mod.rs @@ -693,10 +693,24 @@ fn drive_mouseover_tooltip( .filter(|_| go.is_none()) { let Some(store) = stores.get(entity).ok() else { + note_corpse_miss( + &mut memo.corpse_miss, + guid, + "the picked corpse carries no fields", + ); return; }; // A bone pile with nothing to take publishes no mouseover: no plate, no brighten. if !crate::target::corpse_mouseover_eligible(store) { + // Logged too, though it is the reference's own answer (`0x5d76d0`: bones, and + // `CORPSE_FIELD_DYNAMIC_FLAGS` bit 0 clear, so nothing to take). "No tooltip on a + // grave" looks identical to the two misses below from the player's chair, and this + // line is what tells them apart. + note_corpse_miss( + &mut memo.corpse_miss, + guid, + "a bone pile with no loot, which the reference refuses too (`0x5d76d0`)", + ); if !matches!(*last, LastHover::None) { script.world_tooltip_fade(); *last = LastHover::None;