1131 Commits
Author SHA1 Message Date
herryyun 7c25c89992 实现账号绑定、持久登录与跨设备对局恢复
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
2026-10-14 23:22:50 +08:00
sganggs 488db49f11 0.2.6: CHANGELOG — the #569 line sits with the other scene line (no stray blank line splitting the list) 2026-10-13 18:57:03 +08:00
sganggs 205f3bb7f7 0.2.6: the device slabs stay drawn on an official scene (GitHub #569) — 射击台, 特制水上平台 and 封印的地面 lived only in the procedural board's bucket that a scene replaces, so 战场#03's raised tiles by the blue gate were flat and 战场#05(上半)'s water platforms read as open water; buildBoard repeats them into buckets.raised / raisedDecal with sides reaching under the scene's ground and setStage draws just those on a scene (the 'h' high ground is the scenes' own and is not repeated); DESIGN §31.11, client §15; golden: unchanged 2026-10-13 17:45:04 +08:00
sganggs d8aab0a2db 0.2.6: README / DEPLOY give the full bundle's built size (556 MB, about 790 MB extracted; the disk lines' stale 710 MB too) 2026-10-13 16:22:29 +08:00
sganggs 566f3a7cd6 0.2.6: version 0.2.6 — package.json / package-lock.json / APP_VERSION (DEV_BUILD turns false), README release form and current-version line, CHANGELOG 0.2.6 — 2026-10-13, DESIGN versions line and index, §31 header 2026-10-13 16:17:03 +08:00
sganggs b5d0c3f96f 0.2.6-dev: a dropped connection to the web-font host (fonts.googleapis.com / fonts.gstatic.com — the page falls back to the local and system fonts) no longer fails real.e2e, mock.e2e or leftovers.e2e, as loadout / match-info / i18n already allowed; golden: unchanged 2026-10-13 16:16:36 +08:00
sganggs 9a0af9e891 0.2.6-dev: connect the history of PR #558 by IceCodeNew — the reviewed adaptation is kept (tree unchanged) 2026-10-13 16:04:32 +08:00
sganggs 347343d739 0.2.6-dev: 魂灵之影 only on a board of its field (#557, PR #558 by IceCodeNew adapted) — shadowTile requires Battle.onFieldBoard: a teammate's half counts, a boss field's hand / 临时整备区 rows and a solo boss field's empty half do not, no summon when nothing fits (the PR cut the bench rows by number, which left an empty half legal); the PR's test plus a solo / pair case; DESIGN §3, §31.10, SIM; golden: unchanged 2026-10-13 16:04:32 +08:00
sganggs 1df530f2b9 0.2.6-dev: a piece has no screen rect until it is first drawn — pieceScreenRect returned a just-built view's unprojected (0, 0) record, so a browser test grabbed a piece bought that frame at the canvas corner (the intermittent .fwheel__dia timeout in coop.e2e / real.e2e); the tests' piecePoint waits for a drawn piece that holds still; golden: unchanged 2026-10-13 15:54:40 +08:00
sganggs 2b685011e9 0.2.6-dev: browser tests read the round's real rules — free deploy tiles come from the client's own placement legality (terrain 机变 cards, devices, the boss half) instead of the stage's plain tiles, the facing tour waits for a later round when its purchase merged into an elite, and real.e2e skips its one strategy turn only while 跳过 is enabled (PR #546); golden: unchanged 2026-10-13 14:20:02 +08:00
sganggs a1f0d1bb6e 0.2.6-dev: merge claude/r37-impostor — GitHub #542: impostor boxes from each skeleton's measured clip bounds (idle core, played clips within limits, the rest drawn directly while they play), every slot drawn inside its own scissor, frozen models posed at their clip's first frame, PIXI's pooled batch buffers (no Apple GPU stall from the per-slot flushes); golden: unchanged
# Conflicts:
#	CHANGELOG.md
#	docs/design/client.md
#	docs/history/0.2.6.md
2026-10-13 06:30:53 +08:00
sganggs 47004a3651 0.2.6-dev: impostor review follow-ups (#542) — a skeleton stays in the clip-bounds queue only while an actor uses it (the last one destroyed drops its pending clips, the clip in progress and its scratch skeleton; a later actor queues them again), a clip whose sampling throws is recorded as not measurable and drawn directly while it plays instead of counting as empty, and a frozen model's first update counts as posed only when it succeeded; DESIGN §31.6 updated; golden: unchanged 2026-10-13 06:29:20 +08:00
sganggs d4cdd567dc 0.2.6-dev: the lobby flood test floods in bursts until the server closes the socket and waits for the close with a timeout — on a heavily loaded machine one burst of 600 could be read over more than the 1 s drop window, the socket was never closed and the unbounded wait hung the whole file; golden: unchanged 2026-10-13 06:18:17 +08:00
sganggs bd932158f3 0.2.6-dev: connect the history of PR #552 by IceCodeNew — the reviewed adaptation is kept (tree unchanged) 2026-10-13 06:14:03 +08:00
sganggs 57c9cc528e 0.2.6-dev: connect the history of PR #416 by Cromemadnd — the reviewed adaptation is kept (tree unchanged) 2026-10-13 06:14:03 +08:00
sganggs 349debb320 0.2.6-dev: merge claude/r37-ui — PR #416 ported (each round start replays the own board's Start clips and landing sounds in deployment order, as the maintainer confirmed from official play; landings on buy / a new board tile [ASSUMED]; one sound per landing, a landing pool that hands the oldest voice to the newest) and PR #552 ported as the optional 「弹药数量」 setting, default off; golden: unchanged 2026-10-13 06:14:01 +08:00
sganggs 3a6ec26127 0.2.6-dev: the co-op browser test skips its one strategy turn only while 跳过 is enabled — since PR #546 the last player still to pick sees it disabled, which a random draft order gives the guest about one time in three; golden: unchanged 2026-10-13 06:13:39 +08:00
sganggs 0ceb6641ec 0.2.6-dev: PR #416 by Cromemadnd — every landing of a round start is heard: prep landing sounds take a voice of their own pool (LAND_VOICES 3, the oldest fading out over 30 ms) instead of being dropped by the battle limiter, which let only the first two of a chain sound since 192 of 210 operators share the 1.41 s b_char_set (Grok's review); per-piece cooldown, SFX volume and mute kept, the battle sounds' limiting unchanged, the generic files fetched ahead when a match view comes up; DESIGN §31.8; golden: unchanged 2026-10-13 05:46:29 +08:00
sganggs 4c2fe9431d 0.2.6-dev: DESIGN §31.6 for the impostor box without the setup pose (slots 1.26× the old area on the roster, the DPR-2 crowd numbers, the batch-buffer setting; the open item resolved), docs/design/client.md, CHANGELOG 0.2.6-dev (#542); golden: unchanged 2026-10-13 05:26:05 +08:00
sganggs c973c1a1ad 0.2.6-dev: impostor boxes without the setup-pose floor (#542) — a model frozen before its first update (built while stunned without a stun clip, or dead without a death or idle clip) shows its clip's first frame instead of its setup pose, the box's core is the idle clip (looping clips up to 5× it, one-off clips 2×), and PIXI gets a vertex buffer per batch flush (the per-slot scissor's flushes stalled Apple GPUs: 42–58 → 60 fps for 120 units at 1920 × 1080); golden: unchanged 2026-10-13 05:26:04 +08:00
sganggs a3da5c2775 0.2.6-dev: DESIGN §31.8 says how PR #416 by Cromemadnd sounded twice — its wheel-confirm hook restarted a Start that had run 0.3 s (a purchase then a move) and its round-start sequence forced every piece; the state that follows a wheel drop never landed there 2026-10-13 04:47:58 +08:00
sganggs 461a7747e1 0.2.6-dev: port PR #552 by IceCodeNew — an optional 「弹药数量」 setting (default off: the official HUD has no such number, the maintainer's decision of 2026-10-13) shows an ammo skill's rounds left / magazine under its bar, from the exact b.snap ammo counts; sanitised with the other settings, applied by the field view live, all four language packs, the diagnostics line; the simplified board has no ammo bar; DESIGN §31.9; golden: unchanged 2026-10-13 04:43:39 +08:00
sganggs 231da0efbc 0.2.6-dev: port PR #416 by Cromemadnd — at every round start the own board's pieces replay their Start clip and landing sound one after another in deployment order (the maintainer's confirmation from official play, 2026-10-13), and a purchase or a move onto / across the board plays them too ([ASSUMED], the PR author's account); one sound per landing, idle prep pieces only, the round marked once the view took the sequence, own board only, timers cleared when prep mode ends and on destroy; DESIGN §31.8; golden: unchanged 2026-10-13 04:36:56 +08:00
sganggs 281cf01ff0 0.2.6-dev: connect the history of PR #554 by xcdoge — the reviewed adaptation is kept (tree unchanged) 2026-10-13 03:48:47 +08:00
sganggs 47b9e5b63e 0.2.6-dev: the official battlefield scenes use the extracted light at full strength — SCENE_LIGHT direct and indirect 1 instead of 0.2.5's eye-tuned 0.8 / 0.4 (GitHub #549, the light half of PR #554 by xcdoge; its emissive change to the metal board is not taken); DESIGN §31.7; golden: unchanged 2026-10-13 03:48:47 +08:00
sganggs d7cb8770da 0.2.6-dev: DESIGN §31.6 open item worded plainly (the setup pose could be dropped from the impostor box if a model frozen before its first update were posed at its clip's first frame) (#542); golden: unchanged 2026-10-13 03:44:06 +08:00
sganggs f5b3908804 0.2.6-dev: DESIGN §31.6 adds the slot cost at DPR 2 (the 120-unit crowd keeps 39 of its units in the atlas at 1280 × 720 instead of 119) and, as open, the share of the setup-pose floor (1.16 × instead of 2 × without it) (#542); golden: unchanged 2026-10-13 03:43:49 +08:00
sganggs 0b88a0f515 0.2.6-dev: DESIGN §31.6 impostor bounds and slot clearing (#542: seen, cause, now, cost, [ASSUMED], tests), docs/design/client.md describes the impostor box and slot clipping, CHANGELOG 0.2.6-dev 界面 credits @ImPQlc; golden: unchanged 2026-10-13 03:30:48 +08:00
sganggs c45d86f70c 0.2.6-dev: impostor slots sized from every clip a unit plays and clipped to themselves (GitHub #542 by @ImPQlc: in a crowd 野鬃's idle flag, 浊心斯卡蒂's S3 flight and 隐现's pistol were cut, offset or left stray pixels) — spine.js measures each skeleton's clips once within a 2.5 ms frame budget, units.js impostorBox covers the setup pose and the played clips (a clip past 4× / 2× of that core is drawn directly while it plays, the slot kept), impostor.js draws each slot's skeleton under a scissor rect of the slot; golden: unchanged 2026-10-13 03:30:48 +08:00
sganggs e825254850 0.2.6-dev: the render demo's stress scene takes &ops=<chessId>,… — up to 6 given chess in the crowd's front row (ids 6, 8, 10, …), a given model inside an impostor-rendered crowd (#542); golden: unchanged 2026-10-13 03:30:48 +08:00
IceCodeNew 1196cde1f8 refactor(render): inline ammunition readout after ablation (#552) 2026-10-12 18:23:17 +00:00
IceCodeNew cc3c210779 fix(sim): keep Wisdel shadows off the boss bench (#557) 2026-10-12 17:59:40 +00:00
sganggs 975c79da70 0.2.6-dev: PR #546's design note moves from the released 0.2.5 chapter to DESIGN §31.5 (docs/history/0.2.6.md, now host bandwidth and community follow-up); CHANGELOG 0.2.6-dev credits PRs #546 and #547; golden: unchanged 2026-10-13 01:44:20 +08:00
sganggs 77865e6bc2 0.2.6-dev: merge PR #546 by Xinglan233 — the strategy draft enables 跳过 only while another unpicked player remains (finished players stay in the shown order but are not skip targets) 2026-10-13 01:43:55 +08:00
sganggs 1d55c93e3a 0.2.6-dev: merge PR #547 by Xinglan233 — the scene-asset test resolves the repository root with fileURLToPath (on Windows the URL pathname doubled the drive letter) 2026-10-13 01:43:55 +08:00
sganggs c5925a76fa 0.2.6-dev: the emote fallback browser test blocks the mirror copies under their content-hashed URLs too (/assets/~<hash>/ui/emoticon/…, host bandwidth layer 1); golden: unchanged 2026-10-13 00:19:44 +08:00
xcdoge 80abaaf1b1 #549:棋盘材质的自发光对齐官方 _EmissionColor(0.25 → 1),棋盘亮度再 +4%
接上一提交(官方场景的两个增益改回 1)之后,剩下的偏暗还有一处同类问题:棋盘瓦片材质的自发光被手调压暗了。

官方真值(UnityPy + tools/local-extract/aklz4.py 的 LZ4AK 解码器 dump 客户端
arts/maps/map_autochess/res.ab 的 Material):

  MT_autochess          _Color = (1,1,1,1)   _EmissionColor = (1,1,1,1)
                        _MainTex = TX_autochessi_D   _EmissionMap = TX_autochessi_E
                        _MetallicGlossMap = TX_autochessi_M   _BumpMap = TX_autochessi_N
                        _Metallic = 0   _Glossiness = 0
  MT_autochess_common   _EmissionColor = 0.5588(同样带 _EmissionMap)
  MT_autochessi_BG      _Color = 0.71323 + shader Torappu/Unlit/Texture
                        ⇒ 与代码里的 LIGHTING.bg.color = 0.713 完全一致(这条本来是对的)

也就是说官方棋盘是**自发光**的(albedo 加 emission),不是靠环境灯照亮;而 materials.js 里 boardMaterial 的
emissive 默认就是 1(emissive / emissiveMap 直接对应上面两个材质),decalMaterial(_common 图集)也已经是
官方的 0.559 —— 只有 scene.js 的 LIGHTING.emissive = 0.25 把它整体压到四分之一。

改动:LIGHTING.emissive 0.25 → 1,注释写明官方 _EmissionColor 的来源与它为什么必须是 1(与上一提交那两个
增益同一类问题:照截图手调的系数)。

实测(同一 m04 场景、同一相机,只取棋盘区域求平均,官方截图同口径):

  官方截图      亮度 129.0
  最初          亮度  89.7(−30%)
  场景增益改回 1  亮度 103.3(−20%)
  本提交        亮度 107.4(−17%)

已知未尽:还剩约 −17%。官方棋盘瓦片的着色器是自定义的(dump 里 m_Shader 读不到完整定义),无法直接比对公式,
下一步需要把画面按材质逐区域分离(棋盘瓦片 / 场景沙地 / 水)再分别对齐,而不是继续拧全局系数。
2026-10-12 23:52:31 +08:00
xcdoge 045cc96172 #549:官方场景偏暗 —— 把两个手调增益改回官方语义(直射光 intensity、烘焙光强 lightRange)
问题(#549):3D 棋盘按战场显示官方场景后,整体比官方实机明显偏暗、发闷。只取棋盘区域做量化:官方截图
平均 RGB 152.4/125.8/92.3(亮度 129.0),本项目 98.8/89.4/65.0(亮度 89.7)。

原因:官方场景材质的两个增益是当初照截图手调的猜值(代码注释里自己标了 [ASSUMED]):

  export const SCENE_LIGHT = Object.freeze({ range: 8.0, ambient: 0.2, direct: 0.8, indirect: 0.4 });

而官方数据是(从客户端场景包里 dump 出来的真值,见下):

  scene.json light = { dir: [0.36121, 0.44604, 0.81889], color: [1.0, 0.9312, 0.87131], intensity: 1.1 }
  Light「Mainlight (1)」: m_Type=1(Directional) m_Intensity=1.1 m_BounceIntensity=1.5
  lightRange = 8.0

- direct 0.8 ⇒ 直射光 = lin(color) × (1.1 × 0.8) = 0.88,比官方的 1.1 暗 20%;
- indirect 0.4 ⇒ 烘焙间接光被乘成 lightRange × 0.4 = 3.2,而 lightmap 的语义是"贴图 1.0 = lightRange 的线性光"
  (scenes.py:`L = 5^2.2 · A^2.2 · RGB`,PNG 存 (L / lightRange)^(1/2.2)),所以 indirect 必须为 1 才等于官方烘焙值,
  0.4 等于把间接光压掉 60%。片元里的 `pow(lm.rgb, 2.2) * uLmScale` 与 `uLightColor * N·L * shade` 正是这两项。

改动:`SCENE_LIGHT` 的 direct / indirect 改回 1(= 场景自己的值,与那段注释原本的描述一致),并把注释改成
说明它们为什么必须是 1、以及低于 1 会相对官方渲染变暗(#549)。

实测(同一 m04 场景、同一相机,只取棋盘区域求平均):

  官方截图            亮度 129.0
  改前                亮度  89.7(−30%)
  改后                亮度 103.3(−20%)

顺手排除的两个猜想(都量过,都不是原因):

- 雾:官方 RenderSettings 是 m_Fog = False,而 scene.js 给场景挂了 T.Fog(0x0c1114, 17, 36)。A/B 实测雾开/关
  亮度 95.3 / 95.4 ⇒ 在本视角下没有影响(相机在 near 以内),本次不动它。
- 焦点暗角:官方场景材质也套了棋盘的 focusMask(框外 × uFocusDim = 0.72)。A/B 实测去掉后 103.3 → 106.6(+3%),
  因为本视角的焦点框覆盖了大部分棋盘;官方场景本身没有这种衰减,但它是棋盘的既有玩法表现,留待单独确认,本次不改。

证据来源:`.cache/official-scenes/<version>/scenes/.../level_<stage>.ab` 用 UnityPy(配合 tools/local-extract/aklz4.py
注册的 LZ4AK 解码器)dump 出的 Light 与 RenderSettings;以及仓库自己的 tools/local-extract/scenes.py 里 lightmap 的
RGBM 编码定义。

测试:node --test test/render/board3d-scene.test.js test/render/board3d.test.js test/render/boardart.test.js(见 PR)。
2026-10-12 23:33:58 +08:00
IceCodeNew 0295d95d08 chore: sync ammo readout with upstream dev (#552) 2026-10-12 15:03:43 +00:00
sganggs 909abee0b8 0.2.6-dev: the loadout module-card browser test accepts the content-hash segment the served manifest now puts in local-art URLs (host bandwidth layer 1); golden: unchanged 2026-10-12 21:19:41 +08:00
星闌 7db277b327 test: 修复场景资源测试在 Windows 下的路径解析 2026-10-12 20:24:31 +08:00
星闌 c919794724 fix: 禁用最后一个选策略的玩家的跳过按钮 2026-10-12 19:38:19 +08:00
sganggs 79bb26b317 0.2.6-dev: the maintainer's decisions of 2026-10-12 — the 玩法说明 pages' WebP copies are lossy at quality 90 (25.6 MB of PNG → 4.2 MB; lossless stays a GUIDE_WEBP_MODE away) and /healthz?traffic=1 answers the counters to a loopback or private-network client only (a public visitor, also one a local tunnel or proxy forwards, gets the plain report; TRUST_PROXY applies as for the WebSocket limits); golden: unchanged 2026-10-12 19:09:54 +08:00
sganggs 35f4895219 0.2.6-dev: merge the 0.2.5 release's last commit (README / DEPLOY package size) 2026-10-12 18:37:25 +08:00
sganggs cf7a940027 0.2.5: README / DEPLOY give the full bundle's built size (552 MB, about 780 MB extracted) 2026-10-12 18:36:56 +08:00
sganggs 3d5d6b380d 0.2.6-dev: merge claude/bw-l01 — host bandwidth layers 0 and 1 (no BGM download while the music is silent, WebSocket permessage-deflate, lossless WebP 玩法说明 pages, traffic counters, content-hashed asset URLs with immutable caching, brotli q5) on top of the 0.2.5 release; its note becomes DESIGN §31 in docs/history/0.2.6.md, CHANGELOG 0.2.6-dev, version 0.2.6-dev; golden: unchanged 2026-10-12 18:28:50 +08:00
sganggs 88d4b2544b 0.2.5: version 0.2.5 — package.json / package-lock.json / APP_VERSION (DEV_BUILD turns false), README release form and package sizes (the full bundle now carries the battlefield scenes), CHANGELOG 0.2.5 — 2026-10-12 in the usual sections with credits, DESIGN versions line, §30 header 2026-10-12 18:20:53 +08:00
sganggs 658f0fc392 0.2.5-dev: merge PR #490 by D-Roote — Korean: 「恢复本机对局」 reads 게임 복귀 (the PR's latest commit; its earlier commits are already connected) 2026-10-12 18:13:28 +08:00
IceCodeNew 02fd42abe5 fix(render): show exact remaining ammunition
Reference: lolink’s numeric ammunition display in https://github.com/Yilegendoflink/garrison-protocol/commit/071ed14aa27d5ebf54e57447c958f2681737403c. This implementation uses the existing PIXI HUD and exact snapshot counts; no fork code is copied.
2026-10-12 09:55:51 +00:00
sganggs 3bb7fef74c 0.2.5-dev: official scenes merge chunks that share a material / lightmap into one mesh at load (draw calls on the 3D board back within budget, e.g. act2autochess_m02 prep 22 → 13); the boss-round real-server test reads the actual random pairing instead of assuming the host on the left half; golden: unchanged 2026-10-12 17:48:31 +08:00