From 883340d00a043ac70e93d0ebb4d4f08f2013a534 Mon Sep 17 00:00:00 2001 From: KazWolfe Date: Wed, 15 Jun 2022 11:40:58 -0700 Subject: [PATCH] Add conversion from World Coordinates to Map Coordinates (#882) --- Dalamud/Utility/MapUtil.cs | 131 +++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Dalamud/Utility/MapUtil.cs diff --git a/Dalamud/Utility/MapUtil.cs b/Dalamud/Utility/MapUtil.cs new file mode 100644 index 000000000..b4bbe1038 --- /dev/null +++ b/Dalamud/Utility/MapUtil.cs @@ -0,0 +1,131 @@ +using System.Numerics; + +using Lumina.Excel.GeneratedSheets; + +namespace Dalamud.Utility; + +/// +/// Utility helper class for game maps and coordinate translations that don't require state. +/// +/// The conversion methods were found in 89 54 24 10 56 41 55 41 56 48 81 EC, which itself was found by looking for +/// uses of AddonText 1631. +/// +public static class MapUtil +{ + /// + /// Helper method to convert one of the game's Vector3 X/Z provided by the game to a map coordinate suitable for + /// display to the player. + /// + /// The raw float of a game Vector3 X or Z coordinate to convert. + /// The scale factor of the map, generally retrieved from Lumina. + /// The dimension offset for either X or Z, generally retrieved from Lumina. + /// Returns a converted float for display to the player. + public static float ConvertWorldCoordXZToMapCoord(float value, uint scale, int offset) + { + // Derived from E8 ?? ?? ?? ?? 0F B7 4B 1C and simplified. + + return (0.02f * offset) + (2048f / scale) + (0.02f * value) + 1.0f; + } + + /// + /// Helper method to convert a game Vector3 Y coordinate to a map coordinate suitable for display to the player. + /// + /// The raw float of a game Vector3 Y coordinate to convert. + /// The zOffset for this map. Retrieved from TerritoryTypeTransient. + /// Optionally enable Z offset correction. When a Z offset of -10,000 is set, replace + /// it with 0 for calculation purposes to show a more sane Z coordinate. + /// Returns a converted float for display to the player. + public static float ConvertWorldCoordYToMapCoord(float value, int zOffset, bool correctZOffset = false) + { + // Derived from 48 83 EC 38 80 3D ?? ?? ?? ?? ?? 0F 29 74 24 + + // zOffset of -10000 indicates that the map should not display a Z coordinate. + if (zOffset == -10000 && correctZOffset) zOffset = 0; + + return (value - zOffset) / 100; + } + + /// + /// All-in-one helper method to convert a World Coordinate (internal to the game) to a Map Coordinate (visible to + /// players in the minimap/elsewhere). + /// + /// + /// Note that this method will swap Y and Z in the resulting Vector3 to appropriately reflect the game's display. + /// + /// A Vector3 of raw World coordinates from the game. + /// The offset to apply to the incoming X parameter, generally Lumina's Map.OffsetX. + /// The offset to apply to the incoming Y parameter, generally Lumina's Map.OffsetY. + /// The offset to apply to the incoming Z parameter, generally Lumina's TerritoryTypeTransient.OffsetZ. + /// The global scale to apply to the incoming X and Y parameters, generally Lumina's Map.SizeFactor. + /// An optional mode to "correct" a Z offset of -10000 to be a more human-friendly value. + /// Returns a Vector3 representing visible map coordinates. + public static Vector3 WorldToMap( + Vector3 worldCoordinates, + int xOffset = 0, + int yOffset = 0, + int zOffset = 0, + uint scale = 100, + bool correctZOffset = false) + { + return new Vector3( + ConvertWorldCoordXZToMapCoord(worldCoordinates.X, scale, xOffset), + ConvertWorldCoordXZToMapCoord(worldCoordinates.Z, scale, yOffset), + ConvertWorldCoordYToMapCoord(worldCoordinates.Y, zOffset, correctZOffset)); + } + + /// + /// All-in-one helper method to convert a World Coordinate (internal to the game) to a Map Coordinate (visible to + /// players in the minimap/elsewhere). + /// + /// + /// Note that this method will swap Y and Z to appropriately reflect the game's display. + /// + /// A Vector3 of raw World coordinates from the game. + /// A Lumina map to use for offset/scale information. + /// A TerritoryTypeTransient to use for Z offset information. + /// An optional mode to "correct" a Z offset of -10000 to be a more human-friendly value. + /// Returns a Vector3 representing visible map coordinates. + public static Vector3 WorldToMap( + Vector3 worldCoordinates, Map map, TerritoryTypeTransient territoryTransient, bool correctZOffset = false) + { + return WorldToMap( + worldCoordinates, + map.OffsetX, + map.OffsetY, + territoryTransient.OffsetZ, + map.SizeFactor, + correctZOffset); + } + + /// + /// All-in-one helper method to convert a World Coordinate (internal to the game) to a Map Coordinate (visible to + /// players in the minimap/elsewhere). + /// + /// A Vector2 of raw World coordinates from the game. + /// The offset to apply to the incoming X parameter, generally Lumina's Map.OffsetX. + /// The offset to apply to the incoming Y parameter, generally Lumina's Map.OffsetY. + /// The global scale to apply to the incoming X and Y parameters, generally Lumina's Map.SizeFactor. + /// Returns a Vector2 representing visible map coordinates. + public static Vector2 WorldToMap( + Vector2 worldCoordinates, + int xOffset = 0, + int yOffset = 0, + uint scale = 100) + { + return new Vector2( + ConvertWorldCoordXZToMapCoord(worldCoordinates.X, scale, xOffset), + ConvertWorldCoordXZToMapCoord(worldCoordinates.Y, scale, yOffset)); + } + + /// + /// All-in-one helper method to convert a World Coordinate (internal to the game) to a Map Coordinate (visible to + /// players in the minimap/elsewhere). + /// + /// A Vector2 of raw World coordinates from the game. + /// A Lumina map to use for offset/scale information. + /// Returns a Vector2 representing visible map coordinates. + public static Vector2 WorldToMap(Vector2 worldCoordinates, Map map) + { + return WorldToMap(worldCoordinates, map.OffsetX, map.OffsetY, map.SizeFactor); + } +}