feat: begin adding addon window positions

This commit is contained in:
Anna 2021-03-17 13:36:40 -04:00
parent 358bbe491c
commit 7e4db37b2a
10 changed files with 742 additions and 472 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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,
}
}

View File

@ -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);
} 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);
}
}
}

View File

@ -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;

View File

@ -17,15 +17,6 @@ using Newtonsoft.Json;
namespace HUD_Manager {
public class PluginUi {
private static readonly string[] SavedWindows = {
"AreaMap",
"ChatLog",
"ChatLogPanel_0",
"ChatLogPanel_1",
"ChatLogPanel_2",
"ChatLogPanel_3",
};
private static readonly float[] ScaleOptions = {
2.0f,
1.8f,
@ -505,9 +496,27 @@ namespace HUD_Manager {
ImGui.Separator();
ImGui.TextUnformatted("HUD Elements");
if (ImGui.BeginTabBar("uimanager-positioning")) {
if (ImGui.BeginTabItem("HUD Elements")) {
this.DrawHudElementsTab(layout, ref update);
ImGui.SameLine();
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem("Windows")) {
this.DrawWindowsTab(layout);
ImGui.EndTabItem();
}
ImGui.EndTabBar();
}
EndTabItem:
ImGui.EndTabItem();
}
private void DrawHudElementsTab(SavedLayout layout, ref bool update) {
if (IconButton(FontAwesomeIcon.Plus, "uimanager-add-hud-element")) {
ImGui.OpenPopup(Popups.AddElement);
}
@ -515,8 +524,7 @@ namespace HUD_Manager {
HoverTooltip("Add a new HUD element to this layout");
if (ImGui.BeginPopup(Popups.AddElement)) {
var kinds = Enum.GetValues(typeof(ElementKind))
.Cast<ElementKind>()
var kinds = ElementKindExt.All()
.OrderBy(el => el.LocalisedName(this.Plugin.Interface.Data));
foreach (var kind in kinds) {
if (!ImGui.Selectable($"{kind.LocalisedName(this.Plugin.Interface.Data)}##{kind}")) {
@ -538,10 +546,14 @@ namespace HUD_Manager {
this._editorSearch = string.IsNullOrWhiteSpace(search) ? null : search;
}
if (ImGui.BeginChild("uimanager-layout-editor-elements", new Vector2(0, 0))) {
if (!ImGui.BeginChild("uimanager-layout-editor-elements", new Vector2(0, 0))) {
return;
}
var toRemove = new List<ElementKind>();
var sortedElements = layout.Elements
.Where(entry => !ElementKindExt.Immutable.Contains(entry.Key))
.Select(entry => Tuple.Create(entry.Key, entry.Value, entry.Key.LocalisedName(this.Plugin.Interface.Data)))
.OrderBy(tuple => tuple.Item3);
foreach (var (kind, element, name) in sortedElements) {
@ -591,7 +603,7 @@ namespace HUD_Manager {
ImGui.Separator();
void DrawEnabledCheckbox(ElementKind kind, ElementComponent component) {
void DrawEnabledCheckbox(ElementKind kind, ElementComponent component, ref bool update) {
ImGui.NextColumn();
var enabled = element[component];
@ -606,7 +618,7 @@ namespace HUD_Manager {
}
if (!kind.IsJobGauge()) {
DrawEnabledCheckbox(element.Id, ElementComponent.Visibility);
DrawEnabledCheckbox(element.Id, ElementComponent.Visibility, ref update);
DrawSettingName("Visibility");
var keyboard = element[VisibilityFlags.Keyboard];
@ -645,7 +657,7 @@ namespace HUD_Manager {
ImGui.PopItemWidth();
DrawEnabledCheckbox(element.Id, ElementComponent.X);
DrawEnabledCheckbox(element.Id, ElementComponent.X, ref update);
DrawSettingName("X");
if (this.Plugin.Config.PositioningMode == PositioningMode.Percentage) {
@ -661,7 +673,7 @@ namespace HUD_Manager {
ImGui.PopItemWidth();
DrawEnabledCheckbox(element.Id, ElementComponent.Y);
DrawEnabledCheckbox(element.Id, ElementComponent.Y, ref update);
DrawSettingName("Y");
ImGui.PushItemWidth(-1);
@ -690,7 +702,7 @@ namespace HUD_Manager {
ImGui.PopItemWidth();
DrawEnabledCheckbox(element.Id, ElementComponent.Y);
DrawEnabledCheckbox(element.Id, ElementComponent.Y, ref update);
DrawSettingName("Y");
ImGui.PushItemWidth(-1);
@ -706,7 +718,7 @@ namespace HUD_Manager {
ImGui.PopItemWidth();
}
DrawEnabledCheckbox(element.Id, ElementComponent.Scale);
DrawEnabledCheckbox(element.Id, ElementComponent.Scale, ref update);
DrawSettingName("Scale");
ImGui.PushItemWidth(-1);
@ -727,7 +739,7 @@ namespace HUD_Manager {
ImGui.PopItemWidth();
if (!kind.IsJobGauge()) {
DrawEnabledCheckbox(element.Id, ElementComponent.Opacity);
DrawEnabledCheckbox(element.Id, ElementComponent.Opacity, ref update);
DrawSettingName("Opacity");
ImGui.PushItemWidth(-1);
@ -912,8 +924,51 @@ namespace HUD_Manager {
ImGui.EndChild();
}
EndTabItem:
ImGui.EndTabItem();
private void DrawWindowsTab(SavedLayout layout) {
if (IconButton(FontAwesomeIcon.Plus, "uimanager-add-window")) {
ImGui.OpenPopup(Popups.AddWindow);
}
if (ImGui.BeginPopup(Popups.AddWindow)) {
foreach (var window in WindowKindExt.All) {
if (!ImGui.Selectable(window)) {
continue;
}
var pos = this.Plugin.GameFunctions.GetAddonPosition(window);
if (pos != null && !layout.Windows.ContainsKey(window)) {
layout.Windows.Add(window, new Window(pos));
}
}
ImGui.EndPopup();
}
if (!ImGui.BeginChild("uimanager-layout-editor-windows", new Vector2(0, 0))) {
return;
}
foreach (var entry in layout.Windows) {
if (!ImGui.CollapsingHeader($"{entry.Key}##uimanager-window-{entry.Key}")) {
continue;
}
var pos = entry.Value.Position;
var x = (int) pos.X;
if (ImGui.InputInt($"X##uimanager-window-{entry.Key}", ref x)) {
pos.X = (short) x;
this.Plugin.GameFunctions.SetAddonPosition(entry.Key, pos.X, pos.Y);
}
var y = (int) pos.Y;
if (ImGui.InputInt($"Y##uimanager-window-{entry.Key}", ref y)) {
pos.Y = (short) y;
this.Plugin.GameFunctions.SetAddonPosition(entry.Key, pos.X, pos.Y);
}
}
ImGui.EndChild();
}
private void SetUpImportLayoutPopup() {
@ -939,20 +994,20 @@ namespace HUD_Manager {
if (ImGui.Button($"{name}##import-{slot}") && this._importName != null) {
Guid id;
string newName;
Dictionary<string, Vector2<short>> positions;
Dictionary<string, Window> windows;
if (exists) {
var overwriting = this.Plugin.Config.Layouts.First(entry => entry.Value.Name == this._importName);
id = overwriting.Key;
newName = overwriting.Value.Name;
positions = overwriting.Value.Positions;
windows = overwriting.Value.Windows;
} else {
id = Guid.NewGuid();
newName = this._importName;
positions = new Dictionary<string, Vector2<short>>();
windows = new Dictionary<string, Window>();
}
var currentLayout = this.Plugin.Hud.ReadLayout(slot);
var newLayout = new SavedLayout(newName, currentLayout, positions);
var newLayout = new SavedLayout(newName, currentLayout, windows);
this.Plugin.Config.Layouts[id] = newLayout;
this.Plugin.Config.Save();
@ -1092,7 +1147,7 @@ namespace HUD_Manager {
if (!exists && ImGui.Button("Add") && this._newLayoutName != null) {
// create the layout
var saved = new SavedLayout(this._newLayoutName, new Dictionary<ElementKind, Element>(), new Dictionary<string, Vector2<short>>(), Guid.Empty);
var saved = new SavedLayout(this._newLayoutName, new Dictionary<ElementKind, Element>(), new Dictionary<string, Window>(), Guid.Empty);
// reset the new layout name
this._newLayoutName = null;
@ -1166,6 +1221,18 @@ namespace HUD_Manager {
this.Plugin.Interface.Framework.Gui.Chat.Print($"{ptr.ToInt64():x}");
}
ImGui.SameLine();
if (ImGui.Button("Default")) {
var ptr = this.Plugin.Hud.GetDefaultLayoutPointer();
this.Plugin.Interface.Framework.Gui.Chat.Print($"{ptr.ToInt64():x}");
}
if (ImGui.Button("File pointer 0")) {
var ptr = this.Plugin.Hud.GetFilePointer(0);
this.Plugin.Interface.Framework.Gui.Chat.Print($"{ptr.ToInt64():x}");
}
if (ImGui.Button("Save layout")) {
var ptr = this.Plugin.Hud.GetLayoutPointer(HudSlot.One);
var layout = Marshal.PtrToStructure<Layout>(ptr);
@ -1194,14 +1261,58 @@ namespace HUD_Manager {
this.Plugin.Interface.Framework.Gui.Chat.Print($"{slot}");
}
var current = this.Plugin.Hud.ReadLayout(this.Plugin.Hud.GetActiveHudSlot());
foreach (var element in current.elements) {
ImGui.TextUnformatted(element.id.LocalisedName(this.Plugin.Interface.Data));
ImGui.TextUnformatted($"Width: {element.width}");
ImGui.TextUnformatted($"Height: {element.height}");
ImGui.TextUnformatted($"Opacity: {element.opacity}");
ImGui.Separator();
}
// var layoutPtr = this.Plugin.Hud.GetDefaultLayoutPointer() + 8;
//
// for (var i = 0; i < 291; i++) {
// var rawElement = Marshal.PtrToStructure<RawElement>(layoutPtr + i * Marshal.SizeOf<RawElement>());
// var element = new Element(rawElement);
//
// if ((WindowKind) rawElement.id != WindowKind.FreeCompany) {
// continue;
// }
//
// ImGui.TextUnformatted($"{(WindowKind) rawElement.id}");
// ImGui.TextUnformatted($"Measured from: {rawElement.measuredFrom.Name()}");
// ImGui.TextUnformatted($"Width: {rawElement.width}");
// ImGui.TextUnformatted($"Height: {rawElement.height}");
//
// var screen = ImGui.GetIO().DisplaySize;
// var (pos, _) = CalcPosAndSize(element);
//
// var x = pos.X;
// if (ImGui.DragFloat($"X##addon-{rawElement.id}", ref x, this._dragSpeed)) {
// this.Plugin.GameFunctions.SetAddonPosition("FreeCompany", (short) x, (short) pos.Y);
// }
//
// var y = pos.Y;
// if (ImGui.DragFloat($"Y##addon-{rawElement.id}", ref y, this._dragSpeed)) {
// this.Plugin.GameFunctions.SetAddonPosition("FreeCompany", (short) pos.X, (short) y);
// }
//
// ImGui.TextUnformatted($"X: {rawElement.x}/{(short) Math.Round(rawElement.x * screen.X / 100)}");
// ImGui.TextUnformatted($"Y: {rawElement.y}/{(short) Math.Round(rawElement.y * screen.Y / 100)}");
//
// var opacity = (int) rawElement.opacity;
// if (ImGui.InputInt($"Opacity##addon-{rawElement.id}", ref opacity)) {
// rawElement.opacity = (byte) Math.Max(0, Math.Min(255, opacity));
// Marshal.StructureToPtr(rawElement, layoutPtr + i * Marshal.SizeOf<RawElement>(), false);
// this.Plugin.GameFunctions.SetAddonAlpha("FreeCompany", rawElement.opacity);
// }
//
// if (ImGui.Button("Print addon address")) {
// var ptr = this.Plugin.Interface.Framework.Gui.GetAddonByName("FreeCompany", 1).Address;
// this.Plugin.Interface.Framework.Gui.Chat.Print($"{ptr.ToInt64():x}");
// }
//
// if (ImGui.Button("Print base UI object address")) {
// var ptr = this.Plugin.Interface.Framework.Gui.GetBaseUIObject();
// this.Plugin.Interface.Framework.Gui.Chat.Print($"{ptr.ToInt64():x}");
// }
//
// ImGui.Separator();
// }
ImGui.EndTabItem();
}
@ -1459,32 +1570,15 @@ namespace HUD_Manager {
this.DrawSettings();
}
private Dictionary<string, Vector2<short>> GetPositions() {
var positions = new Dictionary<string, Vector2<short>>();
foreach (var name in SavedWindows) {
var pos = this.Plugin.GameFunctions.GetWindowPosition(name);
if (pos != null) {
positions[name] = pos;
}
}
return positions;
}
public void ImportSlot(string name, HudSlot slot, bool save = true) {
var positions = this.Plugin.Config.ImportPositions
? this.GetPositions()
: new Dictionary<string, Vector2<short>>();
this.Import(name, this.Plugin.Hud.ReadLayout(slot), positions, save);
this.Import(name, this.Plugin.Hud.ReadLayout(slot), save);
}
private void Import(string name, Layout layout, Dictionary<string, Vector2<short>> positions, bool save = true) {
private void Import(string name, Layout layout, bool save = true) {
var guid = this.Plugin.Config.Layouts.FirstOrDefault(kv => kv.Value.Name == name).Key;
guid = guid != default ? guid : Guid.NewGuid();
this.Plugin.Config.Layouts[guid] = new SavedLayout(name, layout, positions);
this.Plugin.Config.Layouts[guid] = new SavedLayout(name, layout);
if (save) {
this.Plugin.Config.Save();
}
@ -1498,6 +1592,7 @@ namespace HUD_Manager {
public const string ImportLayout = "uimanager-import-layout-popup";
public const string ExportLayout = "uimanager-export-layout-popup";
public const string AddElement = "uimanager-add-element-popup";
public const string AddWindow = "uimanager-add-window-popup";
public const string DeleteVerify = "Delete layout?##uimanager-delete-layout-modal";
}
}

View File

@ -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);
}
}
}

View File

@ -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,
};

View File

@ -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",
};
}
}