fix(mosstank): read the real busy signal, not the last-requested spell
A buff pass cast exactly one spell and then stalled at zero. The log timeline made it unambiguous: one "casting Concentration", then every later pass queued 86 buffs and cast none until the 25s stall fired. IsCasting was bound to RuntimeSpellCastState.LastRequestedSpellId. That property records the last spell REQUESTED and is cleared only by Reset() at session teardown -- it is honestly named, and I read a busy flag into it that was never there. So it latched true on the first successful cast and stayed true for the rest of the session, and every tick returned early at the busy check. It now reads the shared busy count: incremented by the cast path (FreeHandsAndCastSpell @0x00566EF0) and decremented by the server's UseDone, which is the actual in-flight signal. EvaluateGate reports PluginCastGate.Busy as well, so a genuinely wedged counter names itself in the status line instead of presenting as silence. Solution builds clean; 14,437 tests pass on the standard hermetic lane filter, 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b9674b1f1e
commit
1a7b0ed3d5
1 changed files with 18 additions and 3 deletions
|
|
@ -384,14 +384,27 @@ internal sealed class AppAutomationSurface
|
|||
}
|
||||
|
||||
// ── IMagicCommands ────────────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// True while an action the server has not acknowledged is in flight.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Reads the shared busy count, which the cast path increments
|
||||
/// (<c>FreeHandsAndCastSpell</c> @0x00566EF0) and the server's UseDone
|
||||
/// decrements. NOT <c>RuntimeSpellCastState.LastRequestedSpellId</c>: that
|
||||
/// records the last spell requested and is cleared only by Reset at session
|
||||
/// teardown, so using it as a busy flag latches true after the first cast
|
||||
/// and never clears -- which is exactly what stalled MossTank's first buff
|
||||
/// pass at one cast.
|
||||
/// </remarks>
|
||||
public bool IsCasting
|
||||
{
|
||||
get
|
||||
{
|
||||
RuntimeSpellCastState? cast;
|
||||
GameRuntime? runtime;
|
||||
lock (_gate)
|
||||
cast = _cast;
|
||||
return cast?.LastRequestedSpellId is not null;
|
||||
runtime = _runtime;
|
||||
return runtime is not null
|
||||
&& runtime.InventoryOwner.Transactions.BusyCount > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -408,6 +421,8 @@ internal sealed class AppAutomationSurface
|
|||
return PluginCastGate.Unavailable;
|
||||
if (!spellbook.Knows(spellId))
|
||||
return PluginCastGate.NotKnown;
|
||||
if (IsCasting)
|
||||
return PluginCastGate.Busy;
|
||||
|
||||
return cast.EvaluateCastGate(spellId) switch
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue