superwow: the map pair, GetQuestLinkForID, GetWeaponEnchantID
Four more off the DLL's manifest, and two measured corrections. GetMapPositionWorldLoc is the INVERSE of GetPlayerMapPosition, which is what the test asserts rather than three numbers: `map_proj::zone_world` is the reference's `0x4a7100`, whose own note is that used one axis per call it inverts the `zone_uv` that verb answers from. The law is transcribed into benilla-ui (which cannot depend on benilla-world) and the round trip is welded, which is the thing that actually keeps the two in step. GetMapBoundaries shares one new `worldmap::loc_rect_at` with the hover grid's own windowing, so no two readers of a (continent, zone) selection can disagree about which rect it means. GetWeaponEnchantID is the one thing GetWeaponEnchantInfo cannot say: the reference reads that very dword as its gate and then reports only that there WAS an enchant, so nothing on the stock surface can tell Windfury from Rockbiter. The id was already in hand and discarded as a `?` gate, so this was one field on the snapshot, plus a test that the two functions cannot disagree about which hands are enchanted. GetQuestLinkForID answers for a quest in the log and nil otherwise — which is also what upstream answers on the first call for one it fetches. The gap is one feed, not new protocol: the ask-once CMSG_QUEST_QUERY cache already exists app-side. That row also corrected the LINK FORMAT for both quest getters. The DLL's own formatter is `|cffffff00|Hquest:%d:%d|h[%s]|h|r`; ours was built without the colour wrapper on the reasoning that it matched the stock quest-log shift-click — but 1.12 has no quest links at all, so there was no stock shape to match and the measured string is the only authority. The four sound-driver getters are deliberately NOT built, with the reason recorded: every one of their return shapes is unknowable from here, none is called in the corpus, and this client has one backend and no enumeration to report — the same bargain KEY_DOWN/KEY_UP lost. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -31,7 +31,8 @@ nothing behind it.
|
||||
| `LootSlot` force-loot arg | done | `script/loot.rs`; truthy (Lua truthiness, e.g. `1`) routes to the take queue instead of the confirm queue |
|
||||
| `SetRaidTarget` `"local"` arg | done | `PartyRequest::SetRaidTarget.local` (`script/party.rs`); the live drain (`ui_party/feed.rs`) applies to `GroupState` directly instead of sending `CMSG`/`MSG_RAID_TARGET_UPDATE` |
|
||||
| Nameplate `frame:GetName(1)` → GUID | done | `script/object/frame_state.rs`'s shared `GetName`, `NamePlates::guid_for_frame` (`script/nameplate.rs`) |
|
||||
| `GetWeaponEnchantInfo([unit])` + `GetWeaponEnchantID` | todo, blocked | needs per-unit weapon-enchant tracking (today only `"player"`'s is fed at all) and no item-template data distinguishing an on-use charge slot from an equip/proc slot — would need new app-side state, not a binding tweak |
|
||||
| `GetWeaponEnchantID` | **done** | the one thing `GetWeaponEnchantInfo` cannot say: the reference reads that very dword as its gate (`0x4c97f8`, nonzero, no DBC lookup) and then reports only that there *was* an enchant, so on the stock surface nothing can tell Windfury from Rockbiter or a shaman's imbue from a rogue's poison. The id was already in hand app-side and discarded — `ui_char.rs`'s `weapon_enchant` used it as a `?` gate — so this was one field on the snapshot. Two returns, main hand then off hand, which is the order its six-value sibling already answers in; the shape is a reading, since upstream publishes no usage string for it and nothing in the corpus calls it. A test asserts the two functions cannot disagree about *which* hands are enchanted |
|
||||
| `GetWeaponEnchantInfo([unit])`'s unit argument | todo, blocked | the extension that takes a **unit** still needs per-unit weapon-enchant tracking; today only `"player"`'s is fed at all |
|
||||
| `GetContainerItemInfo` charges (negative stack count) | todo, blocked | the raw signed field exists (`ObjectFields::item_spell_charges`, benilla-protocol), but nothing in `benilla-formats`' item template says *which* of an item's five spell-trigger slots (if any) is a consumable charge rather than an equip/proc effect — exposing it without that would be a guess, not a port |
|
||||
| New functions (`SpellInfo`, `TrackUnit`/`UntrackUnit`, `SetMouseoverUnit`, `Clickthrough`, `SetAutoloot`, `UnitNameplate`, `CanLootUnit`, Import/Export/AppendText, map/world coord conversions, `IsSwimming`/`IsMounted`/`isIndoors`/`GetSpeed`, mail/quest-link getters) | todo, blocked | each needs new app-side state, not a binding tweak: `IsSwimming`/`IsMounted`/`isIndoors`/`GetSpeed` need a self-movement snapshot (`move_flags() & SWIMMING`, `unit_mount_display_id()`, `area.rs`'s `indoor` bool, and a `MoveSpeeds` component — none currently reach a `feed_*` system that can push them, and `ui_unit.rs`'s `feed_units` is already at Bevy's 16-param ceiling); **`SpellInfo` is now done** — `compat/superwow.rs`, over `script/spellbook.rs`'s `spell_display`: the player's book first, then the host's `Spell.dbc` probe ([`SpellProbe`], installed by `ui_script::lifecycle::install_spell_probe` on every VM build), so it reaches every shipped spell as the real mod does. The range pair stays nil — `SpellRange.dbc` is not on the probe; the rest (`TrackUnit`, `SetMouseoverUnit`, `Clickthrough`, `SetAutoloot`, `CanLootUnit`, `UnitNameplate`, file I/O, map/world coords, quest links) are each plausible but unstarted. **`CombatLogAdd` is done** and has its own row below. **The two mail link getters are now done**, built for ClassicAPI's own `Mail` namespace (`compat/classic_api/merchant_frame.rs`, see its row below) — SuperWoW specifies the same `GetSendMailItemLink`/`GetInboxItemLink`, so that half of this row is closed |
|
||||
| `UnitPosition(unitid)`, `CursorPosition()` | done | `UnitState.position` (`script/unit/mod.rs`), fed by `Transform` from `ui_unit.rs`'s `feed_units` (player/target/targettarget/npc) and `ui_tooltip.rs`'s `drive_mouseover_tooltip` (mouseover); functions in `compat/superwow.rs`. Party/raid/pet aren't wired (their own `snapshot()` call sites in `ui_party/feed.rs`/`ui_pet/unit.rs` pass `None` — each needs its own `Entity`→`Transform` lookup threaded through, not attempted this pass). Reading `Transform` broadly past the usual one-frame-stale tolerance raised `game_plugins.rs`'s `UPDATE_ACTIONABLE_CEILING` by 30 (cited there) — `Transform` is written by enough movement/animation/physics systems that `With<Guid>` alone doesn't shrink the ambiguity count |
|
||||
@@ -82,13 +83,13 @@ The usage strings, verbatim, for what is left:
|
||||
| `GetPlayerBuffID(buffIndex)` | done |
|
||||
| `UnitNameplate("unit")` | **done** — `compat/superwow.rs`, over `NamePlates::frame_for_guid`, through the **same** `plate_frame` wrapper ClassicAPI's `C_NamePlate.GetNamePlateForUnit` uses, so the two names cannot hand back different objects for one plate. Welded by a test that asserts exactly that, because an addon may feature-detect either |
|
||||
| `CanlootUnit("unit")` | **done** — needed no new feed: `UnitState` already carries `dead` and raw `dynamic_flags`, so it is the loot sparkle's own two-part test (`shows_loot_sparkle`: `unit_is_dead() && unit_lootable()`) read through the token map instead of the ECS, and a corpse that sparkles answers 1. Bit `0x1` is **per viewer** on the server — vmangos raises it only for players who may loot — so "can" really means can. **Note the lowercase `l`**: the *usage* string says `CanlootUnit` where the registered name is `CanLootUnit`; the registered name is what an addon calls, and the typo is in the error message only |
|
||||
| `GetMapPositionWorldLoc(continentIndex, zoneIndex, mapX, mapY)` | todo — map fraction to world XY, which `benilla-world`'s own map maths already does for the world map |
|
||||
| `GetMapBoundaries(continentIndex, zoneIndex)` | todo — the zone's world extent, the same table that conversion reads |
|
||||
| `GetMapPositionWorldLoc(continentIndex, zoneIndex, mapX, mapY)` | **done** — the **inverse of `GetPlayerMapPosition`**, which is the assertion the test makes rather than checking three numbers: `benilla-world`'s `map_proj::zone_world` is the reference's `0x4a7100`, whose own note is that used one axis per call it inverts the `zone_uv` that verb answers from. The law is transcribed into `benilla-ui` (which does not depend on `benilla-world`) and the round trip is welded. `mapX` is the horizontal fraction and so the world **Y** axis, `mapY` the vertical and so world **X** — `WorldMapArea`'s own convention, and why the returns are a world *loc* |
|
||||
| `GetMapBoundaries(continentIndex, zoneIndex)` | **done** — both indices are the pair `SetMapZoom` takes, 1-based with zone `0` the whole continent, resolved through one new `worldmap::loc_rect_at` that the hover grid's own windowing now shares, so no two readers of a selection can disagree about which rect it means. **Returns in `WorldMapArea.dbc`'s own field order** (LocLeft, LocRight, LocTop, LocBottom): upstream publishes the argument list and not the returns, and nothing in the corpus calls it, so the row's layout is the only order with evidence behind it |
|
||||
| `GetSpeed()` (no usage string: it takes no argument) | **done** — one new field on the posture snapshot, filled by `ui_unit.rs`'s `feed_self_movement` from `net.rs`'s `current_speed`, the reference's own `CMovement::GetCurrentSpeed 0x7c4c90` walk over our speed block and the same move flags every other field of that snapshot reads. **What could not be settled**: upstream publishes no prose and no addon in the corpus calls it, so whether its number is the *current* speed or the unit's *run* speed is unknowable from here. Current is the reading taken — it is the one client function named after speed that a hook would return, and the strictly more informative of the two (a snare or a mount shows in it). The consequence to know: standing still it is 0, exactly as that getter is |
|
||||
| `GetInboxItemLink(messageIndex)` | done (built for ClassicAPI's `Mail`) |
|
||||
| `GetSoundDriverName(driverIndex)` | todo — with `GetSoundDevices`, `GetNumSoundDrivers`, `GetLoadedSoundDriver`: four getters over the audio backend. benilla has one backend and no enumeration, so these answer a one-row list honestly or not at all; no addon in the corpus calls any of them |
|
||||
| `GetSoundDriverName(driverIndex)` | **deliberately not built** — with `GetSoundDevices`, `GetNumSoundDrivers`, `GetLoadedSoundDriver`: four getters over an audio-driver enumeration. Each one's *return shape* is unknowable from here (is a loaded driver an index or a name? is a device list a table or multiple returns?), nothing in grom's corpus calls any of them, and benilla has one backend and no enumeration to report. So all four would be guessed shapes over invented data, which is the same bargain `KEY_DOWN`/`KEY_UP` lost in the nampower section: a guessed shape an addon switches on is worse than an absent name it can feature-detect |
|
||||
| `GetQuestIDForLogIndex(questIndex)` / `GetQuestLinkForLogIndex(questIndex)` | done |
|
||||
| `GetQuestLinkForID(questID)` | todo — the same link for a quest the log does not hold, which is a server round trip (`Requesting quest ID %d from server` is the DLL's own next string) |
|
||||
| `GetQuestLinkForID(questID)` | **done for a quest in the log**, nil otherwise — which is also what upstream answers on the first call for one it has to fetch (`Requesting quest ID %d from server` is the DLL's own next string). The gap is one feed, not new protocol: `ui_quest_log.rs` already runs an ask-once `CMSG_QUEST_QUERY` template cache, so finishing it means a request queue out of the VM and an (id → title, level) feed back. **This row also corrected the link format for both getters**: the DLL's own formatter is `\|cffffff00\|Hquest:%d:%d\|h[%s]\|h\|r`, and ours had been built without the colour wrapper on the reasoning that it matched the stock shift-click — but 1.12 has no quest links at all, so there was no stock shape to match and the measured one is the only authority |
|
||||
| `ImportFile("filename")` / `ExportFile("filename","text")` | done, under nampower's fence. **Upstream's own folder is `Imports\<name>.txt`** (two more of its literals), where ours is `benilla-config/CustomFiles/` — the deviation is written up in the file-and-credential section below |
|
||||
|
||||
**The four chat-bubble rows are now live.** `ChatBubblesWhisper`, `ChatBubblesRaid` and
|
||||
|
||||
Reference in New Issue
Block a user