diff --git a/.gitignore b/.gitignore index 904fdf9..d3cbc8e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,10 @@ references/ .claude/ launch.log launch-*.log +launch.utf8.log # ImGui auto-saved window/docking state (per-user, not source) imgui.ini + +# User-only download cache (per-developer, not source) +refs/ diff --git a/docs/ISSUES.md b/docs/ISSUES.md index c214820..668603a 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -114,6 +114,48 @@ Copy this block when adding a new issue: --- +## #6 — Vital max ignores enchantment buffs + vitae + +**Status:** OPEN +**Severity:** LOW (3-5% accuracy gap on a HUD bar) +**Filed:** 2026-04-25 +**Component:** ui / player-state + +**Description:** `LocalPlayerState.GetMaxApprox` computes the unenchanted base max for HP/Stam/Mana — `vital.(ranks+start) + attribute_contribution` with retail's hardcoded coefficients (Endurance/2, Endurance, Self). Live test shows bars at ~95% when buffs are presumably active (server character is `+Acdream`, GM-marker char with likely buff stack). Holtburger's `calculate_vital_current` adds `× multiplier + additive` from the active enchantment list — that's the missing 5%. + +**Root cause / status:** Need to fold `Spellbook.ActiveEnchantments` into the max calc. Holtburger's `magic.rs` aggregates by `EnchantmentTypeFlags::SECOND_ATT` masked with the vital id. The same data already arrives via `MagicUpdateEnchantment` events that we wire into `Spellbook`. + +**Files:** +- `src/AcDream.Core/Player/LocalPlayerState.cs` — `GetMaxApprox` returns the base; extend to also call `Spellbook` for vital-typed enchantment aggregation. +- `src/AcDream.Core/Spells/Spellbook.cs` — needs an aggregator helper similar to holtburger's `get_vital_multiplier` / `get_vital_additive`. + +**Research:** holtburger `crates/holtburger-world/src/player/stats_calc.rs:91-111`, `magic.rs` get_enchantment_multiplier / additive. + +**Acceptance:** A `+Acdream` login shows Stam/Mana percent within 1% of retail's reading once any active buff multipliers are applied. (HP already at 100% indicates the unbuffed Health formula is already correct on its own.) + +--- + +## #7 — PlayerDescription parser stops after spells (options/inventory/equipped not extracted) + +**Status:** OPEN +**Severity:** LOW (Issue #5 needed only the early sections; later panels will need the rest) +**Filed:** 2026-04-25 +**Component:** net / player-state + +**Description:** Current `PlayerDescriptionParser` walks through `Attribute / Skill / Spell` vector-flag blocks per holtburger but stops before the trailing options / shortcuts / hotbars / desired_comps / spellbook_filters / options2 / gameplay_options / inventory / equipped sections. Future panels (hotbar, inventory, character options) need that data; the parser will need extension. Holtburger's events.rs:462-625 has the full layout; the messy parts are `gameplay_options` (variable-length opaque blob requiring heuristic skip) and `desired_comps`. + +**Root cause / status:** Just a scope decision — port-the-easy-bits-first approach. Reference shape lives in holtburger's full `unpack`; the only complex piece is `find_inventory_start_after_gameplay_options` (heuristic alignment search). + +**Files:** +- `src/AcDream.Core.Net/Messages/PlayerDescriptionParser.cs` — extend `Parsed` record + walker. +- `tests/AcDream.Core.Net.Tests/PlayerDescriptionParserTests.cs` — add coverage with synthetic payloads of the trailing sections. + +**Research:** holtburger `crates/holtburger-protocol/src/messages/player/events.rs:462-625` (full unpacker including the heuristic `find_inventory_start_after_gameplay_options`). + +**Acceptance:** All sections of a real-world PlayerDescription parse to completion — verified via a packet capture or by feeding synthetic test fixtures covering every flag combination. + +--- + ## #4 — Sky horizon-glow disabled (fog-mix skipped on sky meshes) **Status:** OPEN @@ -142,8 +184,8 @@ Copy this block when adding a new issue: ## #5 — [DONE 2026-04-25] VitalsPanel stamina/mana bars always null **Closed:** 2026-04-25 -**Commit:** `feat(player): #5 LocalPlayerState — Stam/Mana wired through PlayerDescription` -**Resolution:** Added `AcDream.Core.Player.LocalPlayerState` (caches `CurrentStamina` / `MaxStamina` / `CurrentMana` / `MaxMana` from `PlayerDescription (0x0013)`'s `CreatureProfile`). Wired into `GameEventWiring.WireAll` as a new optional 6th parameter so back-compat preserved. `VitalsVM` constructor now takes an optional `LocalPlayerState`; when wired, `StaminaPercent` / `ManaPercent` read through to the cache (no VM-side caching) and `VitalsPanel` automatically draws the two extra bars. Edge cases covered: zero `Max*` returns `null` (no /0); current > max clamps to 1.0; partial profiles preserve previous good values rather than wiping them. 16 new tests (11 `LocalPlayerStateTests` + 3 `VitalsVMTests` + 2 `GameEventWiringTests`). +**Commit:** `feat(player): #5 PlayerDescription parser — Stam/Mana via attribute block` +**Resolution:** First attempt (commit `d42bf57`) used `AppraiseInfoParser` for `PlayerDescription (0x0013)` — wrong wire format. ACE source confirmed via `GameEventPlayerDescription.WriteEventBody`: PlayerDescription is hand-written (DescriptionPropertyFlag-driven property hashtables, vector flags, attribute block, skills, spells, options/inventory tail) — distinct from `IdentifyObjectResponse (0x00C9)`'s `AppraiseInfo.Write`. Pivoted to a real port: new `PlayerDescriptionParser.cs` that walks property hashtables (Int32/Int64/Bool/Double/String/Did/Iid + Position) gated on the property flags, then reads vector flags + has_health + the attribute block where vitals 7/8/9 carry `ranks/start/xp/current`. Also redesigned `LocalPlayerState` to track per-vital snapshots (replacing the sentinel-API of attempt 1) plus per-attribute snapshots, with `GetMaxApprox` applying the retail formula `vital.(ranks+start) + attribute_contribution` (Endurance/2 for Health, Endurance for Stamina, Self for Mana). Live verified: `+Acdream` shows three bars; ~95% reading on Stam/Mana traced to active buff multipliers (filed as #6). Wire-port also added `PrivateUpdateVital (0x02E7)` + `PrivateUpdateVitalCurrent (0x02E9)` for delta updates per holtburger `UpdateVital`. ~700 LOC C#, 30+ new tests.