fix: 优化 BangDream 试炼分列渲染性能

This commit is contained in:
sunlei 2026-06-07 00:56:05 +08:00
parent 9bf2b0792e
commit bbd30ba2ea
4 changed files with 32 additions and 14 deletions

View File

@ -364,7 +364,7 @@ export interface TsuguHook {
- 已新增 `gacha-simulate-spec.spec.ts`,覆盖 10 抽网格、汇总模式、重复卡叠层、计数字样和横幅尺寸;本地生成 `gacha-simulate-spec-10-259.jpg``gacha-simulate-spec-50-259-after-cache-fix.jpg`,验证抽卡模拟两种布局模式图片输出正常。
- 抽卡模拟 50 抽 smoke 暴露资源下载短时失败会把 URL 写入无过期错误缓存,导致后续重试直接输出 `asset error`;已改为只有 HTTP 404 进入错误缓存,超时/网络抖动不污染 URL并新增 `file-cache-client.spec.ts` 覆盖瞬时失败后可再次下载、404 缓存缺失资源两种路径。
- 已新增 `render-blocks/event-stage-spec.ts`,收口试炼列表最大列高、歌曲单元格/封面/ID/难度条尺寸、试炼类型顶部文字规格和换列判断;`event-stage.ts` 与 `list-event-stage.ts` 改为消费 spec活动/歌曲选择和输出结构保持不变。
- 线上 smoke 暴露 `/查试炼 310 -m` 将所有列横向拼成一张巨大 canvas 会触发 Pod `OOMKilled exit=137`;已改为边绘制边按列输出多张 CQ 图片,不再创建最终横向巨图,普通版和 meta 版均拆成 5 张输出。
- 线上 smoke 暴露 `/查试炼 310 -m` 将所有列横向拼成一张巨大 canvas 会触发 Pod `OOMKilled exit=137`;已改为按小批次绘制 stage、边分列边输出多张 CQ 图片,不再创建最终横向巨图,普通版和 meta 版均拆成 5 张输出,同时避免完全串行导致冷缓存首条命令耗时过长
- 已新增 `event-stage-spec.spec.ts`,覆盖试炼歌曲行尺寸、类型顶部文字规格、换列判断和按列高拆分算法;本地生成 `event-stage-split-310*.jpg`、`event-stage-split-310-meta*.jpg`,验证 `/查试炼 310``/查试炼 310 -m` 图片输出正常。
- smoke/Jenkins/远程调试卡点继续按已固化规则处理同一卡点第二次尝试前必须改变可验证变量Jenkins 查询 URL 含方括号时用 `curl -g` 或改查 Jenkins home线上图片 smoke 必须查询 `commandId`、拉回图片、展示图片、查日志并清理本轮临时目录PowerShell 双引号 here-string 中不要写 JS `${...}` 模板字面量,避免被 PowerShell 提前插值smoke 没有真实图片落盘时必须失败。

View File

@ -13,7 +13,10 @@ import {
import { outputEasyImages } from '@/qqbot/plugins/bangDream/tsugu/canvas/output';
import { drawDataBlock } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/data-block';
import { stackImage } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/image-stack';
import { shouldStartNewEventStageColumn } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec';
import {
getEventStageStageBatchSize,
shouldStartNewEventStageColumn,
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec';
import { Canvas } from 'skia-canvas';
/**
@ -58,6 +61,7 @@ export async function drawEventStage(
let currentColumn: Canvas[] = [];
let currentHeight = 0;
let pageIndex = 0;
const stageBatchSize = getEventStageStageBatchSize();
//绘制活动stage每个stage一个图片
/**
@ -83,19 +87,23 @@ export async function drawEventStage(
pageIndex += 1;
}
for (const stage of stageList) {
const stageImage = await drawStageSong(stage);
if (
shouldStartNewEventStageColumn(
currentHeight,
stageImage.height,
currentColumn.length,
)
) {
await flushColumn();
for (let start = 0; start < stageList.length; start += stageBatchSize) {
const stageImages = await Promise.all(
stageList.slice(start, start + stageBatchSize).map(drawStageSong),
);
for (const stageImage of stageImages) {
if (
shouldStartNewEventStageColumn(
currentHeight,
stageImage.height,
currentColumn.length,
)
) {
await flushColumn();
}
currentColumn.push(stageImage);
currentHeight += stageImage.height;
}
currentColumn.push(stageImage);
currentHeight += stageImage.height;
}
await flushColumn();

View File

@ -5,6 +5,7 @@ export interface EventStageCanvasLike {
export const BANGDREAM_EVENT_STAGE_SPEC = {
list: {
maxColumnHeight: 6000,
stageBatchSize: 8,
},
songRow: {
difficultyHeightScale: 10,
@ -66,6 +67,13 @@ export function getEventStageSongRowSize(): { height: number; width: number } {
};
}
/**
* stage
*/
export function getEventStageStageBatchSize(): number {
return BANGDREAM_EVENT_STAGE_SPEC.list.stageBatchSize;
}
/**
* stage
*

View File

@ -4,6 +4,7 @@ import {
getEventStageSongCellWidth,
getEventStageSongJacketHeight,
getEventStageSongRowSize,
getEventStageStageBatchSize,
shouldStartNewEventStageColumn,
splitEventStageImagesByColumnHeight,
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec';
@ -23,6 +24,7 @@ describe('BangDream event stage spec', () => {
expect(BANGDREAM_EVENT_STAGE_SPEC.typeTop.fontSize).toBe(25);
expect(BANGDREAM_EVENT_STAGE_SPEC.typeTop.strokeWidth).toBe(4.5);
expect(BANGDREAM_EVENT_STAGE_SPEC.list.maxColumnHeight).toBe(6000);
expect(getEventStageStageBatchSize()).toBe(8);
});
it('splits stage images by max column height', () => {