feat(ui): port retail appraisal panel
Preserve retail's one-pending-appraisal busy lifetime, parse the complete gated response, and mount the authored examination layout in the shared main-panel host. Keep known 3D preview and inscription-write gaps explicit in AP-110.
This commit is contained in:
parent
6b1ae4fb76
commit
643cdfe66e
24 changed files with 17132 additions and 40 deletions
|
|
@ -110,6 +110,8 @@ public sealed class ItemInteractionController : IDisposable
|
|||
private uint _consumedPrimaryClickTarget;
|
||||
private long _consumedPrimaryClickMs = long.MinValue / 2;
|
||||
private int _busyCount;
|
||||
private uint _awaitingAppraisalId;
|
||||
private uint _currentAppraisalId;
|
||||
private ulong _nextInventoryRequestToken;
|
||||
private PendingBackpackPlacement? _pendingBackpackPlacement;
|
||||
private PendingInventoryRequest? _pendingInventoryRequest;
|
||||
|
|
@ -222,6 +224,7 @@ public sealed class ItemInteractionController : IDisposable
|
|||
public InteractionState InteractionState => _interactionState;
|
||||
|
||||
public int BusyCount => _busyCount;
|
||||
public uint CurrentAppraisalId => _currentAppraisalId;
|
||||
|
||||
public bool CanMakeInventoryRequest =>
|
||||
BaseCanMakeInventoryRequest && _pendingInventoryRequest is null;
|
||||
|
|
@ -451,7 +454,7 @@ public sealed class ItemInteractionController : IDisposable
|
|||
ClearTargetMode();
|
||||
accepted = targetGuid != 0 && _sendExamine is not null;
|
||||
if (accepted)
|
||||
_sendExamine!(targetGuid);
|
||||
RequestAppraisal(targetGuid);
|
||||
break;
|
||||
case InteractionModeKind.UseItemOnTarget:
|
||||
accepted = AcquireTarget(targetGuid);
|
||||
|
|
@ -492,7 +495,61 @@ public sealed class ItemInteractionController : IDisposable
|
|||
return _interactionState.EnterExamine();
|
||||
if (_sendExamine is null)
|
||||
return false;
|
||||
_sendExamine(selectedObjectId);
|
||||
RequestAppraisal(selectedObjectId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>gmExaminationUI::RecvNotice_ExamineObject @ 0x004AB7B0</c>.
|
||||
/// One shared UI-busy reference covers the currently pending appraisal,
|
||||
/// even when another examine request replaces its GUID before a response.
|
||||
/// </summary>
|
||||
private void RequestAppraisal(uint objectId)
|
||||
{
|
||||
if (objectId == 0 || _sendExamine is null)
|
||||
return;
|
||||
|
||||
if (_awaitingAppraisalId == 0)
|
||||
IncrementBusyCount();
|
||||
_awaitingAppraisalId = objectId;
|
||||
_sendExamine(objectId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accepts only the pending or current appraisal, matching
|
||||
/// <c>gmExaminationUI::SetAppraiseInfo @ 0x004ADAE0</c>.
|
||||
/// </summary>
|
||||
public AppraisalResponseAcceptance AcceptAppraisalResponse(uint objectId)
|
||||
{
|
||||
if (objectId == 0
|
||||
|| (objectId != _awaitingAppraisalId
|
||||
&& objectId != _currentAppraisalId))
|
||||
return default;
|
||||
|
||||
bool firstResponse = objectId == _awaitingAppraisalId;
|
||||
if (firstResponse)
|
||||
{
|
||||
_awaitingAppraisalId = 0;
|
||||
if (_busyCount > 0)
|
||||
_busyCount--;
|
||||
_currentAppraisalId = objectId;
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
return new AppraisalResponseAcceptance(
|
||||
Accepted: true,
|
||||
FirstResponse: firstResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail combat-time creature/player refresh sends CM_Item directly and
|
||||
/// therefore does not acquire a second UI-busy reference.
|
||||
/// </summary>
|
||||
public bool RefreshCurrentAppraisal()
|
||||
{
|
||||
if (_currentAppraisalId == 0 || _sendExamine is null)
|
||||
return false;
|
||||
_sendExamine(_currentAppraisalId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1240,6 +1297,8 @@ public sealed class ItemInteractionController : IDisposable
|
|||
_pendingBackpackPlacement = null;
|
||||
_useReservationGeneration++;
|
||||
_busyCount = 0;
|
||||
_awaitingAppraisalId = 0;
|
||||
_currentAppraisalId = 0;
|
||||
_pendingInventoryRequest = null;
|
||||
_lastUseMs = long.MinValue / 2;
|
||||
_consumedPrimaryClickTarget = 0u;
|
||||
|
|
@ -1258,6 +1317,10 @@ public sealed class ItemInteractionController : IDisposable
|
|||
failures);
|
||||
}
|
||||
|
||||
public readonly record struct AppraisalResponseAcceptance(
|
||||
bool Accepted,
|
||||
bool FirstResponse);
|
||||
|
||||
private static void DispatchAll(Action? listeners, List<Exception> failures)
|
||||
{
|
||||
if (listeners is null)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue