paste 5ad529b465
Release MPQ / package (push) Successful in 6s
Guard CharacterOrder_Save against empty char list
CHARACTER_LIST_UPDATE can fire with numChars == 0 in a transient state
when returning to the glue screen after /logout, before the server's
SMSG_CHAR_ENUM re-populates the character list. Without this guard,
CharacterOrder_Save writes an empty string to the vault, wiping the
saved order. The real CHARACTER_LIST_UPDATE that follows then reads
that empty string in Apply, returns early, and leaves the table at
server-default identity order — sort order silently reset.

Fix: skip the write when numChars is 0. The only legitimate zero case
is a brand-new account with no characters, where there's nothing to
persist anyway.
2026-07-17 15:31:09 -05:00
2026-07-17 00:13:13 -05:00

Octo GlueXML

Custom login and character-select UI for Octo. Overlays a small subset of the stock glue files with three features; everything else in Interface/GlueXML/ is loaded unchanged from the base MPQs.

Features

  • Saved-account login. The login screen shows a scrollable list of previously-used accounts with their last-used timestamp. Clicking a row fills the account name and hides the password field; a login without a typed password logs in using the credential stored in the Windows Credential Manager. A "Change password" button reveals the field on demand when you need to update a saved credential.
  • Character reordering. Hold on a character in the select screen for half a second to enter drag mode, then move it up or down. Order is saved per-realm and restored on the next login.

ClassicAPI dependency

The saved-login and character-order features rely on Lua bindings exposed by the ClassicAPI DLL, which is loaded alongside the client. Both features guard their entry points with type(fn) ~= "function" checks so the UI still functions when the DLL isn't present — you just lose persistence.

Saved login — Windows Credential Manager

Passwords never live in Lua or in WTF/. They go straight from the password field into the OS credential vault, and login submits are dispatched from C so the plaintext never crosses back.

Binding Purpose
SaveAccount(name, password) Writes a credential-vault entry. Called when the user types a password (either a first-time save or a "Change password" update).
LoginWithSavedAccount(name) C-side dispatch of the login using the vault password for name.
GetSavedAccounts() Returns { {name=…, lastUsed=epochSeconds}, … }lastUsed is the Windows LastWritten timestamp on the vault entry, auto-refreshed by LoginWithSavedAccount.
DeleteAccount(name) Removes a vault entry (backs the "Remove account" button).
GetSavedAccountName() / SetSavedAccountName(name) Persists just the last-used account name (via SavedVariables) so the same row is pre-selected on next launch. No password, no character map — those were dropped alongside the plaintext store.

Character sort order — per-realm WTF persistence

Persistence is keyed by character name, not by server-assigned charID. Slots renumber every time a character is added or deleted, so name is the only stable identifier.

Binding Purpose
GetSavedCharacterOrder(realm) Reads a |-separated name string for the current realm.
SetSavedCharacterOrder(realm, names) Writes it back.

On every CHARACTER_LIST_UPDATE the code loads the saved string, resolves each name to the current charID, drops names the server no longer knows about (deletions), appends any characters not in the saved list (creations), and re-saves. That means the on-disk order self-cleans without a hook in the delete path.

Releases

Push a v* tag to trigger the mpq-packager Gitea Action (.gitea/workflows/release.yml), which packages this repo into a patch-Z.mpq via StormLib according to mpq.yaml. Z sorts after Blizzard's stock MPQs, so its files win on conflict. Only .lua, .xml, and .toc files are placed in the MPQ — this README, workflow files, and build config are excluded.

S
Description
REQUIRES CLASSICAPI Personal Login/CharSelect
Readme 130 KiB
v0.0.4 Latest
2026-07-17 20:31:09 +00:00
Languages
Lua 100%