Initial HSMappy release (fork of Mappy)
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,505 @@
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Game.ClientState.Keys;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using KamiLib.Classes;
|
||||
using KamiLib.CommandManager;
|
||||
using KamiLib.Window;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Mappy.Classes;
|
||||
using Mappy.Classes.MapWindowComponents;
|
||||
using Mappy.Controllers;
|
||||
using Mappy.Data;
|
||||
using Map = Lumina.Excel.Sheets.Map;
|
||||
|
||||
namespace Mappy.Windows;
|
||||
|
||||
public class MapWindow : Window
|
||||
{
|
||||
public Vector2 MapDrawOffset { get; private set; }
|
||||
public HoverFlags HoveredFlags { get; private set; }
|
||||
public bool ProcessingCommand { get; set; }
|
||||
|
||||
private bool isDragStarted;
|
||||
private Vector2 lastWindowSize;
|
||||
private uint lastMapId;
|
||||
private uint lastAreaPlaceNameId;
|
||||
private uint lastSubAreaPlaceNameId;
|
||||
|
||||
private readonly MapToolbar mapToolbar = new();
|
||||
private readonly MapCoordinateBar mapCoordinateBar = new();
|
||||
private readonly MapContextMenu mapContextMenu = new();
|
||||
|
||||
public MapWindow() : base("###HSMappyMapWindow", new Vector2(400.0f, 250.0f))
|
||||
{
|
||||
UpdateTitle();
|
||||
|
||||
DisableWindowSounds = true;
|
||||
RegisterCommands();
|
||||
}
|
||||
|
||||
public override bool DrawConditions() => IntegrationsController.ShouldShowMap();
|
||||
|
||||
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)
|
||||
{
|
||||
Service.Log.Debug("[OnShow] MapWindow can not be open now.");
|
||||
IsOpen = false;
|
||||
}
|
||||
|
||||
if (System.SystemConfig.KeepOpen) {
|
||||
IsOpen = true;
|
||||
}
|
||||
|
||||
if (Service.ClientState is { IsLoggedIn: false } or { IsPvP: true }) IsOpen = false;
|
||||
}
|
||||
|
||||
public override void OnOpen()
|
||||
{
|
||||
if (ProcessingCommand) {
|
||||
ProcessingCommand = false;
|
||||
System.SystemConfig.FollowPlayer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (System.SystemConfig.FollowOnOpen) {
|
||||
System.IntegrationsController.OpenOccupiedMap();
|
||||
System.SystemConfig.FollowPlayer = true;
|
||||
}
|
||||
|
||||
switch (System.SystemConfig.CenterOnOpen) {
|
||||
case CenterTarget.Player when Service.ObjectTable.LocalPlayer is { } localPlayer:
|
||||
System.MapRenderer.CenterOnGameObject(localPlayer);
|
||||
break;
|
||||
|
||||
case CenterTarget.Map:
|
||||
System.SystemConfig.FollowPlayer = false;
|
||||
System.MapRenderer.DrawOffset = Vector2.Zero;
|
||||
break;
|
||||
|
||||
case CenterTarget.Disabled:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DrawContents()
|
||||
{
|
||||
UpdateTitle();
|
||||
UpdateStyle();
|
||||
UpdateSizePosition();
|
||||
|
||||
HoveredFlags = HoverFlags.Nothing;
|
||||
|
||||
if (WindowBounds.IsBoundedBy(ImGui.GetMousePos(), ImGui.GetCursorScreenPos(), ImGui.GetCursorScreenPos() + ImGui.GetContentRegionMax())) {
|
||||
HoveredFlags |= HoverFlags.Window;
|
||||
}
|
||||
|
||||
MapDrawOffset = ImGui.GetCursorScreenPos();
|
||||
using var fade = ImRaii.PushStyle(ImGuiStyleVar.Alpha, System.SystemConfig.FadePercent, ShouldFade());
|
||||
using (var renderChild = ImRaii.Child("render_child", ImGui.GetContentRegionAvail(), false, ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoScrollbar)) {
|
||||
if (!renderChild) return;
|
||||
if (!System.SystemConfig.AcceptedSpoilerWarning) {
|
||||
DrawSpoilerWarning();
|
||||
return;
|
||||
}
|
||||
|
||||
DrawMapElements();
|
||||
|
||||
// Reset Draw Position for Overlay Extras
|
||||
ImGui.SetCursorPos(Vector2.Zero);
|
||||
DrawToolbar();
|
||||
DrawCoordinateBar();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered()) {
|
||||
HoveredFlags |= HoverFlags.WindowInnerFrame;
|
||||
}
|
||||
|
||||
// Process Inputs
|
||||
ProcessInputs();
|
||||
}
|
||||
|
||||
private void DrawMapElements()
|
||||
{
|
||||
System.MapRenderer.DrawBaseTexture();
|
||||
if (ImGui.IsItemHovered()) {
|
||||
HoveredFlags |= HoverFlags.MapTexture;
|
||||
}
|
||||
|
||||
System.MapRenderer.DrawDynamicElements();
|
||||
}
|
||||
|
||||
private void DrawToolbar()
|
||||
{
|
||||
if (!ShouldShowToolbar()) return;
|
||||
|
||||
using (ImRaii.Group()) {
|
||||
mapToolbar.Draw();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered()) {
|
||||
HoveredFlags |= HoverFlags.Toolbar;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCoordinateBar()
|
||||
{
|
||||
if (!System.SystemConfig.ShowCoordinateBar) return;
|
||||
|
||||
using (ImRaii.Group()) {
|
||||
mapCoordinateBar.Draw(HoveredFlags.HasFlag(HoverFlags.MapTexture), MapDrawOffset);
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered()) {
|
||||
HoveredFlags |= HoverFlags.CoordinateBar;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldShowToolbar()
|
||||
{
|
||||
if (isDragStarted) return false;
|
||||
if (System.SystemConfig.ShowToolbarOnHover && HoveredFlags.Any()) return true;
|
||||
if (System.SystemConfig.AlwaysShowToolbar) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private unsafe void UpdateTitle()
|
||||
{
|
||||
var mapChanged = lastMapId != AgentMap.Instance()->SelectedMapId;
|
||||
var areaChanged = lastAreaPlaceNameId != TerritoryInfo.Instance()->AreaPlaceNameId;
|
||||
var subAreaChanged = lastSubAreaPlaceNameId != TerritoryInfo.Instance()->SubAreaPlaceNameId;
|
||||
var locationChanged = mapChanged || areaChanged || subAreaChanged;
|
||||
|
||||
if (!locationChanged) return;
|
||||
var subLocationString = string.Empty;
|
||||
var mapData = Service.DataManager.GetExcelSheet<Map>().GetRow(AgentMap.Instance()->SelectedMapId);
|
||||
|
||||
if (System.SystemConfig.ShowRegionLabel) {
|
||||
var mapRegionName = mapData.PlaceNameRegion.Value.Name.ExtractText();
|
||||
subLocationString += $" - {mapRegionName}";
|
||||
}
|
||||
|
||||
if (System.SystemConfig.ShowMapLabel) {
|
||||
var mapName = mapData.PlaceName.Value.Name.ExtractText();
|
||||
subLocationString += $" - {mapName}";
|
||||
}
|
||||
|
||||
// Don't show specific locations if we aren't there.
|
||||
if (AgentMap.Instance()->SelectedMapId == AgentMap.Instance()->CurrentMapId) {
|
||||
if (TerritoryInfo.Instance()->AreaPlaceNameId is not 0 && System.SystemConfig.ShowAreaLabel) {
|
||||
var areaLabel = Service.DataManager.GetExcelSheet<PlaceName>().GetRow(TerritoryInfo.Instance()->AreaPlaceNameId);
|
||||
subLocationString += $" - {areaLabel.Name}";
|
||||
}
|
||||
|
||||
if (TerritoryInfo.Instance()->SubAreaPlaceNameId is not 0 && System.SystemConfig.ShowSubAreaLabel) {
|
||||
var subAreaLabel = Service.DataManager.GetExcelSheet<PlaceName>().GetRow(TerritoryInfo.Instance()->SubAreaPlaceNameId);
|
||||
subLocationString += $" - {subAreaLabel.Name}";
|
||||
}
|
||||
}
|
||||
|
||||
WindowName = $"{subLocationString}###HSMappyMapWindow".TrimStart(['-',' ']);
|
||||
|
||||
lastMapId = AgentMap.Instance()->SelectedMapId;
|
||||
lastAreaPlaceNameId = TerritoryInfo.Instance()->AreaPlaceNameId;
|
||||
lastSubAreaPlaceNameId = TerritoryInfo.Instance()->SubAreaPlaceNameId;
|
||||
}
|
||||
|
||||
public void RefreshTitle()
|
||||
{
|
||||
lastMapId = 0;
|
||||
lastAreaPlaceNameId = 0;
|
||||
lastSubAreaPlaceNameId = 0;
|
||||
}
|
||||
|
||||
private void ProcessInputs()
|
||||
{
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) {
|
||||
ImGui.OpenPopup("Mappy_Context_Menu");
|
||||
}
|
||||
else {
|
||||
if (HoveredFlags.Any()) {
|
||||
if (System.SystemConfig.EnableShiftDragMove && ImGui.GetIO().KeyShift) {
|
||||
Flags &= ~ImGuiWindowFlags.NoMove;
|
||||
}
|
||||
else {
|
||||
ProcessMouseScroll();
|
||||
ProcessMapDragStart();
|
||||
Flags |= ImGuiWindowFlags.NoMove;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessMapDragDragging();
|
||||
ProcessMapDragEnd();
|
||||
}
|
||||
|
||||
// Draw Context Menu
|
||||
mapContextMenu.Draw(MapDrawOffset);
|
||||
}
|
||||
|
||||
private unsafe void UpdateStyle()
|
||||
{
|
||||
if (System.SystemConfig.HideWindowFrame) {
|
||||
Flags |= ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoBackground;
|
||||
}
|
||||
else {
|
||||
Flags &= ~(ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoBackground);
|
||||
}
|
||||
|
||||
if (System.SystemConfig.LockWindow) {
|
||||
Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove;
|
||||
}
|
||||
else {
|
||||
Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove);
|
||||
}
|
||||
|
||||
if (System.SystemConfig.NoFocusOnAppear) {
|
||||
Flags |= ImGuiWindowFlags.NoFocusOnAppearing;
|
||||
}
|
||||
else {
|
||||
Flags &= ~ImGuiWindowFlags.NoFocusOnAppearing;
|
||||
}
|
||||
|
||||
if (System.SystemConfig.HideWindowBackground) {
|
||||
Flags |= ImGuiWindowFlags.NoBackground;
|
||||
}
|
||||
else {
|
||||
Flags &= ~ImGuiWindowFlags.NoBackground;
|
||||
}
|
||||
|
||||
if (Service.KeyState[VirtualKey.ESCAPE] && IsFocused && !IsMapLocked()) {
|
||||
AgentMap.Instance()->Hide();
|
||||
}
|
||||
|
||||
if (System.SystemConfig.FollowPlayer && Service.ObjectTable is { LocalPlayer: { } localPlayer }) {
|
||||
System.MapRenderer.CenterOnGameObject(localPlayer);
|
||||
}
|
||||
|
||||
if (System.SystemConfig.LockCenterOnMap) {
|
||||
System.SystemConfig.FollowPlayer = false;
|
||||
System.MapRenderer.DrawOffset = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSizePosition()
|
||||
{
|
||||
var systemConfig = System.SystemConfig;
|
||||
var windowPosition = ImGui.GetWindowPos();
|
||||
var windowSize = ImGui.GetWindowSize();
|
||||
|
||||
if (!IsFocused) {
|
||||
if (windowPosition != systemConfig.WindowPosition) {
|
||||
ImGui.SetWindowPos(systemConfig.WindowPosition);
|
||||
}
|
||||
|
||||
if (windowSize != systemConfig.WindowSize) {
|
||||
ImGui.SetWindowSize(systemConfig.WindowSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If focused
|
||||
if (systemConfig.WindowPosition != windowPosition) {
|
||||
systemConfig.WindowPosition = windowPosition;
|
||||
SystemConfig.Save();
|
||||
}
|
||||
|
||||
if (systemConfig.WindowSize != windowSize) {
|
||||
systemConfig.WindowSize = windowSize;
|
||||
SystemConfig.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawSpoilerWarning()
|
||||
{
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, KnownColor.Orange.Vector())) {
|
||||
const string warningLine1 = "Warning, HSMappy does not protect you from spoilers and will show everything.";
|
||||
const string warningLine2 = "Do not use HSMappy if you are not comfortable with this.";
|
||||
|
||||
ImGui.SetCursorPos(ImGui.GetContentRegionAvail() / 2.0f - (ImGui.CalcTextSize(warningLine1) * 2.0f) with { X = 0.0f });
|
||||
ImGuiHelpers.CenteredText(warningLine1);
|
||||
ImGuiHelpers.CenteredText(warningLine2);
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(30.0f);
|
||||
ImGui.SetCursorPosX(ImGui.GetContentRegionAvail().X / 3.0f);
|
||||
using (ImRaii.Disabled(!(ImGui.GetIO().KeyShift && ImGui.GetIO().KeyCtrl))) {
|
||||
if (ImGui.Button("I understand", new Vector2(ImGui.GetContentRegionAvail().X / 2.0f, 23.0f * ImGuiHelpers.GlobalScale))) {
|
||||
System.SystemConfig.AcceptedSpoilerWarning = true;
|
||||
SystemConfig.Save();
|
||||
}
|
||||
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, 1.0f)) {
|
||||
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) {
|
||||
ImGui.SetTooltip("Hold Shift + Control while clicking activate button");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void OnClose()
|
||||
{
|
||||
AgentMap.Instance()->Hide();
|
||||
SystemConfig.Save();
|
||||
}
|
||||
|
||||
private void ProcessMouseScroll()
|
||||
{
|
||||
if (System.SystemConfig.ZoomLocked) return;
|
||||
if (ImGui.GetIO().MouseWheel is 0) return;
|
||||
if (!HoveredFlags.HasFlag(HoverFlags.WindowInnerFrame)) return;
|
||||
|
||||
if (System.SystemConfig.UseLinearZoom) {
|
||||
MapRenderer.MapRenderer.Scale += System.SystemConfig.ZoomSpeed * ImGui.GetIO().MouseWheel;
|
||||
}
|
||||
else {
|
||||
MapRenderer.MapRenderer.Scale *= 1.0f + System.SystemConfig.ZoomSpeed * ImGui.GetIO().MouseWheel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMapDragDragging()
|
||||
{
|
||||
if (ImGui.IsMouseDragging(ImGuiMouseButton.Left) && isDragStarted) {
|
||||
System.MapRenderer.DrawOffset += ImGui.GetMouseDragDelta() / MapRenderer.MapRenderer.Scale;
|
||||
ImGui.ResetMouseDragDelta();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMapDragEnd()
|
||||
{
|
||||
if (ImGui.IsMouseReleased(ImGuiMouseButton.Left)) {
|
||||
isDragStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMapDragStart()
|
||||
{
|
||||
// Don't allow a drag to start if the window size is changing
|
||||
if (ImGui.GetWindowSize() == lastWindowSize) {
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left) && !isDragStarted) {
|
||||
isDragStarted = true;
|
||||
System.SystemConfig.FollowPlayer = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lastWindowSize = ImGui.GetWindowSize();
|
||||
isDragStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe bool ShouldFade() =>
|
||||
System.SystemConfig.FadeMode.HasFlag(FadeMode.Always) ||
|
||||
System.SystemConfig.FadeMode.HasFlag(FadeMode.WhenFocused) && IsFocused ||
|
||||
System.SystemConfig.FadeMode.HasFlag(FadeMode.WhenMoving) && AgentMap.Instance()->IsPlayerMoving ||
|
||||
System.SystemConfig.FadeMode.HasFlag(FadeMode.WhenUnFocused) && !IsFocused;
|
||||
|
||||
private void RegisterCommands()
|
||||
{
|
||||
System.CommandManager.RegisterCommand(new ToggleCommandHandler
|
||||
{
|
||||
UseShowHideText = true,
|
||||
BaseActivationPath = "/map",
|
||||
EnableDelegate = _ => System.MapWindow.UnCollapseOrShow(),
|
||||
DisableDelegate = _ => System.MapWindow.Close(),
|
||||
ToggleDelegate = _ => System.MapWindow.UnCollapseOrToggle(),
|
||||
});
|
||||
|
||||
System.CommandManager.RegisterCommand(new CommandHandler
|
||||
{
|
||||
ActivationPath = "/map/follow",
|
||||
Delegate = _ =>
|
||||
{
|
||||
System.SystemConfig.FollowPlayer = true;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
});
|
||||
|
||||
System.CommandManager.RegisterCommand(new CommandHandler
|
||||
{
|
||||
ActivationPath = "/map/unfollow",
|
||||
Delegate = _ =>
|
||||
{
|
||||
System.SystemConfig.FollowPlayer = false;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
});
|
||||
|
||||
System.CommandManager.RegisterCommand(new ToggleCommandHandler
|
||||
{
|
||||
BaseActivationPath = "/autofollow",
|
||||
EnableDelegate = _ =>
|
||||
{
|
||||
System.SystemConfig.FollowOnOpen = true;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
DisableDelegate = _ =>
|
||||
{
|
||||
System.SystemConfig.FollowOnOpen = false;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
ToggleDelegate = _ =>
|
||||
{
|
||||
System.SystemConfig.FollowOnOpen = !System.SystemConfig.FollowOnOpen;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
});
|
||||
|
||||
System.CommandManager.RegisterCommand(new ToggleCommandHandler
|
||||
{
|
||||
BaseActivationPath = "/keepopen",
|
||||
EnableDelegate = _ =>
|
||||
{
|
||||
System.SystemConfig.KeepOpen = true;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
DisableDelegate = _ =>
|
||||
{
|
||||
System.SystemConfig.KeepOpen = false;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
ToggleDelegate = _ =>
|
||||
{
|
||||
System.SystemConfig.KeepOpen = !System.SystemConfig.KeepOpen;
|
||||
SystemConfig.Save();
|
||||
},
|
||||
});
|
||||
|
||||
System.CommandManager.RegisterCommand(new CommandHandler
|
||||
{
|
||||
ActivationPath = "/center/player",
|
||||
Delegate = _ =>
|
||||
{
|
||||
if (Service.ObjectTable.LocalPlayer is { } localPlayer) {
|
||||
System.MapRenderer.CenterOnGameObject(localPlayer);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
System.CommandManager.RegisterCommand(new CommandHandler
|
||||
{
|
||||
ActivationPath = "/center/map",
|
||||
Delegate = _ =>
|
||||
{
|
||||
System.SystemConfig.FollowPlayer = false;
|
||||
System.MapRenderer.DrawOffset = Vector2.Zero;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static unsafe bool IsMapLocked()
|
||||
{
|
||||
var addon = Service.GameGui.GetAddonByName<AddonAreaMap>("AreaMap");
|
||||
if (addon is null || addon->RootNode is null) return false;
|
||||
|
||||
return (addon->Param & 0x8_0000) > 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user