feat: begin adding addon window positions
This commit is contained in:
parent
358bbe491c
commit
7e4db37b2a
|
@ -6,7 +6,7 @@ using Dalamud.Plugin;
|
|||
namespace HUD_Manager.Configuration {
|
||||
[Serializable]
|
||||
public class Config : IPluginConfiguration {
|
||||
public const int LatestVersion = 4;
|
||||
public const int LatestVersion = 5;
|
||||
|
||||
public int Version { get; set; } = LatestVersion;
|
||||
|
||||
|
@ -15,7 +15,6 @@ namespace HUD_Manager.Configuration {
|
|||
public bool FirstRun { get; set; } = true;
|
||||
public bool UnderstandsRisks { get; set; }
|
||||
|
||||
public bool ImportPositions { get; set; }
|
||||
public bool SwapsEnabled { get; set; }
|
||||
|
||||
public HudSlot StagingSlot { get; set; } = HudSlot.Four;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Plugin;
|
||||
|
@ -25,20 +27,34 @@ namespace HUD_Manager.Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
var saved = new SavedLayout(entry.Value.Name, layout, entry.Value.Positions);
|
||||
var positions = entry.Value.Positions.ToDictionary(
|
||||
pos => pos.Key,
|
||||
pos => new Window(
|
||||
WindowComponent.X | WindowComponent.Y,
|
||||
pos.Value
|
||||
)
|
||||
);
|
||||
var saved = new SavedLayout(entry.Value.Name, layout, positions);
|
||||
config.Layouts[entry.Key] = saved;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
private static void WithEachElement(JObject old, Action<JObject> action) {
|
||||
private static void WithEachLayout(JObject old, Action<JObject> action) {
|
||||
foreach (var property in old["Layouts"].Children<JProperty>()) {
|
||||
if (property.Name == "$type") {
|
||||
continue;
|
||||
}
|
||||
|
||||
var layout = (JObject) property.Value;
|
||||
|
||||
action(layout);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WithEachElement(JObject old, Action<JObject> action) {
|
||||
WithEachLayout(old, layout => {
|
||||
var elements = (JObject) layout["Elements"];
|
||||
|
||||
foreach (var elementProp in elements.Children<JProperty>()) {
|
||||
|
@ -50,7 +66,7 @@ namespace HUD_Manager.Configuration {
|
|||
|
||||
action(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void MigrateV2(JObject old) {
|
||||
|
@ -84,6 +100,35 @@ namespace HUD_Manager.Configuration {
|
|||
old["Version"] = 4;
|
||||
}
|
||||
|
||||
private static void MigrateV4(JObject old) {
|
||||
WithEachLayout(old, layout => {
|
||||
var oldPositions = (JObject) layout["Positions"];
|
||||
var windows = new Dictionary<string, Window>();
|
||||
|
||||
foreach (var elementProp in oldPositions.Children<JProperty>()) {
|
||||
if (elementProp.Name == "$type") {
|
||||
continue;
|
||||
}
|
||||
|
||||
var position = (JObject) elementProp.Value;
|
||||
windows[elementProp.Name] = new Window(
|
||||
WindowComponent.X | WindowComponent.Y,
|
||||
new Vector2<short>(
|
||||
position["X"].ToObject<short>(),
|
||||
position["Y"].ToObject<short>()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
layout["Windows"] = JObject.FromObject(windows);
|
||||
|
||||
layout.Remove("Positions");
|
||||
});
|
||||
|
||||
old.Remove("ImportPositions");
|
||||
old["Version"] = 5;
|
||||
}
|
||||
|
||||
private static string PluginConfig(string? pluginName = null) {
|
||||
pluginName ??= Assembly.GetAssembly(typeof(Plugin)).GetName().Name;
|
||||
return Path.Combine(new[] {
|
||||
|
@ -149,6 +194,9 @@ namespace HUD_Manager.Configuration {
|
|||
case 3:
|
||||
MigrateV3(config);
|
||||
break;
|
||||
case 4:
|
||||
MigrateV4(config);
|
||||
break;
|
||||
default:
|
||||
PluginLog.Warning($"Tried to migrate from an unknown version: {version}");
|
||||
goto DefaultConfig;
|
||||
|
|
|
@ -8,23 +8,30 @@ namespace HUD_Manager.Configuration {
|
|||
[Serializable]
|
||||
public class SavedLayout {
|
||||
public Dictionary<ElementKind, Element> Elements { get; }
|
||||
public Dictionary<string, Vector2<short>> Positions { get; private set; }
|
||||
public Dictionary<string, Window> Windows { get; }
|
||||
// public Dictionary<string, Vector2<short>> Positions { get; private set; }
|
||||
public Guid Parent { get; set; } = Guid.Empty;
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
public SavedLayout(string name, Dictionary<ElementKind, Element> elements, Dictionary<string, Vector2<short>> positions, Guid parent) {
|
||||
public SavedLayout(string name, Dictionary<ElementKind, Element> elements, Dictionary<string, Window> windows, Guid parent) {
|
||||
this.Name = name;
|
||||
this.Elements = elements;
|
||||
this.Positions = positions;
|
||||
this.Windows = windows;
|
||||
this.Parent = parent;
|
||||
}
|
||||
|
||||
public SavedLayout(string name, Layout hud, Dictionary<string, Vector2<short>> positions) {
|
||||
public SavedLayout(string name, Layout hud, Dictionary<string, Window> windows) {
|
||||
this.Name = name;
|
||||
this.Elements = hud.ToDictionary();
|
||||
this.Positions = positions;
|
||||
this.Windows = windows;
|
||||
}
|
||||
|
||||
public SavedLayout(string name, Layout hud) {
|
||||
this.Name = name;
|
||||
this.Elements = hud.ToDictionary();
|
||||
this.Windows = new Dictionary<string, Window>();
|
||||
}
|
||||
|
||||
public Layout ToLayout() {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace HUD_Manager.Configuration {
|
||||
[Serializable]
|
||||
public class Window {
|
||||
public WindowComponent Enabled { get; set; } = WindowComponent.X | WindowComponent.Y;
|
||||
|
||||
public Vector2<short> Position { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
public Window(WindowComponent enabled, Vector2<short> position) {
|
||||
this.Enabled = enabled;
|
||||
this.Position = position;
|
||||
}
|
||||
|
||||
public Window(Vector2<short> position) {
|
||||
this.Position = position;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum WindowComponent {
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
}
|
|
@ -1,60 +1,82 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HUD_Manager {
|
||||
public class GameFunctions {
|
||||
private delegate IntPtr GetUiBaseDelegate();
|
||||
private delegate IntPtr GetUiWindowDelegate(IntPtr uiBase, string uiName, int index);
|
||||
private delegate void MoveWindowDelegate(IntPtr windowBase, short x, short y);
|
||||
// private delegate IntPtr GetBaseUiObjectDelegate();
|
||||
|
||||
private readonly GetUiBaseDelegate _getUiBase;
|
||||
private readonly GetUiWindowDelegate _getUiWindow;
|
||||
private readonly MoveWindowDelegate _moveWindow;
|
||||
private delegate void SetPositionDelegate(IntPtr windowBase, short x, short y);
|
||||
|
||||
private delegate void SetAlphaDelegate(IntPtr windowBase, byte alpha);
|
||||
|
||||
private delegate byte UpdateAddonPositionDelegate(IntPtr raptureAtkUnitManager, IntPtr addon, byte clicked);
|
||||
|
||||
// private readonly GetBaseUiObjectDelegate _getBaseUiObject;
|
||||
private readonly SetPositionDelegate _setPosition;
|
||||
private readonly SetAlphaDelegate _setAlpha;
|
||||
private readonly UpdateAddonPositionDelegate _updateAddonPosition;
|
||||
|
||||
private Plugin Plugin { get; }
|
||||
|
||||
public GameFunctions(Plugin plugin) {
|
||||
this.Plugin = plugin;
|
||||
|
||||
var getUiBasePtr = this.Plugin.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 41 b8 01 00 00 00 48 8d 15 ?? ?? ?? ?? 48 8b 48 20 e8 ?? ?? ?? ?? 48 8b cf");
|
||||
var getUiWindowPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("e8 ?? ?? ?? ?? 48 8b cf 48 89 87 ?? ?? 00 00 e8 ?? ?? ?? ?? 41 b8 01 00 00 00");
|
||||
var moveWindowPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 48 83 BB ?? ?? ?? ?? 00 74 ?? 48 8B 8B ?? ?? ?? ?? 48 85 C9 74 ?? E8 ?? ?? ?? ??");
|
||||
var setPositionPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("4C 8B 89 ?? ?? ?? ?? 41 0F BF C0");
|
||||
var setAlphaPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("F6 81 ?? ?? ?? ?? ?? 88 91 ?? ?? ?? ??");
|
||||
var updatePositionPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 48 8B 8B ?? ?? ?? ?? 33 D2 48 8B 01 FF 90 ?? ?? ?? ??");
|
||||
// var baseUiPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 0F BF D5");
|
||||
|
||||
this._getUiBase = Marshal.GetDelegateForFunctionPointer<GetUiBaseDelegate>(getUiBasePtr);
|
||||
this._getUiWindow = Marshal.GetDelegateForFunctionPointer<GetUiWindowDelegate>(getUiWindowPtr);
|
||||
this._moveWindow = Marshal.GetDelegateForFunctionPointer<MoveWindowDelegate>(moveWindowPtr);
|
||||
this._setPosition = Marshal.GetDelegateForFunctionPointer<SetPositionDelegate>(setPositionPtr);
|
||||
this._setAlpha = Marshal.GetDelegateForFunctionPointer<SetAlphaDelegate>(setAlphaPtr);
|
||||
this._updateAddonPosition = Marshal.GetDelegateForFunctionPointer<UpdateAddonPositionDelegate>(updatePositionPtr);
|
||||
}
|
||||
|
||||
private IntPtr GetUiBase() {
|
||||
return this._getUiBase.Invoke();
|
||||
}
|
||||
|
||||
private IntPtr GetUiWindow(string uiName, int index) {
|
||||
var uiBase = this.GetUiBase();
|
||||
var offset = Marshal.ReadIntPtr(uiBase, 0x20);
|
||||
|
||||
return this._getUiWindow.Invoke(offset, uiName, index);
|
||||
}
|
||||
|
||||
public void MoveWindow(string uiName, short x, short y) {
|
||||
var windowBase = this.GetUiWindow(uiName, 1);
|
||||
if (windowBase == IntPtr.Zero) {
|
||||
public void SetAddonPosition(string uiName, short x, short y) {
|
||||
var addon = this.Plugin.Interface.Framework.Gui.GetAddonByName(uiName, 1);
|
||||
if (addon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._moveWindow.Invoke(windowBase, x, y);
|
||||
var baseUi = this.Plugin.Interface.Framework.Gui.GetBaseUIObject();
|
||||
var manager = Marshal.ReadIntPtr(baseUi + 0x20);
|
||||
|
||||
this._updateAddonPosition(
|
||||
manager,
|
||||
addon.Address,
|
||||
1
|
||||
);
|
||||
this._setPosition(addon.Address, x, y);
|
||||
this._updateAddonPosition(
|
||||
manager,
|
||||
addon.Address,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
public Vector2<short>? GetWindowPosition(string uiName) {
|
||||
var windowBase = this.GetUiWindow(uiName, 1);
|
||||
if (windowBase == IntPtr.Zero) {
|
||||
public Vector2<short>? GetAddonPosition(string uiName) {
|
||||
var addon = this.Plugin.Interface.Framework.Gui.GetAddonByName(uiName, 1);
|
||||
if (addon == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var x = Marshal.ReadInt16(windowBase + 0x1bc);
|
||||
var y = Marshal.ReadInt16(windowBase + 0x1bc + 2);
|
||||
try {
|
||||
var x = addon.X;
|
||||
var y = addon.Y;
|
||||
|
||||
return new Vector2<short>(x, y);
|
||||
return new Vector2<short>(x, y);
|
||||
} catch (KeyNotFoundException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAddonAlpha(string name, byte alpha) {
|
||||
var addon = this.Plugin.Interface.Framework.Gui.GetAddonByName(name, 1);
|
||||
if (addon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._setAlpha(addon.Address, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,10 +41,15 @@ namespace HUD_Manager {
|
|||
}
|
||||
}
|
||||
|
||||
private IntPtr GetFilePointer(byte index) {
|
||||
public IntPtr GetFilePointer(byte index) {
|
||||
return this._getFilePointer?.Invoke(index) ?? IntPtr.Zero;
|
||||
}
|
||||
|
||||
public void SaveAddonData() {
|
||||
var saveMarker = this.GetFilePointer(0) + 0x3E;
|
||||
Marshal.WriteByte(saveMarker, 1);
|
||||
}
|
||||
|
||||
public void SelectSlot(HudSlot slot, bool force = false) {
|
||||
if (this._setHudLayout == null) {
|
||||
return;
|
||||
|
@ -93,6 +98,10 @@ namespace HUD_Manager {
|
|||
return Marshal.ReadIntPtr(dataPtr);
|
||||
}
|
||||
|
||||
internal IntPtr GetDefaultLayoutPointer() {
|
||||
return this.GetDataPointer() + 0x1c4;
|
||||
}
|
||||
|
||||
internal IntPtr GetLayoutPointer(HudSlot slot) {
|
||||
var slotNum = (int) slot;
|
||||
return this.GetDataPointer() + 0x2c58 + slotNum * LayoutSize;
|
||||
|
@ -196,8 +205,8 @@ namespace HUD_Manager {
|
|||
}
|
||||
|
||||
public class Vector2<T> {
|
||||
public T X { get; }
|
||||
public T Y { get; }
|
||||
public T X { get; set; }
|
||||
public T Y { get; set; }
|
||||
|
||||
public Vector2(T x, T y) {
|
||||
this.X = x;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -89,8 +89,8 @@ namespace HUD_Manager {
|
|||
this.Plugin.Hud.WriteEffectiveLayout(this.Plugin.Config.StagingSlot, layoutId);
|
||||
this.Plugin.Hud.SelectSlot(this.Plugin.Config.StagingSlot, true);
|
||||
|
||||
foreach (var entry in layout.Positions) {
|
||||
this.Plugin.GameFunctions.MoveWindow(entry.Key, entry.Value.X, entry.Value.Y);
|
||||
foreach (var entry in layout.Windows) {
|
||||
this.Plugin.GameFunctions.SetAddonPosition(entry.Key, entry.Value.Position.X, entry.Value.Position.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using Dalamud.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Data;
|
||||
using HUD_Manager.Lumina;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
|
@ -79,9 +82,25 @@ namespace HUD_Manager.Structs {
|
|||
TheFeastAllyInfo = 933766972,
|
||||
TheFeastScore = 3622852831,
|
||||
BattleHighGauge = 884971695,
|
||||
LeftWCrossHotbar = 1717924701,
|
||||
RightWCrossHotbar = 1893596455,
|
||||
OceanFishingVoyageMissions = 1917955123,
|
||||
Timers = 2578885979,
|
||||
}
|
||||
|
||||
public static class ElementKindExt {
|
||||
public static readonly ElementKind[] Immutable = {
|
||||
// cannot be moved with the current method the plugin is using
|
||||
ElementKind.OceanFishingVoyageMissions,
|
||||
|
||||
// don't actually know if this is immutable, but idk what it is
|
||||
ElementKind.Timers,
|
||||
};
|
||||
|
||||
public static IEnumerable<ElementKind> All() => Enum.GetValues(typeof(ElementKind))
|
||||
.Cast<ElementKind>()
|
||||
.Where(kind => !Immutable.Contains(kind));
|
||||
|
||||
public static string LocalisedName(this ElementKind kind, DataManager data) {
|
||||
uint? id = kind switch {
|
||||
ElementKind.Hotbar1 => 0,
|
||||
|
@ -117,8 +136,10 @@ namespace HUD_Manager.Structs {
|
|||
ElementKind.AllianceList1 => 30,
|
||||
ElementKind.AllianceList2 => 31,
|
||||
// ElementKind.DutyList => 32, // listed twice?
|
||||
// 33 is "Timers"
|
||||
// 34-39 empty
|
||||
ElementKind.Timers => 33,
|
||||
// 34-37 empty
|
||||
ElementKind.LeftWCrossHotbar => 38,
|
||||
ElementKind.RightWCrossHotbar => 39,
|
||||
ElementKind.OathGauge => 40,
|
||||
// 41 is "LightningGauge" - guessing that's for GL
|
||||
ElementKind.BeastGauge => 42,
|
||||
|
@ -164,7 +185,7 @@ namespace HUD_Manager.Structs {
|
|||
ElementKind.BattleHighGauge => 82,
|
||||
ElementKind.NewGamePlusGuide => 83,
|
||||
ElementKind.CompressedAether => 84,
|
||||
// 84 is "Ocean Fishing: Voyage Missions"
|
||||
ElementKind.OceanFishingVoyageMissions => 85,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
namespace HUD_Manager.Structs {
|
||||
public enum WindowKind : uint {
|
||||
FreeCompany = 3769291431,
|
||||
}
|
||||
|
||||
public static class WindowKindExt {
|
||||
public static readonly string[] All = {
|
||||
"AreaMap",
|
||||
"ChatLog",
|
||||
"ChatLogPanel_0",
|
||||
"ChatLogPanel_1",
|
||||
"ChatLogPanel_2",
|
||||
"ChatLogPanel_3",
|
||||
"InventoryExpansion",
|
||||
"InventoryLarge",
|
||||
"Inventory",
|
||||
"InventoryBuddy", // chocobo saddlebag
|
||||
"ArmouryBoard", // armoury chest
|
||||
"FreeCompany",
|
||||
"Character",
|
||||
"Currency",
|
||||
"ContentsInfo", // timers
|
||||
"ContentsFinder", // duty finder
|
||||
"RaidFinder", // raid finder
|
||||
"LookingForGroup", // party finder
|
||||
"Macro",
|
||||
"RecipeNote", // crafting log
|
||||
"GatheringNote", // gathering log
|
||||
"ActionMenu", // actions & traits
|
||||
"Achievement",
|
||||
"MountNoteBook", // mount guide
|
||||
"MinionNoteBook", // minion guide
|
||||
"OrnamentNoteBook", // fashion accessories
|
||||
"AOZNotebook", // blue magic spellbook
|
||||
"SystemMenu",
|
||||
"PvpProfile", // PvP Profile
|
||||
"GoldSaucerInfo",
|
||||
"Journal",
|
||||
"Teleport",
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue