Skip to content

Commit

Permalink
Restored the previous nameplate enable/disable behavior in order to h…
Browse files Browse the repository at this point in the history
…elp prevent log spam in the event of game changes breaking nameplate functionality. Also switched UI mouseover target resolution to use the pronoun module for more resiliency.
  • Loading branch information
PunishedPineapple committed Jul 7, 2024
1 parent 521ea9f commit fa74fa6
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 56 deletions.
16 changes: 8 additions & 8 deletions Distance/DalamudPackager.targets
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Target Name="PackagePluginDebug" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<DalamudPackager
<Target Name="PackagePluginDebug" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<DalamudPackager
ProjectDir="$(ProjectDir)"
OutputPath="$(OutputPath)"
AssemblyName="$(AssemblyName)"
Exclude="latest.zip;previous.zip;loc.log;$(ProjectName).pdb;$(ProjectName).deps.json;$(ProjectName)_Localizable.json"
MakeZip="false"/>
</Target>
Exclude="latest.zip;previous.zip;loc.log;$(ProjectName).pdb;$(ProjectName).deps.json;$(ProjectName)_Localizable.json"
MakeZip="false"/>
</Target>
<Target Name="PackagePluginRelease" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
<DalamudPackager
ProjectDir="$(ProjectDir)"
OutputPath="$(OutputPath)"
AssemblyName="$(AssemblyName)"
Exclude="latest.zip;previous.zip;loc.log;$(ProjectName).pdb;$(ProjectName).deps.json;$(ProjectName)_Localizable.json"
MakeZip="true"/>
</Target>
Exclude="latest.zip;previous.zip;loc.log;$(ProjectName).pdb;$(ProjectName).deps.json;$(ProjectName)_Localizable.json"
MakeZip="true"/>
</Target>
</Project>
2 changes: 1 addition & 1 deletion Distance/Distance.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Platforms>AnyCPU</Platforms>
<Version>1.1.1.1</Version>
<Version>1.1.1.2</Version>
<Authors>PunishedPineapple</Authors>
<Product />
<Copyright>Copyright © PunishedPineapple 2022-2024</Copyright>
Expand Down
74 changes: 64 additions & 10 deletions Distance/NameplateHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ internal static void Init( Configuration configuration )
// It's kinda jank to init a static class with an instance's data, but it'll never matter here, and the
// plugin service effectively already crosses this bridge this anyway, so it's not worth worrying about.
mConfiguration = configuration;
Service.AddonLifecycle.RegisterListener(AddonEvent.PostDraw, "NamePlate", NameplateDrawDetour);

if( mConfiguration.NameplateDistancesConfig.ShowNameplateDistances )
{
EnableNameplateDistances();
}
}

internal static void Uninit()
internal static void Uninit()
{
Service.AddonLifecycle.UnregisterListener(NameplateDrawDetour);
DisableNameplateDistances();

DestroyNameplateDistanceNodes();
DestroyNameplateDistanceNodes();

mNodeUpdateTimer.Reset();
mDistanceUpdateTimer.Reset();
Expand All @@ -34,6 +38,50 @@ internal static void Uninit()
mConfiguration = null;
}

internal static void EnableNameplateDistances()
{
if( !mEnabled )
{
try
{
Service.AddonLifecycle.RegisterListener( AddonEvent.PostDraw, "NamePlate", NameplateDrawDetour );
mEnabled = true;
}
catch( Exception e )
{
Service.PluginLog.Error( $"Unknown error while trying to enable nameplate distances:\r\n{e}" );
DisableNameplateDistances();
}
}
}

internal static void DisableNameplateDistances()
{
if( mEnabled )
{
try
{
Service.AddonLifecycle.UnregisterListener( NameplateDrawDetour );
}
catch( Exception e )
{
Service.PluginLog.Error( $"Unknown error while unregistering nameplate listener:\r\n{e}" );
}

try
{
mEnabled = false;
mNodeUpdateTimer.Reset();
mDistanceUpdateTimer.Reset();
HideAllNameplateDistanceNodes();
}
catch( Exception e )
{
Service.PluginLog.Error( $"Unknown error while trying to disable nameplate distances:\r\n{e}" );
}
}
}

internal unsafe static void UpdateNameplateEntityDistanceData()
{
mDistanceUpdateTimer.Restart();
Expand Down Expand Up @@ -140,17 +188,18 @@ private static bool ShouldDrawDistanceForNameplate( int i )
}
}

private static void NameplateDrawDetour(AddonEvent type, AddonArgs args )
private static void NameplateDrawDetour( AddonEvent type, AddonArgs args )
{
var pThis = (AddonNamePlate*)args.Addon;
var pNameplateAddon = (AddonNamePlate*)args.Addon;

try
{
if( mpNameplateAddon != pThis )
if( mpNameplateAddon != pNameplateAddon )
{
Service.PluginLog.Debug( $"Nameplate draw detour pointer mismatch: 0x{(IntPtr)mpNameplateAddon:X} -> 0x{(IntPtr)pThis:X}" );
Service.PluginLog.Debug( $"Nameplate draw detour pointer mismatch: 0x{(IntPtr)mpNameplateAddon:X} -> 0x{(IntPtr)pNameplateAddon:X}" );
// I don't know how to safely clean up our own nodes when the addon reloads. The addon might take care of our inserted nodes when it cleans itself up anyway.
for( int i = 0; i < mDistanceTextNodes.Length; ++i ) mDistanceTextNodes[i] = null;
mpNameplateAddon = pThis;
mpNameplateAddon = pNameplateAddon;
if( mpNameplateAddon != null ) CreateNameplateDistanceNodes();
}

Expand All @@ -161,6 +210,7 @@ private static void NameplateDrawDetour(AddonEvent type, AddonArgs args )
{
Service.PluginLog.Error( $"Unknown error in nameplate draw hook. Disabling nameplate distances.\r\n{e}" );
mConfiguration.NameplateDistancesConfig.ShowNameplateDistances = false;
DisableNameplateDistances();
}
}

Expand All @@ -177,6 +227,9 @@ private static void HideAllNameplateDistanceNodes()
// same, but it also won't make sense to the user to have font sizes for nameplates not match font sizes elsewhere,
// so we also multiply the configured font size by the inverse of the node scale to get the real font size. This
// scaling also affects alignment calculations, so beware.

//***** TODO: This probably actually depends on whether the game is set to use high res UI (under graphics settings). Test this and account for it if necessary.

private static void UpdateNameplateDistanceNodes()
{
mNodeUpdateTimer.Restart();
Expand Down Expand Up @@ -598,10 +651,11 @@ private static void UpdateNameplateDistanceTextNode( int i, string str, TextNode
internal static int DEBUG_mNameplateTextFlags2 = 0;

// Delgates and Hooks
private delegate void NameplateDrawFuncDelegate(AddonEvent type, AddonArgs args);
private delegate void NameplateDrawFuncDelegate( AddonEvent type, AddonArgs args );
private static readonly NameplateDrawFuncDelegate mdNameplateDraw = new( NameplateDrawDetour );

// Members
private static bool mEnabled = false;
private static readonly DistanceInfo[] mNameplateDistanceInfoArray = new DistanceInfo[AddonNamePlate.NumNamePlateObjects];
private static readonly bool[] mShouldDrawDistanceInfoArray = new bool[AddonNamePlate.NumNamePlateObjects];
private static Configuration mConfiguration = null;
Expand Down
7 changes: 5 additions & 2 deletions Distance/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public Plugin( IDalamudPluginInterface pluginInterface )
// UI Initialization
mUI = new PluginUI( this, mPluginInterface, mConfiguration );
mPluginInterface.UiBuilder.Draw += DrawUI;
mPluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
mPluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
mUI.Initialize();
NameplateHandler.Init( mConfiguration );

Expand All @@ -85,7 +85,7 @@ public void Dispose()
Service.Framework.Update -= OnGameFrameworkUpdate;
Service.ClientState.TerritoryChanged -= OnTerritoryChanged;
mPluginInterface.UiBuilder.Draw -= DrawUI;
mPluginInterface.UiBuilder.OpenConfigUi -= DrawConfigUI;
mPluginInterface.UiBuilder.OpenConfigUi -= DrawConfigUI;
mPluginInterface.LanguageChanged -= OnLanguageChanged;
Service.CommandManager.RemoveHandler( mTextCommandName );
mUI.Dispose();
Expand Down Expand Up @@ -308,6 +308,9 @@ private string ProcessTextCommand_Help( string args )
private void OnGameFrameworkUpdate( IFramework framework )
{
UpdateTargetDistanceData();

if( mConfiguration.NameplateDistancesConfig.ShowNameplateDistances ) NameplateHandler.EnableNameplateDistances();
else NameplateHandler.DisableNameplateDistances();
}

private void OnTerritoryChanged( UInt16 ID )
Expand Down
43 changes: 13 additions & 30 deletions Distance/TargetResolver.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
using System;

using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Hooking;

using FFXIVClientStructs.FFXIV.Client.UI.Misc;

namespace Distance;

internal static unsafe class TargetResolver
{
internal static void Init()
{
IntPtr fpUIMouseover = Service.SigScanner.ScanText("E8 ?? ?? ?? ?? 48 8B 7C 24 ?? 4C 8B 74 24 ?? 83 FD 02");
if( fpUIMouseover != IntPtr.Zero )
{
Service.PluginLog.Information( $"UIMouseover function signature found at 0x{fpUIMouseover:X}." );
mUIMouseoverHook = Service.GameInteropProvider.HookFromAddress<UIMouseoverDelegate>(fpUIMouseover, UIMouseoverDetour);
mUIMouseoverHook.Enable();
}
else
{
throw new Exception( "Unable to find the specified function signature for UI mouseover." );
}
}

internal static void Uninit()
{
mUIMouseoverHook?.Disable();
mUIMouseoverHook?.Dispose();
mUIMouseoverHook = null;
}

internal static IGameObject GetTarget( TargetType targetType )
Expand All @@ -35,11 +22,11 @@ internal static IGameObject GetTarget( TargetType targetType )
{
TargetType.Target_And_Soft_Target => Service.TargetManager.SoftTarget ?? Service.TargetManager.Target,
TargetType.FocusTarget => Service.TargetManager.FocusTarget,
TargetType.MouseOver_And_UIMouseOver_Target => mUIMouseoverTarget ?? Service.TargetManager.MouseOverTarget,
TargetType.MouseOver_And_UIMouseOver_Target => GetUIMouseoverTarget() ?? Service.TargetManager.MouseOverTarget,
TargetType.Target => Service.TargetManager.Target,
TargetType.SoftTarget => Service.TargetManager.SoftTarget,
TargetType.MouseOverTarget => Service.TargetManager.MouseOverTarget,
TargetType.UIMouseOverTarget => mUIMouseoverTarget,
TargetType.UIMouseOverTarget => GetUIMouseoverTarget(),
TargetType.TargetOfTarget => GetTargetOfTarget(),
_ => throw new Exception( $"Request to resolve unknown target type: \"{targetType}\"." ),
};
Expand All @@ -58,21 +45,17 @@ private static IGameObject GetTargetOfTarget()
}
}

private static void UIMouseoverDetour( IntPtr pThis, IntPtr pActor )
private static IGameObject GetUIMouseoverTarget()
{
mUIMouseoverHook.Original( pThis, pActor );

if( pActor != IntPtr.Zero )
{
mUIMouseoverTarget = pActor != IntPtr.Zero ? Service.ObjectTable.CreateObjectReference( pActor ) : null;
}
else
if( PronounModule.Instance() != null )
{
mUIMouseoverTarget = null;
var pActor = (IntPtr)PronounModule.Instance()->UiMouseOverTarget;
if( pActor != IntPtr.Zero )
{
return Service.ObjectTable.CreateObjectReference( (IntPtr)pActor );
}
}
}

private delegate void UIMouseoverDelegate( IntPtr pThis, IntPtr pActor );
private static Hook<UIMouseoverDelegate> mUIMouseoverHook;
private static IGameObject mUIMouseoverTarget = null;
return null;
}
}
4 changes: 3 additions & 1 deletion Distance/ToDo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Arbitrary Arcs:


Priority:

-New nameplate difference feels like it might mostly just actually be the "Glare" flag on the text node. Do more testing. It might be the other new flag(s) too, but only when fading in from distance?
-Add fading for aggro text/arc, but realistically, wait until aggro arcs overhaul.
-Make the aggro distance arc have a deg/yalm option like for custom arcs.
-Go over distance-based coloring options for non-arc things and make sure that they are sane.
Expand All @@ -39,6 +39,7 @@ Priority:
-JSON, etc. out because duplicating the schema for every row is stupid.
-Make it two files: a data file, and a version file that contains only the version number and a hash of the data file for verification.
-Allows for only a very small file that's downloaded every time to check version, even if data size balloons.
-Investigate whether the 0.5x font scaling in nameplates is due to the high-res UI option, and account for that if necessary.


Cleanup:
Expand All @@ -58,6 +59,7 @@ Maybe:
-Add custom position/coordinate readout widgets.
-Radius option for arc pip.
-Thickness options for pip and arc?
-Raycast and have result as a coloring option for self-centered arcs (i.e., turn an arc red if it would put you off the edge).
-Add an option to export and import widget/arc configs, but the config options might not be the most stable things ever, so how much of a mess could this end up being?
-Use job icons instead of abbreviations in the classjob filters config?
-Revisit making distance-based colors optionally gradients.
Expand Down
4 changes: 2 additions & 2 deletions Distance/UI/PluginUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public PluginUI( Plugin plugin, IDalamudPluginInterface pluginInterface, Configu
CustomArcsUI = new( plugin, this, configuration );
GeneralSettingsUI = new( plugin, this, configuration );
NameplatesUI = new( plugin, this, configuration );
}
}

public unsafe void Dispose()
public unsafe void Dispose()
{
// This is just to make sure that no nodes get left visible after we stop managing them. We should probably be properly removing and freeing the
// nodes, but by checking for a node with the right id before constructing one, we should only ever have a one-time leak per node, which is probably fine.
Expand Down
4 changes: 2 additions & 2 deletions Distance/UI/PluginUI_Nameplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ internal void DrawConfigOptions()
ImGui.Checkbox( Loc.Localize( "Config Option: Nameplates - Show Distance on Aggro", "Show distance on enemies aggressive to you." ) + $"###Show distance to aggro (nameplates).", ref mConfiguration.NameplateDistancesConfig.ShowAggressive );
ImGuiUtils.HelpMarker( Loc.Localize( "Help: Nameplates - Show Distance on Aggro", "This only applies to targets shown in the enemy list. Distances for additional enemies aggressive to you will not be shown." ) );
ImGui.Checkbox( Loc.Localize( "Config Option: Nameplates - Show Distance on Party", "Show distance on party members." ) + $"###Show distance to party (nameplates).", ref mConfiguration.NameplateDistancesConfig.ShowPartyMembers );
ImGuiUtils.HelpMarker( Loc.Localize( "Help: Nameplates - Show Distance on Party", "This does not apply to cross-world party members." ) );
ImGuiUtils.HelpMarker( Loc.Localize( "Help: Nameplates - Show Distance on Party", "This does not apply to cross-world party members until you have entered an instanced duty." ) );
ImGui.Checkbox( Loc.Localize( "Config Option: Nameplates - Show Distance on Alliance", "Show distance on alliance members." ) + $"###Show distance to alliance (nameplates).", ref mConfiguration.NameplateDistancesConfig.ShowAllianceMembers );
ImGuiUtils.HelpMarker( Loc.Localize( "Help: Nameplates - Show Distance on Alliance", "This does not apply to cross-world alliance members." ) );
ImGuiUtils.HelpMarker( Loc.Localize( "Help: Nameplates - Show Distance on Alliance", "This does not apply to cross-world alliance members until you have entered an instanced duty." ) );
ImGui.Checkbox( Loc.Localize( "Config Option: Filters are Exclusive", "Filters are exclusive." ) + $"###Filters are exclusive (nameplates).", ref mConfiguration.NameplateDistancesConfig.FiltersAreExclusive );
ImGuiUtils.HelpMarker( Loc.Localize( "Help: Nameplates - Filters are Exclusive", "If this is checked, distances will be shown only when an object meets both the criteria above AND the filters below. If it is unchecked, distances will be shown for objects that meet EITHER criteria." ) );
ImGui.Unindent();
Expand Down

0 comments on commit fa74fa6

Please sign in to comment.