Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1c833ebcf | |||
| 3afa7af645 | |||
| 1cccf8967a | |||
| f1864f4cac | |||
| d8457e8d87 |
@@ -102,7 +102,6 @@ public unsafe class AddonAreaMapController : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the window actually considered closed by the agent.
|
|
||||||
if (AgentMap.Instance()->AddonId is 0)
|
if (AgentMap.Instance()->AddonId is 0)
|
||||||
{
|
{
|
||||||
System.WindowManager.GetWindow<MapWindow>()?.Close();
|
System.WindowManager.GetWindow<MapWindow>()?.Close();
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
private int _silentRefreshHideFramesRemaining;
|
private int _silentRefreshHideFramesRemaining;
|
||||||
/// <summary>Frames to skip quest/temp-marker-triggered silent refresh after user opened map via Duty List (quest/gathering/flag/teleport).</summary>
|
/// <summary>Frames to skip quest/temp-marker-triggered silent refresh after user opened map via Duty List (quest/gathering/flag/teleport).</summary>
|
||||||
private int _suppressSilentRefreshFramesRemaining;
|
private int _suppressSilentRefreshFramesRemaining;
|
||||||
|
/// <summary>Frames after user opened map via Duty List; OnShowHook should not Hide() during this window (ProcessingCommand is cleared when MapWindow opens).</summary>
|
||||||
|
private int _userOpenedMapFramesRemaining;
|
||||||
|
|
||||||
/// <summary>True while we're doing a silent refresh; OnAreaMapPreShow should not open the MapWindow.</summary>
|
/// <summary>True while we're doing a silent refresh; OnAreaMapPreShow should not open the MapWindow.</summary>
|
||||||
public static bool SilentRefreshInProgress { get; private set; }
|
public static bool SilentRefreshInProgress { get; private set; }
|
||||||
@@ -142,6 +144,9 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
if (_suppressSilentRefreshFramesRemaining > 0) {
|
if (_suppressSilentRefreshFramesRemaining > 0) {
|
||||||
_suppressSilentRefreshFramesRemaining--;
|
_suppressSilentRefreshFramesRemaining--;
|
||||||
}
|
}
|
||||||
|
if (_userOpenedMapFramesRemaining > 0) {
|
||||||
|
_userOpenedMapFramesRemaining--;
|
||||||
|
}
|
||||||
var skipQuestTempRefresh = _suppressSilentRefreshFramesRemaining > 0;
|
var skipQuestTempRefresh = _suppressSilentRefreshFramesRemaining > 0;
|
||||||
|
|
||||||
var questCount = GetActiveQuestCount();
|
var questCount = GetActiveQuestCount();
|
||||||
@@ -189,9 +194,11 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Call when user opens map via Duty List (quest/gathering/flag/teleport). Suppresses quest/temp-marker-triggered silent refresh for ~1s so we don't close the map.</summary>
|
/// <summary>Call when user opens map via Duty List (quest/gathering/flag/teleport). Cancels any in-progress silent refresh so we never Hide() the map. Suppresses new quest/temp-marker-triggered refresh for ~1s. Must be called BEFORE openMapHook.Original so OnFrameworkUpdate cannot call Hide() first.</summary>
|
||||||
private void SuppressSilentRefreshForUserMapOpen()
|
private void SuppressSilentRefreshForUserMapOpen()
|
||||||
{
|
{
|
||||||
|
_silentRefreshHideFramesRemaining = 0; // Cancel in-progress silent refresh so we never Hide() the map the user just opened
|
||||||
|
SilentRefreshInProgress = false;
|
||||||
_suppressSilentRefreshFramesRemaining = 30; // ~1 second at typical framerate
|
_suppressSilentRefreshFramesRemaining = 30; // ~1 second at typical framerate
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,29 +266,34 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
{
|
{
|
||||||
Service.Log.Verbose("[OnShow] Beginning Show");
|
Service.Log.Verbose("[OnShow] Beginning Show");
|
||||||
|
|
||||||
// If you managed to open the window while the agent says it should be closed
|
// When user just opened via Duty List / gathering / flag / teleport, pass through immediately.
|
||||||
if (System.MapWindow.IsOpen && AgentMap.Instance()->AddonId is 0)
|
var userRequestedMap = System.MapWindow.ProcessingCommand || _userOpenedMapFramesRemaining > 0;
|
||||||
|
if (userRequestedMap)
|
||||||
|
{
|
||||||
|
showMapHook!.Original(agent, a1, a2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var addonId = AgentMap.Instance()->AddonId;
|
||||||
|
var currentMapId = AgentMap.Instance()->CurrentMapId;
|
||||||
|
var selectedMapId = AgentMap.Instance()->SelectedMapId;
|
||||||
|
|
||||||
|
if (System.MapWindow.IsOpen && addonId is 0)
|
||||||
{
|
{
|
||||||
Service.Log.Debug("[OnShow] MapWindow can not be open now.");
|
Service.Log.Debug("[OnShow] MapWindow can not be open now.");
|
||||||
System.MapWindow.Close();
|
System.MapWindow.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow map when user explicitly opened via Duty List / gathering / flag / teleport
|
if (!ShouldShowMap())
|
||||||
if (!ShouldShowMap() && !System.MapWindow.ProcessingCommand)
|
|
||||||
{
|
{
|
||||||
Service.Log.Debug("[OnShow] Condition to open map is rejected, aborting.");
|
Service.Log.Debug("[OnShow] Condition to open map is rejected, aborting.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AgentMap.Instance()->AddonId is not 0 &&
|
// CurrentMapId != SelectedMapId = viewing quest map in different zone; pass through, don't Hide()
|
||||||
AgentMap.Instance()->CurrentMapId != AgentMap.Instance()->SelectedMapId)
|
if (addonId is not 0 && currentMapId != selectedMapId)
|
||||||
{
|
{
|
||||||
if (!System.SystemConfig.KeepOpen)
|
showMapHook!.Original(agent, a1, a2);
|
||||||
{
|
|
||||||
AgentMap.Instance()->Hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
Service.Log.Verbose("[OnShow] Vanilla tried to return to current map, aborted.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,9 +313,14 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
private void OnOpenMapHook(AgentMap* agent, OpenMapInfo* mapInfo) =>
|
private void OnOpenMapHook(AgentMap* agent, OpenMapInfo* mapInfo) =>
|
||||||
HookSafety.ExecuteSafe(() =>
|
HookSafety.ExecuteSafe(() =>
|
||||||
{
|
{
|
||||||
// Set before Original so ShowMap (if called synchronously) can bypass ShouldShowMap rejection
|
// MUST run before Original: cancel any in-progress silent refresh so OnFrameworkUpdate won't call Hide()
|
||||||
|
// after the game opens the map. Also set flags for OnShowHook pass-through.
|
||||||
if (IsUserInitiatedMapOpen(mapInfo->Type))
|
if (IsUserInitiatedMapOpen(mapInfo->Type))
|
||||||
|
{
|
||||||
|
SuppressSilentRefreshForUserMapOpen();
|
||||||
System.MapWindow.ProcessingCommand = true;
|
System.MapWindow.ProcessingCommand = true;
|
||||||
|
_userOpenedMapFramesRemaining = 30; // Persists after ProcessingCommand cleared by MapWindow.OnOpen
|
||||||
|
}
|
||||||
|
|
||||||
openMapHook!.Original(agent, mapInfo);
|
openMapHook!.Original(agent, mapInfo);
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,10 @@ public class SystemConfig : CharacterConfiguration
|
|||||||
public bool MinimapShowQuestAreaRadius = true;
|
public bool MinimapShowQuestAreaRadius = true;
|
||||||
/// <summary>When true, minimap hides with the game GUI (dialogue, interaction, nameplates off). When false, minimap stays visible during dialogue and object interaction.</summary>
|
/// <summary>When true, minimap hides with the game GUI (dialogue, interaction, nameplates off). When false, minimap stays visible during dialogue and object interaction.</summary>
|
||||||
public bool MinimapHideWithGameGui = false;
|
public bool MinimapHideWithGameGui = false;
|
||||||
|
/// <summary>Show Player/NPC tracking (other players, enemies, bosses, etc.) on the minimap, matching the main map display.</summary>
|
||||||
|
public bool MinimapShowPlayersAndNpcs = true;
|
||||||
|
/// <summary>Icon ID for other players on the minimap (default 60403, distinct from party 60421). Override if you prefer a different look.</summary>
|
||||||
|
public uint MinimapOtherPlayerIconId = 60403;
|
||||||
|
|
||||||
// Do not persist this setting
|
// Do not persist this setting
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||||
@@ -18,6 +19,52 @@ namespace Mappy.MapRenderer;
|
|||||||
|
|
||||||
public partial class MapRenderer
|
public partial class MapRenderer
|
||||||
{
|
{
|
||||||
|
private unsafe void DrawMinimapGameObjects(
|
||||||
|
Vector2 contentTopLeft,
|
||||||
|
Func<float, float, Vector2> texToContent,
|
||||||
|
Vector2 size,
|
||||||
|
float scaleFactor,
|
||||||
|
float offsetX,
|
||||||
|
float offsetY)
|
||||||
|
{
|
||||||
|
if (!System.SystemConfig.MinimapShowPlayersAndNpcs) return;
|
||||||
|
if (Service.ObjectTable is not { LocalPlayer: { } player }) return;
|
||||||
|
|
||||||
|
foreach (var obj in Service.ObjectTable.Reverse())
|
||||||
|
{
|
||||||
|
if (!obj.IsTargetable) continue;
|
||||||
|
if (GroupManager.Instance()->MainGroup.IsEntityIdInParty(obj.EntityId)) continue;
|
||||||
|
if (GroupManager.Instance()->MainGroup.IsEntityIdInAlliance(obj.EntityId)) continue;
|
||||||
|
if (Vector3.Distance(obj.Position, player.Position) >= 150.0f) continue;
|
||||||
|
|
||||||
|
var iconId = obj.ObjectKind switch
|
||||||
|
{
|
||||||
|
ObjectKind.Player when System.SystemConfig.ShowPlayers => System.SystemConfig.MinimapOtherPlayerIconId,
|
||||||
|
ObjectKind.BattleNpc when IsBoss(obj) && obj.TargetObject is null => 60402u,
|
||||||
|
ObjectKind.BattleNpc when IsBoss(obj) && obj.TargetObject is not null => 60401u,
|
||||||
|
ObjectKind.BattleNpc when obj is { SubKind: (int)BattleNpcSubKind.Enemy, TargetObject: not null } => 60422u,
|
||||||
|
ObjectKind.BattleNpc when obj is { SubKind: (int)BattleNpcSubKind.Enemy, TargetObject: null } => 60424u,
|
||||||
|
ObjectKind.BattleNpc when obj.SubKind == (int)BattleNpcSubKind.Pet => 60961u,
|
||||||
|
ObjectKind.Treasure => 60003u,
|
||||||
|
ObjectKind.GatheringPoint => System.GatheringPointIconCache.GetValue(obj.BaseId),
|
||||||
|
ObjectKind.EventObj when IsAetherCurrent(obj) => 60653u,
|
||||||
|
_ => 0u
|
||||||
|
};
|
||||||
|
|
||||||
|
if (iconId is 0) continue;
|
||||||
|
if (System.IconConfig.IconSettingMap.TryGetValue(iconId, out var setting) && setting.Hide) continue;
|
||||||
|
|
||||||
|
var pos = new Vector2(obj.Position.X, obj.Position.Z);
|
||||||
|
var tx = 1024.0f + (pos.X - offsetX) * scaleFactor;
|
||||||
|
var ty = 1024.0f + (pos.Y - offsetY) * scaleFactor;
|
||||||
|
var contentPos = texToContent(tx, ty);
|
||||||
|
if (!IsInMinimapBounds(contentPos, size, MinimapBoundsMargin)) continue;
|
||||||
|
|
||||||
|
var tooltip = GetTooltipForGameObject(obj);
|
||||||
|
DrawMinimapIcon(iconId, contentPos + contentTopLeft, sizeScale: 1.5f, tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe void DrawGameObjects()
|
private unsafe void DrawGameObjects()
|
||||||
{
|
{
|
||||||
if (AgentMap.Instance()->SelectedMapId != AgentMap.Instance()->CurrentMapId) return;
|
if (AgentMap.Instance()->SelectedMapId != AgentMap.Instance()->CurrentMapId) return;
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ public partial class MapRenderer
|
|||||||
DrawMinimapGatheringMarkers(contentTopLeft, TexToContent, size);
|
DrawMinimapGatheringMarkers(contentTopLeft, TexToContent, size);
|
||||||
// Party / alliance members (same marker as main map)
|
// Party / alliance members (same marker as main map)
|
||||||
DrawMinimapGroupMembers(contentTopLeft, TexToContent, size, scaleFactor, offsetX, offsetY);
|
DrawMinimapGroupMembers(contentTopLeft, TexToContent, size, scaleFactor, offsetX, offsetY);
|
||||||
|
// Player / NPC tracking (other players, enemies, bosses, etc.)
|
||||||
|
DrawMinimapGameObjects(contentTopLeft, TexToContent, size, scaleFactor, offsetX, offsetY);
|
||||||
// User flag
|
// User flag
|
||||||
DrawMinimapFlag(contentTopLeft, TexToContent, scaleFactor, offsetX, offsetY);
|
DrawMinimapFlag(contentTopLeft, TexToContent, scaleFactor, offsetX, offsetY);
|
||||||
// Temporary (quest objectives, etc.)
|
// Temporary (quest objectives, etc.)
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<Name>HSMappy</Name>
|
<Name>HSMappy</Name>
|
||||||
<InternalName>HSMappy</InternalName>
|
<InternalName>HSMappy</InternalName>
|
||||||
<Author>Knack117</Author>
|
<Author>Knack117</Author>
|
||||||
<Version>1.0.0.7</Version>
|
<Version>1.0.0.12</Version>
|
||||||
<Punchline>A more versatile in-game map.</Punchline>
|
<Punchline>A more versatile in-game map.</Punchline>
|
||||||
<Description>Replaces the in-game map with an ImGui implementation with several additional features. Fork with minimap improvements, quest radius on minimap, and more.</Description>
|
<Description>Replaces the in-game map with an ImGui implementation with several additional features. Fork with minimap improvements, quest radius on minimap, and more.</Description>
|
||||||
<RepoUrl>http://brassnet.ddns.net:33983/KnackAtNite/HSMappy</RepoUrl>
|
<RepoUrl>http://brassnet.ddns.net:33983/KnackAtNite/HSMappy</RepoUrl>
|
||||||
|
|||||||
@@ -286,6 +286,16 @@ public class MinimapOptionsTab : ITabItem
|
|||||||
configChanged |= ImGui.Checkbox("Show Quest Area Radius", ref System.SystemConfig.MinimapShowQuestAreaRadius);
|
configChanged |= ImGui.Checkbox("Show Quest Area Radius", ref System.SystemConfig.MinimapShowQuestAreaRadius);
|
||||||
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
ImGui.SetTooltip("Show quest objective area circles on the minimap (same as on the Area Map).");
|
ImGui.SetTooltip("Show quest objective area circles on the minimap (same as on the Area Map).");
|
||||||
|
configChanged |= ImGui.Checkbox("Show Players and NPCs", ref System.SystemConfig.MinimapShowPlayersAndNpcs);
|
||||||
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
ImGui.SetTooltip("Show Player/NPC tracking on the minimap (other players, enemies, bosses, etc.), matching the main map display.");
|
||||||
|
var otherPlayerIcon = (int)System.SystemConfig.MinimapOtherPlayerIconId;
|
||||||
|
if (ImGui.DragInt("Other Player Icon (minimap)", ref otherPlayerIcon, 1.0f, 60000, 61000, "%d")) {
|
||||||
|
System.SystemConfig.MinimapOtherPlayerIconId = (uint)Math.Clamp(otherPlayerIcon, 60000, 61000);
|
||||||
|
configChanged = true;
|
||||||
|
}
|
||||||
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
ImGui.SetTooltip("Icon ID for other players on the minimap (default 60403). Must be distinct from party marker (60421).");
|
||||||
configChanged |= ImGui.Checkbox("Hide Minimap With Game GUI", ref System.SystemConfig.MinimapHideWithGameGui);
|
configChanged |= ImGui.Checkbox("Hide Minimap With Game GUI", ref System.SystemConfig.MinimapHideWithGameGui);
|
||||||
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
ImGui.SetTooltip("When enabled, the minimap hides during NPC dialogue, object interaction, and when the game hides nameplates (same as the main map). When disabled, the minimap stays visible in those situations.");
|
ImGui.SetTooltip("When enabled, the minimap hides during NPC dialogue, object interaction, and when the game hides nameplates (same as the main map). When disabled, the minimap stays visible in those situations.");
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ public class MapWindow : Window
|
|||||||
|
|
||||||
public override unsafe void PreOpenCheck()
|
public override unsafe void PreOpenCheck()
|
||||||
{
|
{
|
||||||
// If you managed to open the window while the agent says it should be closed
|
|
||||||
if (System.MapWindow.IsOpen && AgentMap.Instance()->AddonId is 0)
|
if (System.MapWindow.IsOpen && AgentMap.Instance()->AddonId is 0)
|
||||||
{
|
{
|
||||||
Service.Log.Debug("[OnShow] MapWindow can not be open now.");
|
Service.Log.Debug("[OnShow] MapWindow can not be open now.");
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[{"Author":"Knack117","Name":"HSMappy","Punchline":"A more versatile in-game map.","Description":"Replaces the in-game map with an ImGui implementation with several additional features. Fork with minimap improvements, quest radius on minimap, white gradient player cone, and more.","Changelog":"1.0.0.7: Duty List quest click opens Area Map even when Hide With Game GUI would block it. 1.0.0.6: Minimap stays open after client restart (restore on login). 1.0.0.5: Fix crash when map texture path is invalid (ArgumentOutOfRangeException in Lumina GetFileHash). 1.0.0.4: Temp marker circle refreshes when quest objective is progressed. 1.0.0.3: Fix marker cache refresh after quest turn-in; invalidate temp cache so old markers don't persist. 1.0.0.2: Red direction arrow on minimap pointing to player flag. 1.0.0.1: Duty List quest click keeps Area Map open; player flags show on minimap. 1.0.0.0: Initial HSMappy release. Minimap: quest radius circle (orange, transparent), tooltip; cone drawn under markers; white gradient cone; /hsmappy commands.","InternalName":"HSMappy","AssemblyVersion":"1.0.0.7","RepoUrl":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy","ApplicableVersion":"any","Tags":["map","mapping","overlay","utility"],"CategoryTags":["jobs"],"DalamudApiLevel":14,"DownloadLinkInstall":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.7/latest.zip","IsHide":false,"IsTestingExclusive":false,"DownloadLinkTesting":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.7/latest.zip","DownloadLinkUpdate":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.7/latest.zip","LastUpdate":"1772233231"}]
|
[{"Author":"Knack117","Name":"HSMappy","Punchline":"A more versatile in-game map.","Description":"Replaces the in-game map with an ImGui implementation with several additional features. Fork with minimap improvements, quest radius on minimap, white gradient player cone, and more.","Changelog":"1.0.0.12: Other players on minimap use distinct icon (60403) from party markers. 1.0.0.11: Player/NPC tracking on minimap with Show Players and NPCs toggle. 1.0.0.10: Release build. Suppress silent refresh at start of OnOpenMapHook; remove debug logging. 1.0.0.9: Duty List quest click: don't Hide() when viewing quest map (SelectedMapId != CurrentMapId). 1.0.0.8: Cancel silent refresh when opening map from Duty List so it doesn't immediately close. 1.0.0.7: Duty List quest click opens Area Map even when Hide With Game GUI would block it. 1.0.0.6: Minimap stays open after client restart (restore on login). 1.0.0.5: Fix crash when map texture path is invalid (ArgumentOutOfRangeException in Lumina GetFileHash). 1.0.0.4: Temp marker circle refreshes when quest objective is progressed. 1.0.0.3: Fix marker cache refresh after quest turn-in; invalidate temp cache so old markers don't persist. 1.0.0.2: Red direction arrow on minimap pointing to player flag. 1.0.0.1: Duty List quest click keeps Area Map open; player flags show on minimap. 1.0.0.0: Initial HSMappy release. Minimap: quest radius circle (orange, transparent), tooltip; cone drawn under markers; white gradient cone; /hsmappy commands.","InternalName":"HSMappy","AssemblyVersion":"1.0.0.12","RepoUrl":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy","ApplicableVersion":"any","Tags":["map","mapping","overlay","utility"],"CategoryTags":["jobs"],"DalamudApiLevel":14,"DownloadLinkInstall":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.12/latest.zip","IsHide":false,"IsTestingExclusive":false,"DownloadLinkTesting":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.12/latest.zip","DownloadLinkUpdate":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.12/latest.zip","LastUpdate":"1772313500"}]
|
||||||
|
|||||||
Reference in New Issue
Block a user