feat: suppress treasure map opening

This commit is contained in:
Anna 2021-04-16 08:01:48 -04:00
parent 91a454d768
commit 532b8e46b7
4 changed files with 93 additions and 32 deletions

View File

@ -5,19 +5,20 @@ using System;
namespace Globetrotter { namespace Globetrotter {
[Serializable] [Serializable]
internal class Configuration : IPluginConfiguration { internal class Configuration : IPluginConfiguration {
private DalamudPluginInterface _pi; private DalamudPluginInterface Plugin { get; set; } = null!;
public int Version { get; set; } = 1; public int Version { get; set; } = 1;
public bool ShowOnHover { get; set; } = true; public bool ShowOnHover { get; set; } = true;
public bool ShowOnDecipher { get; set; } = true;
public bool ShowOnOpen { get; set; } = true; public bool ShowOnOpen { get; set; } = true;
public void Initialize(DalamudPluginInterface pi) { public void Initialize(DalamudPluginInterface pi) {
this._pi = pi ?? throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null"); this.Plugin = pi ?? throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null");
} }
public void Save() { public void Save() {
this._pi.SavePluginConfig(this); this.Plugin.SavePluginConfig(this);
} }
} }
} }

View File

@ -4,6 +4,7 @@
<Version>1.1.4</Version> <Version>1.1.4</Version>
<TargetFramework>net48</TargetFramework> <TargetFramework>net48</TargetFramework>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Dalamud"> <Reference Include="Dalamud">
@ -28,6 +29,6 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="1.2.1"/> <PackageReference Include="DalamudPackager" Version="1.2.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,6 @@
using ImGuiNET; using ImGuiNET;
using System; using System;
using System.Numerics;
namespace Globetrotter { namespace Globetrotter {
internal class PluginUi { internal class PluginUi {
@ -25,28 +26,52 @@ namespace Globetrotter {
return; return;
} }
ImGui.SetNextWindowSize(new Vector2(350, 250), ImGuiCond.FirstUseEver);
if (!ImGui.Begin("Globetrotter settings", ref this._displaySettings)) { if (!ImGui.Begin("Globetrotter settings", ref this._displaySettings)) {
ImGui.End();
return; return;
} }
ImGui.TextUnformatted("Use /tmap to open your current treasure map."); ImGui.TextUnformatted("Use /tmap to open your current treasure map.");
ImGui.TextUnformatted("If you have a map and this plugin isn't working, change zone.");
ImGui.Separator();
var showOnDecipher = this.Config.ShowOnDecipher;
if (HelpCheckbox("Show on decipher", "Open the map with a flag set after deciphering a map.", ref showOnDecipher)) {
this.Config.ShowOnDecipher = showOnDecipher;
this.Config.Save();
}
ImGui.Separator();
var showOnOpen = this.Config.ShowOnOpen;
if (HelpCheckbox("Show on open", "Open the map with a flag set instead of the normal treasure map window.", ref showOnOpen)) {
this.Config.ShowOnOpen = showOnOpen;
this.Config.Save();
}
ImGui.Separator(); ImGui.Separator();
var showOnHover = this.Config.ShowOnHover; var showOnHover = this.Config.ShowOnHover;
if (ImGui.Checkbox("Show on hover", ref showOnHover)) { if (HelpCheckbox("Show on hover", "Open the map with a flag set when hovering over a deciphered map.", ref showOnHover)) {
this.Config.ShowOnHover = showOnHover; this.Config.ShowOnHover = showOnHover;
this.Config.Save(); this.Config.Save();
} }
var showOnOpen = this.Config.ShowOnOpen;
if (ImGui.Checkbox("Show on open", ref showOnOpen)) {
this.Config.ShowOnOpen = showOnOpen;
this.Config.Save();
}
ImGui.End(); ImGui.End();
} }
private static bool HelpCheckbox(string label, string help, ref bool isChecked) {
var ret = ImGui.Checkbox(label, ref isChecked);
ImGui.TreePush();
ImGui.PushTextWrapPos();
ImGui.TextUnformatted(help);
ImGui.PopTextWrapPos();
ImGui.TreePop();
return ret;
}
} }
} }

View File

@ -3,6 +3,7 @@ using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
@ -10,7 +11,7 @@ namespace Globetrotter {
internal sealed class TreasureMaps : IDisposable { internal sealed class TreasureMaps : IDisposable {
private const uint TreasureMapsCode = 0x54; private const uint TreasureMapsCode = 0x54;
private static Dictionary<uint, uint> _mapToRow; private static Dictionary<uint, uint>? _mapToRow;
private Dictionary<uint, uint> MapToRow { private Dictionary<uint, uint> MapToRow {
get { get {
@ -26,7 +27,7 @@ namespace Globetrotter {
continue; continue;
} }
EventItem opened; EventItem? opened;
// FIXME: remove this try/catch when lumina is fixed // FIXME: remove this try/catch when lumina is fixed
try { try {
opened = rank.KeyItemName.Value; opened = rank.KeyItemName.Value;
@ -49,24 +50,31 @@ namespace Globetrotter {
private DalamudPluginInterface Interface { get; } private DalamudPluginInterface Interface { get; }
private Configuration Config { get; } private Configuration Config { get; }
private TreasureMapPacket _lastMap; private TreasureMapPacket? _lastMap;
private delegate char HandleActorControlSelfDelegate(long a1, long a2, IntPtr dataPtr); private delegate char HandleActorControlSelfDelegate(long a1, long a2, IntPtr dataPtr);
private delegate IntPtr ShowTreasureMapDelegate(IntPtr manager, ushort rowId, ushort subRowId, byte a4);
private readonly Hook<HandleActorControlSelfDelegate> _acsHook; private readonly Hook<HandleActorControlSelfDelegate> _acsHook;
private readonly Hook<ShowTreasureMapDelegate> _showMapHook;
public TreasureMaps(DalamudPluginInterface pi, Configuration config) { public TreasureMaps(DalamudPluginInterface pi, Configuration config) {
this.Interface = pi ?? throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null"); this.Interface = pi ?? throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null");
this.Config = config ?? throw new ArgumentNullException(nameof(config), "Configuration cannot be null"); this.Config = config ?? throw new ArgumentNullException(nameof(config), "Configuration cannot be null");
var delegatePtr = this.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 48 8B D9 49 8B F8 41 0F B7 08"); var acsPtr = this.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 48 8B D9 49 8B F8 41 0F B7 08");
if (delegatePtr == IntPtr.Zero) { this._acsHook = new Hook<HandleActorControlSelfDelegate>(acsPtr, new HandleActorControlSelfDelegate(this.OnACS));
PluginLog.Log("Unable to detect treasure maps because could not find ACS handler delegate");
return;
}
this._acsHook = new Hook<HandleActorControlSelfDelegate>(delegatePtr, new HandleActorControlSelfDelegate(this.OnACS));
this._acsHook.Enable(); this._acsHook.Enable();
var showMapPtr = this.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 40 84 FF 0F 85 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ??");
this._showMapHook = new Hook<ShowTreasureMapDelegate>(showMapPtr, new ShowTreasureMapDelegate(this.OnShowMap));
this._showMapHook.Enable();
}
public void Dispose() {
this._acsHook.Dispose();
this._showMapHook.Dispose();
} }
public void OnHover(object sender, ulong id) { public void OnHover(object sender, ulong id) {
@ -77,6 +85,36 @@ namespace Globetrotter {
this.OpenMapLocation(); this.OpenMapLocation();
} }
private IntPtr OnShowMap(IntPtr manager, ushort rowId, ushort subRowId, byte a4) {
try {
if (!this.OnShowMapInner(rowId, subRowId)) {
return IntPtr.Zero;
}
} catch (Exception ex) {
PluginLog.LogError(ex, "Exception on show map");
}
return this._showMapHook.Original(manager, rowId, subRowId, a4);
}
private bool OnShowMapInner(ushort rowId, ushort subRowId) {
if (this._lastMap == null) {
try {
var eventItemId = this.MapToRow.First(entry => entry.Value == rowId);
this._lastMap = new TreasureMapPacket(eventItemId.Key, subRowId, false);
} catch (InvalidOperationException) {
// no-op
}
}
if (!this.Config.ShowOnOpen && (!this.Config.ShowOnDecipher || this._lastMap?.JustOpened != true)) {
return true;
}
this.OpenMapLocation();
return false;
}
private char OnACS(long a1, long a2, IntPtr dataPtr) { private char OnACS(long a1, long a2, IntPtr dataPtr) {
try { try {
this.OnACSInner(dataPtr); this.OnACSInner(dataPtr);
@ -94,10 +132,6 @@ namespace Globetrotter {
} }
this._lastMap = packet; this._lastMap = packet;
if (this.Config.ShowOnOpen && packet.JustOpened) {
this.OpenMapLocation();
}
} }
public void OpenMapLocation() { public void OpenMapLocation() {
@ -132,9 +166,13 @@ namespace Globetrotter {
); );
this.Interface.Framework.Gui.OpenMapWithMapLink(mapLink); this.Interface.Framework.Gui.OpenMapWithMapLink(mapLink);
if (this._lastMap != null) {
this._lastMap.JustOpened = false;
}
} }
private static TreasureMapPacket ParsePacket(IntPtr dataPtr) { private static TreasureMapPacket? ParsePacket(IntPtr dataPtr) {
uint category = Marshal.ReadByte(dataPtr); uint category = Marshal.ReadByte(dataPtr);
if (category != TreasureMapsCode) { if (category != TreasureMapsCode) {
return null; return null;
@ -169,16 +207,12 @@ namespace Globetrotter {
val *= c; val *= c;
return (41f / c * ((val + 1024f) / 2048f)) + 1; return (41f / c * ((val + 1024f) / 2048f)) + 1;
} }
public void Dispose() {
this._acsHook?.Dispose();
}
} }
internal class TreasureMapPacket { internal class TreasureMapPacket {
public uint EventItemId { get; } public uint EventItemId { get; }
public uint SubRowId { get; } public uint SubRowId { get; }
public bool JustOpened { get; } public bool JustOpened { get; set; }
public TreasureMapPacket(uint eventItemId, uint subRowId, bool justOpened) { public TreasureMapPacket(uint eventItemId, uint subRowId, bool justOpened) {
this.EventItemId = eventItemId; this.EventItemId = eventItemId;