实现账号绑定、持久登录与跨设备对局恢复
CI / test (ubuntu-latest, node 22) (push) Failing after 33m10s
CI / test (ubuntu-latest, node 24) (push) Failing after 34m41s
CI / tooling (lint, imports, typecheck) (push) Failing after 36m11s
CI / test (windows-latest, node 22) (push) Canceled after 0s
CI / test (windows-latest, node 24) (push) Canceled after 0s

This commit is contained in:
herryyun committed 2026-10-14 23:22:50 +08:00
1 parent 488db49f11
commit 7c25c89992
62 files changed
+6855 -1005

No files matched your search

+31
View File
@@ -73,6 +73,37 @@ Audio: autochess BGM per phase, UI SFX (buy/sell/refresh/level/merge/ready/timer
---
### Required account binding at the callsign field (fork integration)
The title hides 博士代号 until binding, then displays the role nickname as plain text without an input
(`public/js/skland/entry.js`;
`SP_SKLAND=1`, [skland.md](../skland.md)). The primary button shows 绑定账号 until a named role is fetched, then 开始.
Multiple roles start with the default role and can be switched. Unbinding or an empty role list clears the callsign
and restores 绑定账号. The nickname retains its person icon. The scan tab fetches a QR automatically and refreshes it
every 10 s; the first awaiting-confirmation response starts a 60 s window. Refresh keeps the current image visible
until its replacement is ready and updates the image source in place. Manual refresh remains available, with
serial 2 s polling and paused timers outside the scan tab/visible page. Saved callsigns/entered flags and account recovery cannot skip the binding lookup. Skland QR
login supports official/Bilibili channels; phone/password uses the Hypergryph account. Every game-entry HTTP request
uses the existing game session token and a 30-day HttpOnly JWT cookie, without entering the lobby automatically.
The cookie restores the role in a new tab or after a server restart; role choice persists on the server. The callsign
never becomes an identity key: UID plus server region determine a stable game player id, allowing duplicate names.
Account UI, styles and the entry policy stay in independent module files; title, boot and recovery have small hooks
to reduce upstream merge conflicts. An optional server account policy also checks hello and room/game requests
against the JWT-owned role; editing the client's UUID, region or name cannot select another player's binding.
Unbind revokes remembered login. Owner request, 2026-10-14; §31.12 and [skland.md](../skland.md).
The title's 恢复账号对局 picker queries the selected role's live server-side seat, even on a device with no local match
history. It replaces the visible 本机 recovery buttons (including the obsolete lobby shortcut). Opening it or restoring
the login cookie does not disconnect an active device. 开始 or an explicit recovery confirmation asks for the role's
current token, reconnects with the JWT, and enters only after welcome confirms the expected playerId. The existing
socket is then replaced (4001, no auto-reconnect), and its old token cannot take the role back on reload. A duplicated
tab or stale saved entered flag stays at the title unless its own current role token really resumed. Any anonymous
welcome also clears an already-entered shell; the connection banner's 在此页面继续 uses checked account entry.
The picker shows
empty, loading and error states, a takeover notice and a refresh action; an expired/replaced selector cannot create a
new match. Room/match state is still memory-only with the existing disconnect windows; server restart ends it.
The UI and entry adapter remain in public/js/skland/ (§31.13).
## 13. Local-client art (optional, host-side)
`tools/local-extract/extract.py` (Python: UnityPy + lz4 + Pillow; decodes Arknights' custom **LZ4AK** bundle compression via `aklz4.py`) extracts the art the web download does not include (some of it, most official HUD sprites among it, is on the public mirror too — §22.5) from a locally installed client (CrossOver Windows build or PlayCover iOS build) into `public/assets/local/**` and writes `data/local-assets.json` (`{ groups: { '<subdir>': { name: { path, w, h, kind } } } }`). Everything here is **optional**: clients must render correctly when the file or any entry is missing (fall back to the web assets / procedural art). The emotes and the guide pages below are on the public mirror too (§22.5): fetch-assets downloads them (data/assets.json `ui['emoticon/<dir>/<picId>']`, `ui['guide/<key>']`) and the client shows the local copy first, then that one (`data.js artUrls`); docs/DEPLOY.md §6 lists what still needs the client.