show focus target on visibility hover
This commit is contained in:
@@ -14,6 +14,7 @@ using LightlessSync.Interop;
|
|||||||
using LightlessSync.LightlessConfiguration;
|
using LightlessSync.LightlessConfiguration;
|
||||||
using LightlessSync.PlayerData.Factories;
|
using LightlessSync.PlayerData.Factories;
|
||||||
using LightlessSync.PlayerData.Handlers;
|
using LightlessSync.PlayerData.Handlers;
|
||||||
|
using LightlessSync.PlayerData.Pairs;
|
||||||
using LightlessSync.Services.ActorTracking;
|
using LightlessSync.Services.ActorTracking;
|
||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
@@ -41,10 +42,13 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
private readonly ILogger<DalamudUtilService> _logger;
|
private readonly ILogger<DalamudUtilService> _logger;
|
||||||
private readonly IObjectTable _objectTable;
|
private readonly IObjectTable _objectTable;
|
||||||
private readonly ActorObjectService _actorObjectService;
|
private readonly ActorObjectService _actorObjectService;
|
||||||
|
private readonly ITargetManager _targetManager;
|
||||||
private readonly PerformanceCollectorService _performanceCollector;
|
private readonly PerformanceCollectorService _performanceCollector;
|
||||||
private readonly LightlessConfigService _configService;
|
private readonly LightlessConfigService _configService;
|
||||||
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
||||||
private readonly Lazy<PairFactory> _pairFactory;
|
private readonly Lazy<PairFactory> _pairFactory;
|
||||||
|
private PairUniqueIdentifier? _FocusPairIdent;
|
||||||
|
private IGameObject? _FocusOriginalTarget;
|
||||||
private uint? _classJobId = 0;
|
private uint? _classJobId = 0;
|
||||||
private DateTime _delayedFrameworkUpdateCheck = DateTime.UtcNow;
|
private DateTime _delayedFrameworkUpdateCheck = DateTime.UtcNow;
|
||||||
private string _lastGlobalBlockPlayer = string.Empty;
|
private string _lastGlobalBlockPlayer = string.Empty;
|
||||||
@@ -68,6 +72,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
_gameData = gameData;
|
_gameData = gameData;
|
||||||
_gameConfig = gameConfig;
|
_gameConfig = gameConfig;
|
||||||
_actorObjectService = actorObjectService;
|
_actorObjectService = actorObjectService;
|
||||||
|
_targetManager = targetManager;
|
||||||
_blockedCharacterHandler = blockedCharacterHandler;
|
_blockedCharacterHandler = blockedCharacterHandler;
|
||||||
Mediator = mediator;
|
Mediator = mediator;
|
||||||
_performanceCollector = performanceCollector;
|
_performanceCollector = performanceCollector;
|
||||||
@@ -125,20 +130,24 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
mediator.Subscribe<TargetPairMessage>(this, (msg) =>
|
mediator.Subscribe<TargetPairMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
if (clientState.IsPvP) return;
|
if (clientState.IsPvP) return;
|
||||||
var pair = _pairFactory.Value.Create(msg.Pair.UniqueIdent) ?? msg.Pair;
|
if (!ResolvePairAddress(msg.Pair, out var pair, out var addr)) return;
|
||||||
var name = pair.PlayerName;
|
|
||||||
if (string.IsNullOrEmpty(name)) return;
|
|
||||||
if (!_actorObjectService.TryGetPlayerByName(name, out var descriptor))
|
|
||||||
return;
|
|
||||||
var addr = descriptor.Address;
|
|
||||||
if (addr == nint.Zero) return;
|
|
||||||
var useFocusTarget = _configService.Current.UseFocusTarget;
|
var useFocusTarget = _configService.Current.UseFocusTarget;
|
||||||
_ = RunOnFrameworkThread(() =>
|
_ = RunOnFrameworkThread(() =>
|
||||||
{
|
{
|
||||||
|
var gameObject = CreateGameObject(addr);
|
||||||
|
if (gameObject is null) return;
|
||||||
if (useFocusTarget)
|
if (useFocusTarget)
|
||||||
targetManager.FocusTarget = CreateGameObject(addr);
|
{
|
||||||
|
_targetManager.FocusTarget = gameObject;
|
||||||
|
if (_FocusPairIdent.HasValue && _FocusPairIdent.Value.Equals(pair.UniqueIdent))
|
||||||
|
{
|
||||||
|
_FocusOriginalTarget = _targetManager.FocusTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
targetManager.Target = CreateGameObject(addr);
|
{
|
||||||
|
_targetManager.Target = gameObject;
|
||||||
|
}
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
IsWine = Util.IsWine();
|
IsWine = Util.IsWine();
|
||||||
@@ -148,6 +157,61 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
private Lazy<ulong> RebuildCID() => new(GetCID);
|
private Lazy<ulong> RebuildCID() => new(GetCID);
|
||||||
|
|
||||||
public bool IsWine { get; init; }
|
public bool IsWine { get; init; }
|
||||||
|
private bool ResolvePairAddress(Pair pair, out Pair resolvedPair, out nint address)
|
||||||
|
{
|
||||||
|
resolvedPair = _pairFactory.Value.Create(pair.UniqueIdent) ?? pair;
|
||||||
|
address = nint.Zero;
|
||||||
|
var name = resolvedPair.PlayerName;
|
||||||
|
if (string.IsNullOrEmpty(name)) return false;
|
||||||
|
if (!_actorObjectService.TryGetPlayerByName(name, out var descriptor))
|
||||||
|
return false;
|
||||||
|
address = descriptor.Address;
|
||||||
|
return address != nint.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FocusVisiblePair(Pair pair)
|
||||||
|
{
|
||||||
|
if (_clientState.IsPvP) return;
|
||||||
|
if (!ResolvePairAddress(pair, out var resolvedPair, out var address)) return;
|
||||||
|
_ = RunOnFrameworkThread(() => FocusPairUnsafe(address, resolvedPair.UniqueIdent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseVisiblePairFocus()
|
||||||
|
{
|
||||||
|
_ = RunOnFrameworkThread(ReleaseFocusUnsafe);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FocusPairUnsafe(nint address, PairUniqueIdentifier pairIdent)
|
||||||
|
{
|
||||||
|
var target = CreateGameObject(address);
|
||||||
|
if (target is null) return;
|
||||||
|
|
||||||
|
if (!_FocusPairIdent.HasValue)
|
||||||
|
{
|
||||||
|
_FocusOriginalTarget = _targetManager.FocusTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
_targetManager.FocusTarget = target;
|
||||||
|
_FocusPairIdent = pairIdent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseFocusUnsafe()
|
||||||
|
{
|
||||||
|
if (!_FocusPairIdent.HasValue)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var previous = _FocusOriginalTarget;
|
||||||
|
if (previous != null && !IsObjectPresent(previous))
|
||||||
|
{
|
||||||
|
previous = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_targetManager.FocusTarget = previous;
|
||||||
|
_FocusPairIdent = null;
|
||||||
|
_FocusOriginalTarget = null;
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe GameObject* GposeTarget
|
public unsafe GameObject* GposeTarget
|
||||||
{
|
{
|
||||||
@@ -505,6 +569,17 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
Mediator.UnsubscribeAll(this);
|
Mediator.UnsubscribeAll(this);
|
||||||
_framework.Update -= FrameworkOnUpdate;
|
_framework.Update -= FrameworkOnUpdate;
|
||||||
|
if (_FocusPairIdent.HasValue)
|
||||||
|
{
|
||||||
|
if (_framework.IsInFrameworkUpdateThread)
|
||||||
|
{
|
||||||
|
ReleaseFocusUnsafe();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ = RunOnFrameworkThread(ReleaseFocusUnsafe);
|
||||||
|
}
|
||||||
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ public record PairDataChangedMessage : MessageBase;
|
|||||||
public record PairUiUpdatedMessage(PairUiSnapshot Snapshot) : MessageBase;
|
public record PairUiUpdatedMessage(PairUiSnapshot Snapshot) : MessageBase;
|
||||||
public record CensusUpdateMessage(byte Gender, byte RaceId, byte TribeId) : MessageBase;
|
public record CensusUpdateMessage(byte Gender, byte RaceId, byte TribeId) : MessageBase;
|
||||||
public record TargetPairMessage(Pair Pair) : MessageBase;
|
public record TargetPairMessage(Pair Pair) : MessageBase;
|
||||||
|
public record PairFocusCharacterMessage(Pair Pair) : SameThreadMessage;
|
||||||
public record CombatStartMessage : MessageBase;
|
public record CombatStartMessage : MessageBase;
|
||||||
public record CombatEndMessage : MessageBase;
|
public record CombatEndMessage : MessageBase;
|
||||||
public record PerformanceStartMessage : MessageBase;
|
public record PerformanceStartMessage : MessageBase;
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
private readonly TagHandler _tagHandler;
|
private readonly TagHandler _tagHandler;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private readonly LightFinderService _broadcastService;
|
private readonly LightFinderService _broadcastService;
|
||||||
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
|
|
||||||
private List<IDrawFolder> _drawFolders;
|
private List<IDrawFolder> _drawFolders;
|
||||||
private Pair? _lastAddedUser;
|
private Pair? _lastAddedUser;
|
||||||
@@ -68,6 +69,9 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
private float _windowContentWidth;
|
private float _windowContentWidth;
|
||||||
private readonly SeluneBrush _seluneBrush = new();
|
private readonly SeluneBrush _seluneBrush = new();
|
||||||
private const float _connectButtonHighlightThickness = 14f;
|
private const float _connectButtonHighlightThickness = 14f;
|
||||||
|
private Pair? _focusedPair;
|
||||||
|
private Pair? _pendingFocusPair;
|
||||||
|
private int _pendingFocusFrame = -1;
|
||||||
|
|
||||||
public CompactUi(
|
public CompactUi(
|
||||||
ILogger<CompactUi> logger,
|
ILogger<CompactUi> logger,
|
||||||
@@ -109,7 +113,9 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_broadcastService = broadcastService;
|
_broadcastService = broadcastService;
|
||||||
_pairLedger = pairLedger;
|
_pairLedger = pairLedger;
|
||||||
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_tabMenu = new TopTabMenu(Mediator, _apiController, _uiSharedService, pairRequestService, dalamudUtilService, lightlessNotificationService);
|
_tabMenu = new TopTabMenu(Mediator, _apiController, _uiSharedService, pairRequestService, dalamudUtilService, lightlessNotificationService);
|
||||||
|
Mediator.Subscribe<PairFocusCharacterMessage>(this, msg => RegisterFocusCharacter(msg.Pair));
|
||||||
|
|
||||||
AllowPinning = true;
|
AllowPinning = true;
|
||||||
AllowClickthrough = false;
|
AllowClickthrough = false;
|
||||||
@@ -178,6 +184,12 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
_lightlessMediator = mediator;
|
_lightlessMediator = mediator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnClose()
|
||||||
|
{
|
||||||
|
ForceReleaseFocus();
|
||||||
|
base.OnClose();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
{
|
{
|
||||||
var drawList = ImGui.GetWindowDrawList();
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
@@ -268,6 +280,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
selune.Animate(ImGui.GetIO().DeltaTime);
|
selune.Animate(ImGui.GetIO().DeltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessFocusTracker();
|
||||||
|
|
||||||
var lastAddedPair = _pairUiService.GetLastAddedPair();
|
var lastAddedPair = _pairUiService.GetLastAddedPair();
|
||||||
if (_configService.Current.OpenPopupOnAdd && lastAddedPair is not null)
|
if (_configService.Current.OpenPopupOnAdd && lastAddedPair is not null)
|
||||||
{
|
{
|
||||||
@@ -1117,4 +1131,50 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
_wasOpen = IsOpen;
|
_wasOpen = IsOpen;
|
||||||
IsOpen = false;
|
IsOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterFocusCharacter(Pair pair)
|
||||||
|
{
|
||||||
|
_pendingFocusPair = pair;
|
||||||
|
_pendingFocusFrame = ImGui.GetFrameCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessFocusTracker()
|
||||||
|
{
|
||||||
|
var frame = ImGui.GetFrameCount();
|
||||||
|
Pair? character = _pendingFocusFrame == frame ? _pendingFocusPair : null;
|
||||||
|
if (!ReferenceEquals(character, _focusedPair))
|
||||||
|
{
|
||||||
|
if (character is null)
|
||||||
|
{
|
||||||
|
_dalamudUtilService.ReleaseVisiblePairFocus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dalamudUtilService.FocusVisiblePair(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
_focusedPair = character;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pendingFocusFrame == frame)
|
||||||
|
{
|
||||||
|
_pendingFocusPair = null;
|
||||||
|
_pendingFocusFrame = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ForceReleaseFocus()
|
||||||
|
{
|
||||||
|
if (_focusedPair is null)
|
||||||
|
{
|
||||||
|
_pendingFocusPair = null;
|
||||||
|
_pendingFocusFrame = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dalamudUtilService.ReleaseVisiblePairFocus();
|
||||||
|
_focusedPair = null;
|
||||||
|
_pendingFocusPair = null;
|
||||||
|
_pendingFocusFrame = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,6 +247,10 @@ public class DrawUserPair
|
|||||||
else if (_pair.IsVisible)
|
else if (_pair.IsVisible)
|
||||||
{
|
{
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.Eye, UIColors.Get("LightlessBlue"));
|
_uiSharedService.IconText(FontAwesomeIcon.Eye, UIColors.Get("LightlessBlue"));
|
||||||
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem | ImGuiHoveredFlags.AllowWhenOverlapped | ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
{
|
||||||
|
_mediator.Publish(new PairFocusCharacterMessage(_pair));
|
||||||
|
}
|
||||||
if (ImGui.IsItemClicked())
|
if (ImGui.IsItemClicked())
|
||||||
{
|
{
|
||||||
_mediator.Publish(new TargetPairMessage(_pair));
|
_mediator.Publish(new TargetPairMessage(_pair));
|
||||||
|
|||||||
Reference in New Issue
Block a user