feat(Hunts) read hunt map from client, remove dead code in static files - #142
Open
Deldee wants to merge 10 commits into
Open
feat(Hunts) read hunt map from client, remove dead code in static files#142Deldee wants to merge 10 commits into
Deldee wants to merge 10 commits into
Conversation
XeldarAlz
requested changes
Aug 28, 2026
XeldarAlz
left a comment
Owner
There was a problem hiding this comment.
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.
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
force-pushed
the
hunt-local-maps
branch
from
August 29, 2026 18:52
3484a49 to
5e86626
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Checklist
Gates (CI enforces all of these):
dotnet build Aetherphone.sln -c Releaseis cleandotnet testpasses (this is where localization lockstep and accent contrast are enforced)async void, no new LINQ outside the allowlisted files, no rawImGuiHelpers.GlobalScale(useUiScale.Current), no hand-formatted clock text (useTimeText.Clock)Strings:
Core/Localization/L.csplus the same key in all nine JSONs undersrc/Aetherphone/Localization/, in this same PRL.csanden.jsonso they do not driftQuality:
/phoneor/phonedev)Windows/Components/widgets,TextStyles, andMetricstokensdocs/still tells the truth