feat(player): #5 LocalPlayerState — Stam/Mana wired through PlayerDescription
Closes ISSUES.md #5. The Vitals devtools window now draws three bars (HP / Stamina / Mana) once the server sends the first PlayerDescription (0x0013), instead of HP only. Built test-first per CLAUDE.md TDD rule — 16 new tests went red before the implementation went in. New AcDream.Core.Player.LocalPlayerState (cache): - {CurrentStamina, MaxStamina, CurrentMana, MaxMana} as uint? — null until first received. - StaminaPercent / ManaPercent: 0..1 fraction or null when either field is missing or max is zero. Clamps to 1.0 if current > max (server can briefly report this during buff transitions). - OnPlayerDescription preserves any previously known good value when an incoming field is null — partial profiles don't wipe state. - Changed event for future subscribers. GameEventWiring.WireAll: - New optional 6th parameter: LocalPlayerState? localPlayer = null. Existing 5-arg call sites still work; without the parameter the new PlayerDescription handler still parses + feeds the spellbook but skips the cache update. - PlayerDescription (0x0013) shares AppraiseInfo wire format with IdentifyObjectResponse (0x00C9) per AppraiseInfoParser docstring, so the new handler reuses the existing parser and pulls CreatureProfile.{Stamina, StaminaMax, Mana, ManaMax}. - Player's full learned spellbook also lands here (previously only item-scoped Identify responses fed the spellbook). VitalsVM: - Constructor adds optional LocalPlayerState? parameter (default null keeps every existing caller compiling). - StaminaPercent / ManaPercent now read through to LocalPlayerState every access — no VM-side caching, so a server-side delta to the cache surfaces next frame without any explicit refresh. GameWindow: - Public readonly LocalPlayer field alongside Combat / Chat / Items / SpellBook so plugins + future panels can bind directly. - WireAll call updated to pass LocalPlayer. - VitalsVM construction passes LocalPlayer so the existing VitalsPanel automatically picks up the two new bars. Test counts: - AcDream.Core.Tests: 550 → 561 (+11 LocalPlayerStateTests) - AcDream.UI.Abstractions.Tests: 23 → 26 (+3 VitalsVM through-cache) - AcDream.Core.Net.Tests: 192 → 194 (+2 PlayerDescription wiring) - Total: 765 → 781 Build: 0 warnings, 0 errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9faf9d7e3a
commit
d42bf5735d
8 changed files with 436 additions and 50 deletions
|
|
@ -3,6 +3,7 @@ using AcDream.Core.Chat;
|
|||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.Player;
|
||||
using AcDream.Core.Spells;
|
||||
|
||||
namespace AcDream.Core.Net;
|
||||
|
|
@ -34,7 +35,8 @@ public static class GameEventWiring
|
|||
ItemRepository items,
|
||||
CombatState combat,
|
||||
Spellbook spellbook,
|
||||
ChatLog chat)
|
||||
ChatLog chat,
|
||||
LocalPlayerState? localPlayer = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dispatcher);
|
||||
ArgumentNullException.ThrowIfNull(items);
|
||||
|
|
@ -165,5 +167,31 @@ public static class GameEventWiring
|
|||
foreach (uint sid in p.Value.SpellBook)
|
||||
spellbook.OnSpellLearned(sid);
|
||||
});
|
||||
|
||||
// ── Player ────────────────────────────────────────────────
|
||||
// PlayerDescription (0x0013) carries the same AppraiseInfo body as
|
||||
// IdentifyObjectResponse (0x00C9), but it's targeted at the local
|
||||
// player. Issue #5: feed CreatureProfile.{Stamina, Mana, *Max}
|
||||
// into LocalPlayerState so the Vitals HUD can render those bars.
|
||||
// Spellbook + properties get the same downstream treatment as
|
||||
// IdentifyObjectResponse so the player's full learned spellbook
|
||||
// also lands here.
|
||||
dispatcher.Register(GameEventType.PlayerDescription, e =>
|
||||
{
|
||||
var p = AppraiseInfoParser.TryParse(e.Payload.Span);
|
||||
if (p is null || !p.Value.Success) return;
|
||||
|
||||
if (localPlayer is not null && p.Value.CreatureProfile is { } profile)
|
||||
{
|
||||
localPlayer.OnPlayerDescription(
|
||||
currentStamina: profile.Stamina,
|
||||
maxStamina: profile.StaminaMax,
|
||||
currentMana: profile.Mana,
|
||||
maxMana: profile.ManaMax);
|
||||
}
|
||||
|
||||
foreach (uint sid in p.Value.SpellBook)
|
||||
spellbook.OnSpellLearned(sid);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue