Recover stale battle input locks
CI / test (push) Successful in 2m52s
Details
CI / test (push) Successful in 2m52s
Details
This commit is contained in:
parent
d6784b7ca9
commit
ba932c0d17
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Vanguard.Battle
|
||||
{
|
||||
|
|
@ -14,6 +15,11 @@ namespace Vanguard.Battle
|
|||
|
||||
public bool IsLocked => _reasons.Count > 0;
|
||||
|
||||
public string Describe() =>
|
||||
_reasons.Count == 0
|
||||
? "none"
|
||||
: string.Join(",", _reasons.Select(pair => pair.Key + "=" + pair.Value));
|
||||
|
||||
public event Action<bool> Changed;
|
||||
|
||||
public void Acquire(string reason)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Vanguard.UI
|
|||
private readonly AnimationConfig _animationConfig;
|
||||
private readonly InputLockService _inputLock;
|
||||
private bool _feedbackLockHeld;
|
||||
private string _lastInputLockSummary;
|
||||
private readonly Dictionary<string, CardCatalogItemDto> _catalog =
|
||||
new Dictionary<string, CardCatalogItemDto>(StringComparer.Ordinal);
|
||||
private bool _catalogLoading;
|
||||
|
|
@ -342,9 +343,47 @@ namespace Vanguard.UI
|
|||
|
||||
UpdateClock();
|
||||
UpdateFeedback();
|
||||
SanitizeInputLocks();
|
||||
UpdateAutoPhases();
|
||||
}
|
||||
|
||||
private void SanitizeInputLocks()
|
||||
{
|
||||
if (!_inputLock.IsLocked)
|
||||
{
|
||||
_lastInputLockSummary = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Locks must never outlive the UI/gameplay state that owns them.
|
||||
// This also recovers from a missed close callback after reconnects,
|
||||
// overlays or card menus.
|
||||
if (!_reconnecting)
|
||||
_inputLock.Release("reconnect");
|
||||
if (_overlays == null || !_overlays.IsOpen)
|
||||
_inputLock.Release("overlay");
|
||||
if (_cardMenu == null || !_cardMenu.IsVisible)
|
||||
_inputLock.Release("card-menu");
|
||||
if (!_feedbackPlaying && _feedbackQueue.Count == 0)
|
||||
{
|
||||
_feedbackLockHeld = false;
|
||||
_inputLock.Release("feedback");
|
||||
}
|
||||
|
||||
var summary = _inputLock.Describe();
|
||||
if (!_inputLock.IsLocked)
|
||||
{
|
||||
_lastInputLockSummary = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.Equals(summary, _lastInputLockSummary, StringComparison.Ordinal))
|
||||
{
|
||||
_lastInputLockSummary = summary;
|
||||
Debug.LogWarning("Battle input lock held: " + summary);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAutoPhases()
|
||||
{
|
||||
if (_view == null || _sending || _reconnecting)
|
||||
|
|
|
|||
|
|
@ -1005,6 +1005,9 @@ Battle; Boot и общие сервисы остаются персистент
|
|||
завершается автоматически, кнопка «Закончить муллиган» скрывается и не
|
||||
блокируется feedback/overlay-локом; при реконнекте авто-завершение
|
||||
взводится повторно из снапшота.
|
||||
- InputLock чистит зависшие причины, если owning-состояние уже неактивно
|
||||
(нет reconnect/overlay/card-menu/feedback). Это убирает блокировку
|
||||
«Сменить» после хода противника, когда сервер уже прислал ride-интенты.
|
||||
- Trigger-зона противника зеркальна: над его колодой в сторону центра,
|
||||
а не за дальним краем.
|
||||
- Карты на столе и в руке масштабируются общим `cardScale = 1.25`
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@
|
|||
`AnimationConfig` (`Resources/AnimationConfig`). Guard/drive/intercept
|
||||
показывают имя карты и держатся 1.5–2 с. 3D-карты плавно снапятся,
|
||||
поворачиваются в Rest и переворачиваются; подсветка целей и точки броска
|
||||
обновляются на каждом снимке.
|
||||
обновляются на каждом снимке. Зависшие причины `InputLockService`
|
||||
снимаются, когда reconnect/overlay/card-menu/feedback уже неактивны.
|
||||
- Бой: динамическая плашка `POWER X vs SHIELD Y` (Power атакующего против
|
||||
Power защищающегося + GuardShield), пересчитывается на каждом снимке, в
|
||||
том числе после Guard. От атакующего к цели идёт затухающая 3D-стрелка,
|
||||
|
|
|
|||
Loading…
Reference in New Issue