8763cf4c70
Made-with: Cursor
437 lines
20 KiB
C#
437 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface.Utility;
|
|
using Dalamud.Interface.Utility.Raii;
|
|
using Dalamud.Utility;
|
|
using KamiLib.Window;
|
|
using Lumina.Excel.Sheets;
|
|
using Mappy.Controllers;
|
|
using Mappy.Data;
|
|
using Mappy.Helpers;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
|
using Map = Lumina.Excel.Sheets.Map;
|
|
|
|
namespace Mappy.Windows;
|
|
|
|
public class MinimapWindow : Window
|
|
{
|
|
private bool _wasLoggedIn;
|
|
|
|
public MinimapWindow() : base("HSMappy Minimap###HSMappyMinimap", new Vector2(200.0f, 200.0f))
|
|
{
|
|
DisableWindowSounds = true;
|
|
Flags |= ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollWithMouse;
|
|
}
|
|
|
|
public override bool DrawConditions() =>
|
|
IntegrationsController.ShouldShowMinimap() && System.SystemConfig.ShowMinimap;
|
|
|
|
public override void PreOpenCheck()
|
|
{
|
|
var isLoggedIn = Service.ClientState is { IsLoggedIn: true, IsPvP: false };
|
|
if (!isLoggedIn)
|
|
{
|
|
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()
|
|
{
|
|
if (System.SystemConfig.MinimapDrawUnderOtherUI)
|
|
{
|
|
var win = ImGuiP.GetCurrentWindow();
|
|
var pos = ImGui.GetWindowPos();
|
|
var size = ImGui.GetWindowSize();
|
|
var mouse = ImGui.GetMousePos();
|
|
var cursorOverMinimap = mouse.X >= pos.X && mouse.X <= pos.X + size.X && mouse.Y >= pos.Y && mouse.Y <= pos.Y + size.Y;
|
|
if (cursorOverMinimap)
|
|
ImGuiP.BringWindowToDisplayFront(win);
|
|
else
|
|
ImGuiP.BringWindowToDisplayBack(win);
|
|
}
|
|
|
|
var agent = AgentMap.Instance();
|
|
// Try loading from Lumina first so minimap can show without ever opening the area map
|
|
if (!System.MapRenderer.HasMinimapCacheFor(agent->CurrentMapId) && agent->SelectedMapId != agent->CurrentMapId)
|
|
System.MapRenderer.TryEnsureLuminaCacheFor(agent->CurrentMapId);
|
|
|
|
var mapLoaded = agent->SelectedMapId == agent->CurrentMapId || System.MapRenderer.HasMinimapCacheFor(agent->CurrentMapId);
|
|
|
|
if (!mapLoaded)
|
|
{
|
|
// Map data could not be loaded for this area (no Lumina path matched). Minimap shows automatically when data is available.
|
|
const string hint = "Map unavailable for this area.";
|
|
var textSize = ImGui.CalcTextSize(hint);
|
|
var pos = (ImGui.GetWindowSize() - textSize) * 0.5f;
|
|
ImGui.SetCursorPos(new Vector2(Math.Max(0, pos.X), Math.Max(20, pos.Y)));
|
|
ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.7f, 0.9f), hint);
|
|
UpdateStyle();
|
|
UpdateSizePosition();
|
|
return;
|
|
}
|
|
|
|
UpdateStyle();
|
|
UpdateSizePosition();
|
|
|
|
// Compensate for window padding (minimap gets zero padding from plugin)
|
|
var padding = ImGui.GetStyle().WindowPadding;
|
|
ImGui.SetCursorPos(new Vector2(-padding.X, -padding.Y));
|
|
|
|
// Use actual window size so content scales when resized
|
|
var contentSize = ImGui.GetContentRegionAvail();
|
|
if (contentSize.X <= 0 || contentSize.Y <= 0) return;
|
|
|
|
var totalWidth = contentSize.X;
|
|
var totalHeight = contentSize.Y;
|
|
|
|
// Compute bar heights: top bar fits server info on one line; bottom bar = coord text + 2px
|
|
float topBarHeight = 0f;
|
|
float bottomBarHeight = 0f;
|
|
if (System.SystemConfig.MinimapShowMapInfoBar)
|
|
topBarHeight = ComputeMapInfoBarHeight(totalWidth);
|
|
if (System.SystemConfig.MinimapShowCoordinateBar)
|
|
bottomBarHeight = ComputeCoordinateBarHeight(totalWidth, totalHeight, topBarHeight);
|
|
|
|
var minimapSide = Math.Min(totalWidth, totalHeight - topBarHeight - bottomBarHeight);
|
|
minimapSide = Math.Max(1f, minimapSide);
|
|
var scale = minimapSide / 200f;
|
|
|
|
// Top bar (outside edge, above minimap)
|
|
if (System.SystemConfig.MinimapShowMapInfoBar && topBarHeight > 0) {
|
|
DrawMapInfoBar(totalWidth, topBarHeight, scale);
|
|
}
|
|
|
|
// Minimap (square, sized to fit available space)
|
|
var minimapSize = new Vector2(minimapSide, minimapSide);
|
|
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, System.SystemConfig.MinimapOpacity))
|
|
using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, 0f))
|
|
using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, Vector2.Zero))
|
|
using (var child = ImRaii.Child("minimap_render", minimapSize, false, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
|
|
{
|
|
if (child) {
|
|
System.MapRenderer.DrawMinimapContents(minimapSize);
|
|
if (ImGui.IsItemHovered()) {
|
|
var io = ImGui.GetIO();
|
|
var wheel = io.MouseWheel;
|
|
if (wheel != 0) {
|
|
var zoom = System.SystemConfig.MinimapZoom;
|
|
zoom -= wheel * 0.012f;
|
|
System.SystemConfig.MinimapZoom = Math.Clamp(zoom, 0.03f, 0.112f);
|
|
SystemConfig.Save();
|
|
}
|
|
io.MouseWheel = 0f;
|
|
io.MouseWheelH = 0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bottom bar (outside edge, below minimap)
|
|
if (System.SystemConfig.MinimapShowCoordinateBar && bottomBarHeight > 0) {
|
|
DrawCoordinateBar(totalWidth, bottomBarHeight, scale);
|
|
}
|
|
|
|
// Action menu ">>" button at top-right of minimap
|
|
if (System.SystemConfig.MinimapShowActionMenuButton) {
|
|
DrawActionMenuButton(totalWidth, topBarHeight, minimapSide);
|
|
}
|
|
|
|
// Restore default padding for the next window is done in plugin Draw callback (PopStyleVar after all windows).
|
|
}
|
|
|
|
public override void OnOpen()
|
|
{
|
|
ImGui.SetWindowPos(System.SystemConfig.MinimapPosition);
|
|
var size = GetMinimapWindowSize();
|
|
ImGui.SetWindowSize(size);
|
|
}
|
|
|
|
private unsafe float ComputeMapInfoBarHeight(float width)
|
|
{
|
|
var (line1, line2) = GetMapInfoLines();
|
|
if (string.IsNullOrEmpty(line1) && string.IsNullOrEmpty(line2)) return 0f;
|
|
var fontScale = ComputeMapInfoFontScale(width, line1, line2);
|
|
ImGui.SetWindowFontScale(fontScale);
|
|
var h1 = string.IsNullOrEmpty(line1) ? 0f : ImGui.CalcTextSize(line1).Y;
|
|
var h2 = string.IsNullOrEmpty(line2) ? 0f : ImGui.CalcTextSize(line2).Y;
|
|
var lineSpacing = line1.Length > 0 && line2.Length > 0 ? 2f : 0f;
|
|
ImGui.SetWindowFontScale(1f);
|
|
return h1 + h2 + lineSpacing + 6f * ImGuiHelpers.GlobalScale;
|
|
}
|
|
|
|
private static float ComputeMapInfoFontScale(float width, string line1, string line2)
|
|
{
|
|
var horzPad = 8f * ImGuiHelpers.GlobalScale;
|
|
var maxWidth = Math.Max(1f, width - horzPad);
|
|
ImGui.SetWindowFontScale(1f);
|
|
var w1 = string.IsNullOrEmpty(line1) ? 0f : ImGui.CalcTextSize(line1).X;
|
|
var w2 = string.IsNullOrEmpty(line2) ? 0f : ImGui.CalcTextSize(line2).X;
|
|
var maxLineWidth = Math.Max(w1, w2);
|
|
if (maxLineWidth <= 0) return 1f;
|
|
var autoScale = Math.Clamp(maxWidth / maxLineWidth, 0.5f, 1f);
|
|
var mult = Math.Clamp(System.SystemConfig.MinimapMapInfoFontScale, 0.5f, 2f);
|
|
return Math.Clamp(autoScale * mult, 0.3f, 1.5f);
|
|
}
|
|
|
|
private unsafe (string line1, string line2) GetMapInfoLines()
|
|
{
|
|
var agent = AgentMap.Instance();
|
|
var currentMapId = agent->CurrentMapId;
|
|
if (currentMapId == 0) return (string.Empty, string.Empty);
|
|
var mapData = Service.DataManager.GetExcelSheet<Map>().GetRow(currentMapId);
|
|
if (mapData.RowId == 0) return (string.Empty, string.Empty);
|
|
var rawParts = new string?[4];
|
|
if (System.SystemConfig.ShowRegionLabel)
|
|
rawParts[0] = mapData.PlaceNameRegion.Value.Name.ExtractText();
|
|
if (System.SystemConfig.ShowMapLabel)
|
|
rawParts[1] = mapData.PlaceName.Value.Name.ExtractText();
|
|
if (agent->CurrentMapId == currentMapId) {
|
|
if (TerritoryInfo.Instance()->AreaPlaceNameId is not 0 && System.SystemConfig.ShowAreaLabel) {
|
|
var areaLabel = Service.DataManager.GetExcelSheet<PlaceName>().GetRow(TerritoryInfo.Instance()->AreaPlaceNameId);
|
|
rawParts[2] = areaLabel.Name.ExtractText();
|
|
}
|
|
if (TerritoryInfo.Instance()->SubAreaPlaceNameId is not 0 && System.SystemConfig.ShowSubAreaLabel) {
|
|
var subAreaLabel = Service.DataManager.GetExcelSheet<PlaceName>().GetRow(TerritoryInfo.Instance()->SubAreaPlaceNameId);
|
|
rawParts[3] = subAreaLabel.Name.ExtractText();
|
|
}
|
|
}
|
|
var order = System.SystemConfig.MinimapMapInfoOrder;
|
|
if (order.Length != 4) order = [0, 1, 2, 3];
|
|
var ordered = new List<string>();
|
|
foreach (var idx in order) {
|
|
var i = Math.Clamp(idx, 0, 3);
|
|
if (rawParts[i] is { } s)
|
|
ordered.Add(s);
|
|
}
|
|
var line1 = ordered.Count >= 2 ? string.Join(" - ", ordered[0], ordered[1]) : (ordered.Count == 1 ? ordered[0] : string.Empty);
|
|
var line2 = ordered.Count >= 4 ? string.Join(" - ", ordered[2], ordered[3]) : (ordered.Count == 3 ? ordered[2] : string.Empty);
|
|
return (line1, line2);
|
|
}
|
|
|
|
private static IDisposable? PushMinimapFont(int fontType)
|
|
{
|
|
return fontType switch {
|
|
1 when System.MinimapAxis12FontHandle != null => System.MinimapAxis12FontHandle.Push(),
|
|
2 when System.MinimapAxis18FontHandle != null => System.MinimapAxis18FontHandle.Push(),
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
private unsafe void DrawMapInfoBar(float width, float height, float _)
|
|
{
|
|
using var childBg = ImRaii.PushColor(ImGuiCol.ChildBg, System.SystemConfig.MinimapMapInfoBarBackground);
|
|
using var child = ImRaii.Child("minimap_mapinfo_bar", new Vector2(width, height), false, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse);
|
|
if (!child) return;
|
|
|
|
var (line1, line2) = GetMapInfoLines();
|
|
if (string.IsNullOrEmpty(line1) && string.IsNullOrEmpty(line2)) return;
|
|
|
|
using var _font = PushMinimapFont(System.SystemConfig.MinimapMapInfoFontType);
|
|
var fontScale = ComputeMapInfoFontScale(width, line1, line2);
|
|
ImGui.SetWindowFontScale(fontScale);
|
|
try {
|
|
var color = System.SystemConfig.MinimapMapInfoColor;
|
|
var totalHeight = 0f;
|
|
if (line1.Length > 0) totalHeight += ImGui.CalcTextSize(line1).Y;
|
|
if (line2.Length > 0) totalHeight += (line1.Length > 0 ? 2f : 0f) + ImGui.CalcTextSize(line2).Y;
|
|
var y = (height - totalHeight) * 0.5f;
|
|
if (line1.Length > 0) {
|
|
var sz = ImGui.CalcTextSize(line1);
|
|
ImGui.SetCursorPos(new Vector2((width - sz.X) * 0.5f, y));
|
|
ImGui.TextColored(color, line1);
|
|
y += sz.Y + 2f;
|
|
}
|
|
if (line2.Length > 0) {
|
|
var sz = ImGui.CalcTextSize(line2);
|
|
ImGui.SetCursorPos(new Vector2((width - sz.X) * 0.5f, y));
|
|
ImGui.TextColored(color, line2);
|
|
}
|
|
} finally {
|
|
ImGui.SetWindowFontScale(1f);
|
|
}
|
|
}
|
|
|
|
private float ComputeCoordinateBarHeight(float totalWidth, float totalHeight, float topBarHeight)
|
|
{
|
|
var showCoords = System.SystemConfig.MinimapCoordBarShowCoordinates;
|
|
var showTime = System.SystemConfig.MinimapCoordBarShowTime;
|
|
var showRepair = System.SystemConfig.MinimapCoordBarShowRepairPercent;
|
|
if (!showCoords && !showTime && !showRepair) return 0f;
|
|
|
|
var minimapSide = Math.Min(totalWidth, totalHeight - topBarHeight - 20f);
|
|
minimapSide = Math.Max(1f, minimapSide);
|
|
var baseScale = Math.Clamp(minimapSide / 200f, 0.15f, 1f);
|
|
var mult = Math.Clamp(System.SystemConfig.MinimapCoordBarFontScale, 0.5f, 2f);
|
|
var fontScale = Math.Clamp(baseScale * mult, 0.15f, 1.5f);
|
|
ImGui.SetWindowFontScale(fontScale);
|
|
var h = 0f;
|
|
if (showCoords) h = Math.Max(h, ImGui.CalcTextSize(" 99.9 99.9 ").Y);
|
|
if (showTime) h = Math.Max(h, ImGui.CalcTextSize(DateTime.Now.ToString("h:mm tt")).Y);
|
|
if (showRepair) h = Math.Max(h, ImGui.CalcTextSize("100%").Y);
|
|
ImGui.SetWindowFontScale(1f);
|
|
return h + 8f * ImGuiHelpers.GlobalScale;
|
|
}
|
|
|
|
private void DrawCoordinateBar(float width, float height, float scale)
|
|
{
|
|
var showCoords = System.SystemConfig.MinimapCoordBarShowCoordinates;
|
|
var showTime = System.SystemConfig.MinimapCoordBarShowTime;
|
|
var showRepair = System.SystemConfig.MinimapCoordBarShowRepairPercent;
|
|
if (!showCoords && !showTime && !showRepair) return;
|
|
|
|
using var childBg = ImRaii.PushColor(ImGuiCol.ChildBg, System.SystemConfig.MinimapCoordBarBackground);
|
|
using var child = ImRaii.Child("minimap_coord_bar", new Vector2(width, height), false, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse);
|
|
if (!child) return;
|
|
|
|
var mult = Math.Clamp(System.SystemConfig.MinimapCoordBarFontScale, 0.5f, 2f);
|
|
var fontScale = Math.Clamp(scale * mult, 0.15f, 1.5f);
|
|
ImGui.SetWindowFontScale(fontScale);
|
|
using var _font = PushMinimapFont(System.SystemConfig.MinimapCoordBarFontType);
|
|
try {
|
|
var color = System.SystemConfig.MinimapCoordBarColor;
|
|
var horzPad = 6f * ImGuiHelpers.GlobalScale;
|
|
var lineHeight = ImGui.GetTextLineHeight();
|
|
var yPos = Math.Max(0f, (height - lineHeight) * 0.5f - 2f);
|
|
var gap = 8f * ImGuiHelpers.GlobalScale;
|
|
|
|
var order = System.SystemConfig.MinimapBottomBarOrder;
|
|
if (order.Length != 3) order = [0, 1, 2];
|
|
|
|
var texts = new Dictionary<int, string>();
|
|
if (showCoords && System.MapRenderer.GetCurrentMinimapTransform() is { } transform) {
|
|
var pos = Service.ObjectTable.LocalPlayer?.Position ?? Vector3.Zero;
|
|
var mapCoord = MapUtil.WorldToMap(new Vector2(pos.X, pos.Z), transform.Item1, transform.Item2, transform.Item3);
|
|
texts[0] = $"{mapCoord.X:F1} {mapCoord.Y:F1}";
|
|
}
|
|
if (showRepair) texts[1] = $"{EquipmentConditionHelper.GetLowestConditionPercent():F0}%";
|
|
if (showTime) texts[2] = DateTime.Now.ToString("h:mm tt");
|
|
|
|
var visibleOrder = new List<string>();
|
|
foreach (var idx in order) {
|
|
var i = Math.Clamp(idx, 0, 2);
|
|
if (texts.TryGetValue(i, out var t)) visibleOrder.Add(t);
|
|
}
|
|
|
|
var cursorX = horzPad;
|
|
for (var j = 0; j < visibleOrder.Count; j++) {
|
|
var text = visibleOrder[j];
|
|
var sz = ImGui.CalcTextSize(text);
|
|
var isLast = j == visibleOrder.Count - 1;
|
|
var x = isLast ? width - horzPad - sz.X : cursorX;
|
|
ImGui.SetCursorPos(new Vector2(x, yPos));
|
|
ImGui.TextColored(color, text);
|
|
if (!isLast) cursorX += sz.X + gap;
|
|
}
|
|
} finally {
|
|
ImGui.SetWindowFontScale(1f);
|
|
}
|
|
}
|
|
|
|
private void DrawActionMenuButton(float totalWidth, float topBarHeight, float _)
|
|
{
|
|
const string buttonLabel = ">>";
|
|
var pad = 6f * ImGuiHelpers.GlobalScale;
|
|
var textSize = ImGui.CalcTextSize(buttonLabel);
|
|
var buttonSize = textSize + new Vector2(pad * 2, pad);
|
|
var windowPos = ImGui.GetWindowPos();
|
|
var screenPos = new Vector2(
|
|
windowPos.X + totalWidth - buttonSize.X - pad,
|
|
windowPos.Y + topBarHeight + pad);
|
|
var buttonMin = screenPos;
|
|
var buttonMax = screenPos + buttonSize;
|
|
|
|
var drawList = ImGui.GetForegroundDrawList();
|
|
var isHovered = ImGui.IsMouseHoveringRect(buttonMin, buttonMax);
|
|
var isClicked = isHovered && ImGui.IsMouseClicked(ImGuiMouseButton.Left);
|
|
|
|
if (isClicked)
|
|
ImGui.OpenPopup("minimap_action_popup");
|
|
|
|
var bgColor = isHovered ? new Vector4(0.25f, 0.25f, 0.3f, 0.98f) : new Vector4(0.12f, 0.12f, 0.18f, 0.98f);
|
|
var borderColor = new Vector4(1f, 1f, 1f, 0.9f);
|
|
var textColor = new Vector4(1f, 1f, 1f, 1f);
|
|
|
|
drawList.AddRectFilled(buttonMin, buttonMax, ImGui.GetColorU32(bgColor), 3f);
|
|
drawList.AddRect(buttonMin, buttonMax, ImGui.GetColorU32(borderColor), 3f, ImDrawFlags.None, 1.5f);
|
|
var textPos = screenPos + new Vector2((buttonSize.X - textSize.X) * 0.5f, (buttonSize.Y - textSize.Y) * 0.5f);
|
|
drawList.AddText(textPos, ImGui.GetColorU32(textColor), buttonLabel);
|
|
|
|
if (isHovered)
|
|
{
|
|
ImGui.SetNextWindowBgAlpha(1f);
|
|
using var tooltip = ImRaii.Tooltip();
|
|
ImGui.Text("Automations");
|
|
}
|
|
|
|
var popupX = windowPos.X + totalWidth + pad;
|
|
var popupY = windowPos.Y + topBarHeight;
|
|
ImGui.SetNextWindowPos(new Vector2(popupX, popupY), ImGuiCond.Appearing);
|
|
if (ImGui.BeginPopup("minimap_action_popup", ImGuiWindowFlags.NoMove))
|
|
{
|
|
if (ImGui.MenuItem("Desynth all items in inventory"))
|
|
MinimapActions.InvokeDesynth();
|
|
if (ImGui.MenuItem("Extract Materia"))
|
|
MinimapActions.InvokeExtract();
|
|
if (ImGui.MenuItem("Repair"))
|
|
MinimapActions.InvokeRepair();
|
|
if (ImGui.MenuItem("Equip Gear"))
|
|
MinimapActions.InvokeEquip();
|
|
if (ImGui.MenuItem("Open Coffers"))
|
|
MinimapActions.InvokeCoffers();
|
|
ImGui.EndPopup();
|
|
}
|
|
}
|
|
|
|
private void UpdateStyle()
|
|
{
|
|
if (System.SystemConfig.MinimapLockPosition)
|
|
Flags |= ImGuiWindowFlags.NoMove;
|
|
else
|
|
Flags &= ~ImGuiWindowFlags.NoMove;
|
|
}
|
|
|
|
private unsafe Vector2 GetMinimapWindowSize()
|
|
{
|
|
var minimapSizePx = System.SystemConfig.MinimapSize;
|
|
var topBarHeight = System.SystemConfig.MinimapShowMapInfoBar ? ComputeMapInfoBarHeight(minimapSizePx) : 0f;
|
|
var bottomBarHeight = System.SystemConfig.MinimapShowCoordinateBar
|
|
? ComputeCoordinateBarHeight(minimapSizePx, minimapSizePx + topBarHeight + 24f, topBarHeight)
|
|
: 0f;
|
|
var totalHeight = minimapSizePx + topBarHeight + bottomBarHeight;
|
|
return new Vector2(minimapSizePx, totalHeight);
|
|
}
|
|
|
|
private void UpdateSizePosition()
|
|
{
|
|
var config = System.SystemConfig;
|
|
var windowPosition = ImGui.GetWindowPos();
|
|
var windowSize = ImGui.GetWindowSize();
|
|
var expectedSize = GetMinimapWindowSize();
|
|
|
|
// Size is config-only (set in Mappy settings); always apply config size to window.
|
|
if (Math.Abs(windowSize.X - expectedSize.X) > 0.1f || Math.Abs(windowSize.Y - expectedSize.Y) > 0.1f)
|
|
ImGui.SetWindowSize(expectedSize);
|
|
|
|
if (!ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows)) {
|
|
// Not focused: apply config position to window
|
|
if (windowPosition != config.MinimapPosition)
|
|
ImGui.SetWindowPos(config.MinimapPosition);
|
|
} else {
|
|
// Focused: save window position to config (size is changed only via settings)
|
|
if (config.MinimapPosition != windowPosition) {
|
|
config.MinimapPosition = windowPosition;
|
|
SystemConfig.Save();
|
|
}
|
|
}
|
|
}
|
|
}
|