Skip to content

feat(Hunts) read hunt map from client, remove dead code in static files - #142

Open
Deldee wants to merge 10 commits into
XeldarAlz:devfrom
Deldee:hunt-local-maps
Open

feat(Hunts) read hunt map from client, remove dead code in static files#142
Deldee wants to merge 10 commits into
XeldarAlz:devfrom
Deldee:hunt-local-maps

Conversation

@Deldee

@Deldee Deldee commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

What

Removed the hunt maps to read from the game client
Cleaned up the static file to remove anything related to the old file, as well as unused section

Why

Files are big, they're already on the client

Closes #

How I tested it

  • Open the app
  • Load a mark
  • Ensure landmines are accurate
  • Load another mark, ensure landmine are accurate
  • Teleport to an aetheryte from the map, to be certain

Checklist

Gates (CI enforces all of these):

  • dotnet build Aetherphone.sln -c Release is clean
  • dotnet test passes (this is where localization lockstep and accent contrast are enforced)
  • No em dashes anywhere: code, strings, JSON catalogs, docs
  • No async void, no new LINQ outside the allowlisted files, no raw ImGuiHelpers.GlobalScale (use UiScale.Current), no hand-formatted clock text (use TimeText.Clock)

Strings:

  • Every new user-visible string is a LocString in Core/Localization/L.cs plus the same key in all nine JSONs under src/Aetherphone/Localization/, in this same PR
  • Any changed English text is updated in both L.cs and en.json so they do not drift

Quality:

  • Verified in-game on the screens this touches, on the build variant that matters (/phone or /phonedev)
  • Draw-path code allocates nothing per frame and uses the shared Windows/Components/ widgets, TextStyles, and Metrics tokens
  • README updated if this changes what a user sees or types; the relevant page under docs/ still tells the truth
  • Commit messages and this PR body carry no AI attribution trailers

@XeldarAlz XeldarAlz left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged onto dev and built: Release clean, 0 warnings, tests 1820/1821 (the one failure is SpotlightMathTests "7/2", a decimal separator issue on my machine, unrelated). Not verified in-game. I re-checked the data claims and they hold: sizeFactor is byte identical, all 1064 mob and 91 aetheryte POIs survive, all 1063 zonePoiIds still resolve, and every POI in the old data sits inside its zone's crop rect, so normalizing by 2048 is the right call. Two blocking comments inline.

Comment thread src/Aetherphone/Apps/Hunts/HuntsApp.Detail.cs Outdated
Comment thread src/Aetherphone/Core/Hunts/HuntZoneMapTextures.cs
Comment thread src/Aetherphone/Core/Hunts/HuntZoneCatalogue.cs Outdated
Comment thread src/Aetherphone/Core/Maps/MapPixelMath.cs
Comment thread src/Aetherphone/Core/Hunts/HuntZoneMapTextures.cs Outdated
Comment thread src/Aetherphone/Core/Hunts/HuntUiLanguage.cs Outdated
Comment thread src/Aetherphone/Core/Hunts/HuntZoneModels.cs
Comment thread src/Aetherphone/Apps/Hunts/HuntsApp.Detail.cs Outdated
Deldee added 10 commits August 29, 2026 14:17
Replace the bundled, Faloop-sourced JPEGs under Hunts/Maps with the
real map texture Dalamud loads on demand: HuntZoneMapTextures now
takes IDataManager and ITextureProvider, resolves a territory's Map
row (TerritoryType.Map), and loads ui/map/<id>/<id>_m.tex (with the
same underscore/no-slash filename fallbacks HousingGameMaps already
uses) via ITextureProvider.GetFromGame, caching the resolved path per
territory since Draw calls this every frame the zone map is visible.

Spawn dots normalize against the full 2048px canvas the same way
MapPixelMath.ToGameCoordinate already does for the same rawX/rawY
inputs, not HuntPOI.json's old pixelSize/offset: those described the
crop Faloop served their zone JPEGs at, not the raw coordinate space
itself, so they only lined dots up on that same crop. On the full,
uncropped in-game texture they placed dots off, which pixelSize and
offset (and the now fully unused HuntZoneMap fields and zone
parameter behind them) are dropped for.

Drop the now-unused local map JPEGs, the FileTextureCache they were
the only user of, and the PowerShell tool that downloaded them from
Faloop, since nothing bundles or fetches map images anymore.
pixelSize and offset described the crop Faloop served their zone
JPEGs at, dead since the previous commit switched to the full in-game
map texture. sizeFactor only differs from HuntZoneMap's own 100
default for six Heavensward zones (95 apiece), so keep it only there
and let the default carry the rest.

HuntZoneDefinition.ExpansionId and TerritoryId were never read, and
HuntPoiEntry.JourneyPoiId had no reader at all. Drop all three from
the model and the JSON, along with every POI entry whose type isn't
mob or aetheryte: boundary (121), ferry (4), and gatekeeper (3)
entries are never looked up, either by HuntMob.json's zonePoiIds
(verified against all 1063 referenced ids, which resolve to mob-type
POIs exclusively) or by the aetheryte-only filter that builds the
map's aetheryte dots. No zone is left with zero POIs.

Zone display names move to a live TerritoryType.PlaceName lookup too,
in whichever of the four game languages HuntUiLanguage maps
Aetherphone's UI language to (matching HuntMobLore's existing mapping
for descriptions and tips). Territory resolution used to try the
client's own installed language first before falling back to English,
matching HuntPOI.json's per-language name against a TerritoryType
sheet read in that same language; a handful of zones were missing a
German or French name in Faloop's data, which meant a JA/FR/DE client
could silently fail to resolve a zone and return territory 0. Always
building the lookup table from an explicitly English-requested sheet,
matched against a single guaranteed-present English name, fixes that
and is what makes flattening HuntZoneDefinition.Name from a
four-language dictionary down to one string safe.

209KB down to 125KB total.
TipFor resolved through HuntUiLanguage.Key(), which only ever returns
de/fr/ja/en (the four game-client languages), collapsing every other
Aetherphone locale to English before HuntMobTextCatalog even got a
chance to look anything up. HuntMobTips.json actually carries all
nine locales though (unlike HuntMobDescriptions.json, which really is
game-client-language-only and correctly keeps using HuntUiLanguage),
so es/pt/ru/tr/zh readers always saw English tips despite their
translation existing in the file. TipIsFallback already used
Loc.Current.Code, so it was quietly out of sync with what TipFor
actually fetched. Pass Loc.Current.Code straight through instead and
let TextFor's own per-entry fallback handle real gaps.
ResolveZoneLabel called TerritoryType.PlaceName.Value.Name.ExtractText()
every frame the detail zone map is on screen; ExtractText decodes a
Lumina SeString into a new managed string on every call, and Draw runs
every frame. Add zoneLabelCache, mirroring HuntsApp.List.cs's
worldLabelCache/rowIdCache pattern: TryGetValue, compute once, store.
Keyed by territory id, zone id, and UI language, since the language is
user-changeable at runtime and the fallback label differs per zone.
…dLanguageException

GetExcelSheet<TerritoryType>(ClientLanguage.English) throws on a client
whose game data does not carry English strings for that sheet, which
CN/KR clients can hit. BuildTerritoryIdLookup ran this lazily from the
draw path with nothing catching it, so a CN client would crash on the
first zone-to-territory lookup and keep re-throwing every subsequent
frame since the null-coalescing cache never got a chance to assign.
Catch UnsupportedLanguageException, log once, and cache the resulting
empty lookup so the failure path only ever runs once, same as success.
…eLabel

The method only ever read zone.Id from the HuntZoneDefinition; the
caller already has that string on hand.
HuntZoneDefinition.Map already defaults to a HuntZoneMap with
SizeFactor 100 when the key is absent, so an explicit "map": {} on 41
zones carried no information. Drop the key entirely from those zones;
the 6 zones with a real sizeFactor override keep their map block.
…guage

It sits next to HuntClientLanguage.Key(), which returns the actual
client language; this one maps the plugin's UI language to a sheet
language for GetExcelSheet, a different thing the old name implied
was the same.
HuntZoneMapTextures and HousingGameMaps each carried their own copy of
TextureCandidates/FileExists/ResolveTexturePath, with Hunts silently
missing the _s.tex fallback candidate Housing had. Extract both into
Core/Maps/MapTextures, keeping all five candidates so the two callers
stay behaviorally identical; both now pass a subsystem label through
for the existing Debug-level 'could not test' log line.
The zone map always opened fit to the whole texture, so a mob whose
candidates cluster in a small corner of the map (as little as 47% of
the panel for outer_la_noscea) left the dots small and clustered
together even though their positions were correct.

Add PhotoZoomView.FocusOn(stage, size, normalizedBounds, padding), on
top of a new SnapTo that clamps to the existing zoom range and reuses
the existing pan clamp, so a target region can be framed immediately
without the user ever seeing the unfocused full-texture view. Hunts
computes the bounding box of the current detailMapPoints (not the
aetheryte points, which can sit far from the candidate cluster and
would fight the zoom) and focuses on it once per newly opened mob,
deferred to the first Draw of the map panel since the stage and
texture size aren't known until then. Live phase/zone narrowing while
a page stays open does not re-focus, to avoid yanking the view under
the user; only opening a different mob does.
@Deldee
Deldee requested a review from XeldarAlz August 29, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants