Skip to content

Commit 5d9a685

Browse files
committed
changelog: v3.1.11
1 parent 639d9c5 commit 5d9a685

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## [v3.1.11] - 2026-08-27
4+
5+
### Added
6+
- **Bit-level packet access, and an expansion id with no parsers behind it now says so.** 4.x marshals a packet as a bit stream interleaved with the byte stream in one buffer, and a GUID as a mask bit per byte followed by the non-zero bytes XOR'd with 1, each pass in an order belonging to the opcode. `Packet` had no bit accessors at all; it has `writeBit`/`readBit`, `writeBits`/`readBits` and the two GUID passes, which take the order as an argument because the per-opcode tables have to be read off a running core rather than recalled. A byte write flushes the open bit byte and a byte read closes it, so none of the 181 packed-guid call sites has to remember to. `createPacketParsers` used to hand an unrecognised expansion WotLK's parsers, which misparses rather than failing
7+
- **The 109 Cataclysm movement layouts, derived from a 4.3.4 core rather than transcribed.** 4.3.4 chooses the order of the bit and byte streams per opcode with no pattern between them - `MSG_MOVE_START_FORWARD` writes position Y, Z, X then guid mask bits 5, 2, 0, while `MSG_MOVE_HEARTBEAT` writes Z, X, Y then pitch, timestamp and fall bits - and none of the 109 follows from another. `derive_cata_movement` parses the core's own `MovementStatusElements` arrays into `movement_sequences.json` and `cata_movement.cpp` executes it, because 109 hand-written readers would be 109 chances to transcribe one wrong
8+
9+
### Fixed
10+
- **Every label in the interface was drawn and measured at 82% of its size.** ImGui asks stb_truetype to fit a face's whole ascender-to-descender span into the height it is given; `<FontHeight>` means the em square, which is what every traditional font API means by a size - stb's own header calls the em mapping "probably what traditional APIs compute". FRIZQT__ spans 1215 units of a 1000-unit em. The width is the half that moves things: anything anchored to a caption's right edge landed short by 18% of that caption's width, which is how the auction house's rarity dropdown came to sit on top of the item level boxes it hangs off. `ExtraSizeScale` carries the correction, read per face off its own `head` and `hhea`
11+
- **The chat box drew what you typed in the wrong face, at the wrong size, with no shadow.** An EditBox, a message frame and a SimpleHTML draw text of their own, and the XML says how by putting a `<FontString>` straight in the frame rather than in a Layer. Thirty-nine do, `InputBoxTemplate` and the chat window among them, and the emitter only walked `<Layers>` - so all thirty-nine were dropped, where `ChatFontNormal` is ARIALN at fourteen with a black shadow. The setters it needs were no-ops on a frame - `SetFontObject`, `SetTextHeight`, `SetShadowOffset`, `SetShadowColor`, `SetJustifyH`, `SetJustifyV` - and the edit box and message paths drew no shadow at all
12+
- **Nothing on the buff bar said what a buff does.** The aura tooltip gave a name, a stack count and a countdown and never the effect, so Power Word: Fortitude never mentioned the 165 Stamina. `SetUnitDebuff` had less still - no stacks, no time left - and is the same builder now with HARMFUL in its filter
13+
- **A tooltip nothing had filled yet lost its title.** `SetText` was refused unless the flag only the fillers set was already on, and the first line of a tooltip is a `SetText`, so the frame metatable took the refusal as "this is not a tooltip" and stored the words where a button keeps its label. A GameTooltip is one before anything has been put in it
14+
- **A mounted player looked to everyone else like one landing over and over.** Ground contact breaks for a frame at riding speed, and the frame after it read as a landing: `MSG_MOVE_FALL_LAND` went out, and every client in range plays that as a landing on the mount. Crossing open ground sent several a second. The airborne interval is counted now and a landing is reported only for one long enough to have been a fall
15+
- **The guild vault opened on an empty panel.** `CMSG_GUILD_BANKER_ACTIVATE`'s `sendAllSlots` byte was zero and the tab query's full-update flag was false; both reach `Guild::SendBankList` as its "with content" argument, so the client asked the server for a bank and told it to leave out what was in it. The reader also gated the tab-name block on the update flag *and* on the list being tab zero, which is Cataclysm's rule - 3.3.5 and 2.4.3 write it under the flag alone, so a tab query answered with the names attached had the item count read out of the tab count and the items out of the names. `GUILDBANK_UPDATE_TABS`, `_MONEY` and `_WITHDRAWMONEY` are fired now; the first is what runs `GuildBankFrame_SelectAvailableTab`, which is what picks a tab the player may look in and draws it
16+
- **A hunter with nothing selected shot himself until he died.** An empty `SpellCastTargets` is `TARGET_FLAG_SELF` on the wire, and the server reads that as "the caster is the target" - it fills the unit target in with the caster and casts the spell there. The cast builder wrote it for any absent target. A spell whose `EffectImplicitTargetA` names an enemy now raises "You have no target" and sends nothing, which is what the real client does; self-casts and fishing clear the target on purpose and are what that flag is for, and a friendly spell still falls back to the caster where auto self-cast asks for it
17+
- **The cursor over a vendor was the plain hand.** Two faults, either of which was enough. `NPC_FLAG_VENDOR` was `0x04` - one of the two bits in the run that nothing sets - so no merchant in the game ever read as one; the rest of the run is written out beside it now, and the two spirit flags were the other way round, which no caller could see because both are only ever tested as a pair. And the cursor asked the picker for `closestGuid`, the nearest entry point of anything the ray touched: a game object's fallback sphere is 2.5 yards against a unit's 1.8, so the stall or forge a merchant stands at answered first. `resolve()` is what a click acts on and carries the unit-over-object bias
18+
- **An achievement banner appeared and stayed for the rest of the session.** `AlertFrame_AnimateIn` shows it, plays three animation groups in a row, then plays the `waitAndAnimOut` whose `OnFinished` hides it - and the second call raised, so everything after it was lost. A `<Texture>` may carry `<Animations>` of its own and only a frame's were emitted, so the glow and the shine had no `animIn`; regions keep their methods on themselves rather than on a shared metatable, so `CreateAnimationGroup` is copied onto them too. And an animation's `parentKey` was written on the frame rather than on its group, so `frame.waitAndAnimOut.animOut` was nil - every one of the six sites that reads one in the interface reaches it through the group, as WoW does. The same template shape carries the dungeon-completion and BNet toasts
19+
- **Turtle's whole options framework failed to compile, and took a run of names elsewhere with it.** `OptionsFrame.xml` pulls its two Lua files in with `<Include>`, and an include was handed to the XML parser whatever it was: "expected an element" on `Options\Options.lua` and `Options\Functions.lua`, and with them `OptionsFrame_AddCategory` and every panel that registers one. Which element named a file does not decide how to read it - the extension does, both ways round. Reported in #132
20+
- **Turtle's loot window came up with no buttons in it.** `LootFrame.xml` declares `<Button name="LootButton" virtual="true">` and then writes `<LootButton name="LootButton1"/>`, which the real client accepts and this reported as an unknown type, building nothing inside it. A virtual frame records what kind of frame it makes now, and an element naming one is created as that kind and inherits it. Reported in #132
21+
- **One client's asset tree answered for another's missing files.** The base fallback resolves per file with no check on where the file came from, and a thin expansion tree leans on it - the wotlk tree here holds 18,943 files against the base tree's 199,468, so nine lookups in ten are answered by the base. Cataclysm makes it visible rather than merely wrong: its Azeroth is the sundered one, so a tile a Cata tree does not cover was drawn as the old world with nothing said. `asset_extract` records the expansion in `manifest.json` and the client checks it
22+
- **An area trigger that refused said nothing useful.** The near-miss report needed the player inside the trigger's own flat extent before it would say anything, and a portal box is three yards across - so "I walked into it and nothing happened" was never the case it covered. It reports a pass within a few yards now, and prints the three rotated axes the box test actually compared rather than only the height. The cooldown branch moves to warning level for the same reason: a suppressed portal and a broken one look identical from the chair, and the window is ten seconds after any arrival
23+
324
## [v3.1.10] - 2026-08-27
425

526
### Fixed

0 commit comments

Comments
 (0)