Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cccf8967a | |||
| f1864f4cac | |||
| d8457e8d87 | |||
| daaac71c83 | |||
| d10a550136 | |||
| c9b50f8f72 | |||
| 015d7ee191 | |||
| 2c54907cd5 |
@@ -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();
|
||||||
@@ -159,10 +164,15 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
RequestSilentRefresh(); // objectives added (e.g. new quest)
|
RequestSilentRefresh(); // objectives added (e.g. new quest)
|
||||||
if (_lastQuestSequenceSnapshot.Length > 0 && sequenceSnapshot != _lastQuestSequenceSnapshot)
|
if (_lastQuestSequenceSnapshot.Length > 0 && sequenceSnapshot != _lastQuestSequenceSnapshot)
|
||||||
RequestSilentRefresh(); // quest step advanced (multi-step objective)
|
RequestSilentRefresh(); // quest step advanced (multi-step objective)
|
||||||
|
_lastQuestCount = questCount;
|
||||||
|
_lastTempMarkerCount = tempCount;
|
||||||
|
_lastQuestSequenceSnapshot = sequenceSnapshot;
|
||||||
|
} else {
|
||||||
|
// During suppression: only update temp baseline so we don't false-trigger when suppression
|
||||||
|
// ends (e.g. Duty List click repopulates markers). Keep _lastQuestCount and _lastQuestSequenceSnapshot
|
||||||
|
// so quest turn-in and objective progression during suppression still trigger refresh when suppression ends.
|
||||||
|
_lastTempMarkerCount = tempCount;
|
||||||
}
|
}
|
||||||
_lastQuestCount = questCount;
|
|
||||||
_lastTempMarkerCount = tempCount;
|
|
||||||
_lastQuestSequenceSnapshot = sequenceSnapshot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Build a string of (QuestId, Sequence) for each active quest so we can detect step advances.</summary>
|
/// <summary>Build a string of (QuestId, Sequence) for each active quest so we can detect step advances.</summary>
|
||||||
@@ -184,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +216,9 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
var currentMapId = agent->CurrentMapId;
|
var currentMapId = agent->CurrentMapId;
|
||||||
if (currentMapId == 0) return;
|
if (currentMapId == 0) return;
|
||||||
|
|
||||||
|
// Clear temp marker cache so old markers (e.g. from turned-in quest) don't persist
|
||||||
|
MapRenderer.MapRenderer.InvalidateTempMarkerCache(currentMapId);
|
||||||
|
|
||||||
SilentRefreshInProgress = true;
|
SilentRefreshInProgress = true;
|
||||||
agent->OpenMapByMapId(currentMapId, 0, true);
|
agent->OpenMapByMapId(currentMapId, 0, true);
|
||||||
agent->ResetMapMarkers();
|
agent->ResetMapMarkers();
|
||||||
@@ -251,8 +266,19 @@ 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();
|
||||||
@@ -264,15 +290,10 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,9 +306,22 @@ public unsafe class IntegrationsController : IDisposable
|
|||||||
showMapHook!.Original(agent, a1, a2);
|
showMapHook!.Original(agent, a1, a2);
|
||||||
}, Service.Log, "Exception during OnShowHook");
|
}, Service.Log, "Exception during OnShowHook");
|
||||||
|
|
||||||
|
private static bool IsUserInitiatedMapOpen(MapType type) =>
|
||||||
|
type is MapType.QuestLog or MapType.GatheringLog or MapType.FlagMarker or MapType.Bozja
|
||||||
|
or MapType.MobHunt or MapType.SharedFate or MapType.Teleport or MapType.Treasure;
|
||||||
|
|
||||||
private void OnOpenMapHook(AgentMap* agent, OpenMapInfo* mapInfo) =>
|
private void OnOpenMapHook(AgentMap* agent, OpenMapInfo* mapInfo) =>
|
||||||
HookSafety.ExecuteSafe(() =>
|
HookSafety.ExecuteSafe(() =>
|
||||||
{
|
{
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
SuppressSilentRefreshForUserMapOpen();
|
||||||
|
System.MapWindow.ProcessingCommand = true;
|
||||||
|
_userOpenedMapFramesRemaining = 30; // Persists after ProcessingCommand cleared by MapWindow.OnOpen
|
||||||
|
}
|
||||||
|
|
||||||
openMapHook!.Original(agent, mapInfo);
|
openMapHook!.Original(agent, mapInfo);
|
||||||
|
|
||||||
switch (mapInfo->Type)
|
switch (mapInfo->Type)
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ public unsafe partial class MapRenderer : IDisposable
|
|||||||
// Markers are drawn from whatever the game has already populated (e.g. after opening the map once).
|
// Markers are drawn from whatever the game has already populated (e.g. after opening the map once).
|
||||||
|
|
||||||
// When the game has the current map loaded (area map open or just closed), update our cache for this map.
|
// When the game has the current map loaded (area map open or just closed), update our cache for this map.
|
||||||
if (agent->SelectedMapId == currentMapId && agent->SelectedMapPath.Length > 0) {
|
if (agent->SelectedMapId == currentMapId && agent->SelectedMapPath.Length > 0 && agent->SelectedMapBgPath.Length > 0) {
|
||||||
var bgPath = $"{agent->SelectedMapBgPath}.tex";
|
var bgPath = $"{agent->SelectedMapBgPath}.tex";
|
||||||
var fgPath = $"{agent->SelectedMapPath}.tex";
|
var fgPath = $"{agent->SelectedMapPath}.tex";
|
||||||
var pathKey = bgPath + "|" + fgPath;
|
var pathKey = bgPath + "|" + fgPath;
|
||||||
@@ -346,13 +346,23 @@ public unsafe partial class MapRenderer : IDisposable
|
|||||||
|
|
||||||
private static TexFile? GetTexFile(string rawPath)
|
private static TexFile? GetTexFile(string rawPath)
|
||||||
{
|
{
|
||||||
var path = Service.TextureSubstitutionProvider.GetSubstitutedPath(rawPath);
|
if (string.IsNullOrWhiteSpace(rawPath)) return null;
|
||||||
|
string path;
|
||||||
if (Path.IsPathRooted(path)) {
|
try {
|
||||||
return Service.DataManager.GameData.GetFileFromDisk<TexFile>(path);
|
path = Service.TextureSubstitutionProvider.GetSubstitutedPath(rawPath);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(path)) return null;
|
||||||
|
|
||||||
return Service.DataManager.GetFile<TexFile>(path);
|
try {
|
||||||
|
if (Path.IsPathRooted(path)) {
|
||||||
|
return Service.DataManager.GameData.GetFileFromDisk<TexFile>(path);
|
||||||
|
}
|
||||||
|
return Service.DataManager.GetFile<TexFile>(path);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMapMarkers()
|
private void DrawMapMarkers()
|
||||||
|
|||||||
@@ -369,6 +369,9 @@ public partial class MapRenderer
|
|||||||
/// <summary>Cached quest/objective (temp) markers per map; populated during silent refresh on quest accept/turn-in/objective update.</summary>
|
/// <summary>Cached quest/objective (temp) markers per map; populated during silent refresh on quest accept/turn-in/objective update.</summary>
|
||||||
private static readonly Dictionary<uint, List<CachedTempMarker>> TempMarkerCache = new();
|
private static readonly Dictionary<uint, List<CachedTempMarker>> TempMarkerCache = new();
|
||||||
|
|
||||||
|
/// <summary>Clear the temp marker cache for a map so stale markers (e.g. from a turned-in quest) are not drawn until we refresh.</summary>
|
||||||
|
public static void InvalidateTempMarkerCache(uint mapId) => TempMarkerCache.Remove(mapId);
|
||||||
|
|
||||||
/// <summary>Cached non-FATE event markers per map; populated during silent refresh.</summary>
|
/// <summary>Cached non-FATE event markers per map; populated during silent refresh.</summary>
|
||||||
private static readonly Dictionary<uint, List<CachedEventMarker>> EventMarkerCache = new();
|
private static readonly Dictionary<uint, List<CachedEventMarker>> EventMarkerCache = new();
|
||||||
|
|
||||||
|
|||||||
+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.2</Version>
|
<Version>1.0.0.10</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>
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Mappy.Windows;
|
|||||||
|
|
||||||
public class MinimapWindow : Window
|
public class MinimapWindow : Window
|
||||||
{
|
{
|
||||||
|
private bool _wasLoggedIn;
|
||||||
|
|
||||||
public MinimapWindow() : base("HSMappy Minimap###HSMappyMinimap", new Vector2(200.0f, 200.0f))
|
public MinimapWindow() : base("HSMappy Minimap###HSMappyMinimap", new Vector2(200.0f, 200.0f))
|
||||||
{
|
{
|
||||||
DisableWindowSounds = true;
|
DisableWindowSounds = true;
|
||||||
@@ -22,8 +24,18 @@ public class MinimapWindow : Window
|
|||||||
|
|
||||||
public override void PreOpenCheck()
|
public override void PreOpenCheck()
|
||||||
{
|
{
|
||||||
if (Service.ClientState is { IsLoggedIn: false } or { IsPvP: true })
|
var isLoggedIn = Service.ClientState is { IsLoggedIn: true, IsPvP: false };
|
||||||
|
if (!isLoggedIn)
|
||||||
|
{
|
||||||
IsOpen = false;
|
IsOpen = false;
|
||||||
|
_wasLoggedIn = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore minimap when transitioning from login screen to in-game (ShowMinimap persists in config)
|
||||||
|
if (!_wasLoggedIn && System.SystemConfig.ShowMinimap)
|
||||||
|
UnCollapseOrShow();
|
||||||
|
_wasLoggedIn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override unsafe void DrawContents()
|
protected override unsafe void DrawContents()
|
||||||
|
|||||||
@@ -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.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.2","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.2/latest.zip","IsHide":false,"IsTestingExclusive":false,"DownloadLinkTesting":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.2/latest.zip","DownloadLinkUpdate":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.2/latest.zip","LastUpdate":"1772140942"}]
|
[{"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.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.10","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.10/latest.zip","IsHide":false,"IsTestingExclusive":false,"DownloadLinkTesting":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.10/latest.zip","DownloadLinkUpdate":"http://brassnet.ddns.net:33983/KnackAtNite/HSMappy/releases/download/v1.0.0.10/latest.zip","LastUpdate":"1772237531"}]
|
||||||
|
|||||||
Reference in New Issue
Block a user