refactor: 收口 BangDream 渲染主题资源
This commit is contained in:
parent
9f0293a977
commit
31e0da78cf
@ -339,6 +339,13 @@ export interface TsuguHook {
|
|||||||
- 关键图片命令输出非空,尺寸在既有范围。
|
- 关键图片命令输出非空,尺寸在既有范围。
|
||||||
- 视觉 token 修改只改 theme/spec 文件。
|
- 视觉 token 修改只改 theme/spec 文件。
|
||||||
|
|
||||||
|
当前进度:
|
||||||
|
|
||||||
|
- 已新增 `render-blocks/theme.ts`,先收口公共文字颜色、分割线颜色、简易背景色、图表背景/文字色和默认字体名。
|
||||||
|
- 已新增 `render-blocks/layout-spec.ts`,统一横向/纵向虚线分割规格,歌曲列表、活动列表、活动详情和通用列表框架不再重复维护分割线宽高/颜色。
|
||||||
|
- 已新增 `runtime/asset-manifest.ts`,收口本地 `BG`、`Card`、`Skill`、`SongChart`、字体和标题资源路径;`canvas/text.ts`、`canvas/rect.ts`、`canvas/output.ts`、`canvas/background.ts`、`card-art.ts`、`list-rarity.ts`、`skill-text.ts`、`title.ts`、`song-chart-preview.ts` 已改走 manifest。
|
||||||
|
- 已生成查曲、查活动和查谱面 smoke 图片,验证 theme/spec/manifest 第一段迁移后本地图片输出非空,谱面预览资源路径未断。
|
||||||
|
|
||||||
### Phase 6:策略 policy 和时间/档线规则
|
### Phase 6:策略 policy 和时间/档线规则
|
||||||
|
|
||||||
目标:服务器优先级、国服预估、档位、时区和活动状态从工具函数变成可测试规则。
|
目标:服务器优先级、国服预估、档位、时区和活动状态从工具函数变成可测试规则。
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { createBlurredTrianglePattern } from '@/qqbot/plugins/bangDream/tsugu/ca
|
|||||||
import { scatterImages } from '@/qqbot/plugins/bangDream/tsugu/canvas/background-star-scatter';
|
import { scatterImages } from '@/qqbot/plugins/bangDream/tsugu/canvas/background-star-scatter';
|
||||||
import { drawTextOnCanvas } from '@/qqbot/plugins/bangDream/tsugu/canvas/background-text';
|
import { drawTextOnCanvas } from '@/qqbot/plugins/bangDream/tsugu/canvas/background-text';
|
||||||
import { loadImage, Image, Canvas } from 'skia-canvas';
|
import { loadImage, Image, Canvas } from 'skia-canvas';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
interface BackgroundOptions {
|
interface BackgroundOptions {
|
||||||
image?: Image | Canvas | any;
|
image?: Image | Canvas | any;
|
||||||
@ -118,14 +118,10 @@ let defaultBGTexture: Image;
|
|||||||
* 在底层绘图工具层中加载图片Once。
|
* 在底层绘图工具层中加载图片Once。
|
||||||
*/
|
*/
|
||||||
async function loadImageOnce() {
|
async function loadImageOnce() {
|
||||||
star.push(
|
star.push(await loadImageFromPath(getBangDreamAssetPath('backgroundStar1')));
|
||||||
await loadImageFromPath(path.join(assetsRootPath, '/BG/star1.png')),
|
star.push(await loadImageFromPath(getBangDreamAssetPath('backgroundStar2')));
|
||||||
);
|
|
||||||
star.push(
|
|
||||||
await loadImageFromPath(path.join(assetsRootPath, '/BG/star2.png')),
|
|
||||||
);
|
|
||||||
defaultBGTexture = await loadImageFromPath(
|
defaultBGTexture = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/BG/bg_object_big.png'),
|
getBangDreamAssetPath('backgroundObjectBig'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
loadImageOnce();
|
loadImageOnce();
|
||||||
@ -136,7 +132,7 @@ loadImageOnce();
|
|||||||
* @param options1 - options1参数。
|
* @param options1 - options1参数。
|
||||||
*/
|
*/
|
||||||
export async function createEasyBackground({ width, height }) {
|
export async function createEasyBackground({ width, height }) {
|
||||||
const bgColor = '#fef3ef';
|
const bgColor = BANGDREAM_RENDER_THEME.color.backgroundEasy;
|
||||||
const canvas: Canvas = new Canvas(width, height);
|
const canvas: Canvas = new Canvas(width, height);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = bgColor;
|
ctx.fillStyle = bgColor;
|
||||||
|
|||||||
@ -4,9 +4,8 @@ import {
|
|||||||
createEasyBackground,
|
createEasyBackground,
|
||||||
createImageBackground,
|
createImageBackground,
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/canvas/background';
|
} from '@/qqbot/plugins/bangDream/tsugu/canvas/background';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
|
||||||
let BGDefaultImage: Image;
|
let BGDefaultImage: Image;
|
||||||
/**
|
/**
|
||||||
@ -14,7 +13,7 @@ let BGDefaultImage: Image;
|
|||||||
*/
|
*/
|
||||||
async function loadImageOnce() {
|
async function loadImageOnce() {
|
||||||
BGDefaultImage = await loadImageFromPath(
|
BGDefaultImage = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/BG/live.png'),
|
getBangDreamAssetPath('backgroundLive'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
loadImageOnce();
|
loadImageOnce();
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { Canvas, FontLibrary } from 'skia-canvas';
|
import { Canvas, FontLibrary } from 'skia-canvas';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import { getTextWidth } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { getTextWidth } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
FontLibrary.use('old', [`${assetsRootPath}/Fonts/old.ttf`]);
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
|
FontLibrary.use('old', [getBangDreamAssetPath('fontOld')]);
|
||||||
|
|
||||||
interface RoundedRect {
|
interface RoundedRect {
|
||||||
width: number;
|
width: number;
|
||||||
@ -24,7 +26,7 @@ export function drawRoundedRect({
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
radius = 25,
|
radius = 25,
|
||||||
color = '#ffffff',
|
color = BANGDREAM_RENDER_THEME.color.surface,
|
||||||
opacity = 0.9,
|
opacity = 0.9,
|
||||||
strokeColor = '#bbbbbb',
|
strokeColor = '#bbbbbb',
|
||||||
strokeWidth = 0,
|
strokeWidth = 0,
|
||||||
@ -119,14 +121,14 @@ interface RoundedRectWithText {
|
|||||||
*/
|
*/
|
||||||
export function drawRoundedRectWithText({
|
export function drawRoundedRectWithText({
|
||||||
text,
|
text,
|
||||||
font = 'old',
|
font = BANGDREAM_RENDER_THEME.font.body,
|
||||||
textColor = '#ffffff',
|
textColor = BANGDREAM_RENDER_THEME.color.surface,
|
||||||
textSize,
|
textSize,
|
||||||
textAlign = 'center',
|
textAlign = 'center',
|
||||||
height = (textSize * 4) / 3,
|
height = (textSize * 4) / 3,
|
||||||
width = getTextWidth(text, textSize, font) + height,
|
width = getTextWidth(text, textSize, font) + height,
|
||||||
radius = height / 2,
|
radius = height / 2,
|
||||||
color = '#5b5b5b',
|
color = BANGDREAM_RENDER_THEME.color.labelBackground,
|
||||||
opacity = 1,
|
opacity = 1,
|
||||||
strokeColor = color,
|
strokeColor = color,
|
||||||
strokeWidth = 0,
|
strokeWidth = 0,
|
||||||
@ -144,7 +146,7 @@ export function drawRoundedRectWithText({
|
|||||||
|
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
ctx.textBaseline = 'alphabetic';
|
ctx.textBaseline = 'alphabetic';
|
||||||
ctx.font = `${textSize}px old,Microsoft Yahei`;
|
ctx.font = `${textSize}px ${font},${BANGDREAM_RENDER_THEME.font.fallback}`;
|
||||||
|
|
||||||
let x = 0,
|
let x = 0,
|
||||||
y = 0;
|
y = 0;
|
||||||
|
|||||||
@ -4,10 +4,12 @@ import {
|
|||||||
Canvas,
|
Canvas,
|
||||||
CanvasRenderingContext2D,
|
CanvasRenderingContext2D,
|
||||||
} from 'skia-canvas';
|
} from 'skia-canvas';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
FontLibrary.use('old', [`${assetsRootPath}/Fonts/old.ttf`]);
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
|
FontLibrary.use('old', [getBangDreamAssetPath('fontOld')]);
|
||||||
FontLibrary.use('FangZhengHeiTi', [
|
FontLibrary.use('FangZhengHeiTi', [
|
||||||
`${assetsRootPath}/Fonts/FangZhengHeiTi_GBK.ttf`,
|
getBangDreamAssetPath('fontFangZhengHeiTi'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
interface WrapTextOptions {
|
interface WrapTextOptions {
|
||||||
@ -31,8 +33,8 @@ export function drawText({
|
|||||||
textSize = 40,
|
textSize = 40,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
lineHeight = (textSize * 4) / 3,
|
lineHeight = (textSize * 4) / 3,
|
||||||
color = '#505050',
|
color = BANGDREAM_RENDER_THEME.color.primaryText,
|
||||||
font = 'old',
|
font = BANGDREAM_RENDER_THEME.font.body,
|
||||||
}: WrapTextOptions): Canvas {
|
}: WrapTextOptions): Canvas {
|
||||||
const wrappedTextData = wrapText({ text, maxWidth, lineHeight, textSize });
|
const wrappedTextData = wrapText({ text, maxWidth, lineHeight, textSize });
|
||||||
let canvas: Canvas;
|
let canvas: Canvas;
|
||||||
@ -131,8 +133,8 @@ export function drawTextWithImages({
|
|||||||
lineHeight = (textSize * 4) / 3,
|
lineHeight = (textSize * 4) / 3,
|
||||||
content,
|
content,
|
||||||
spacing = textSize / 3,
|
spacing = textSize / 3,
|
||||||
color = '#505050',
|
color = BANGDREAM_RENDER_THEME.color.primaryText,
|
||||||
font = 'old',
|
font = BANGDREAM_RENDER_THEME.font.body,
|
||||||
}: TextWithImagesOptions) {
|
}: TextWithImagesOptions) {
|
||||||
const wrappedTextData = wrapTextWithImages({
|
const wrappedTextData = wrapTextWithImages({
|
||||||
textSize,
|
textSize,
|
||||||
@ -305,5 +307,5 @@ export const setFontStyle = function (
|
|||||||
font: string,
|
font: string,
|
||||||
) {
|
) {
|
||||||
//设置字体大小
|
//设置字体大小
|
||||||
ctx.font = textSize + 'px ' + font + ',Microsoft Yahei';
|
ctx.font = `${textSize}px ${font},${BANGDREAM_RENDER_THEME.font.fallback}`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,18 +36,12 @@ import {
|
|||||||
drawSongListInList,
|
drawSongListInList,
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-song';
|
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-song';
|
||||||
import { drawDottedLine } from '@/qqbot/plugins/bangDream/tsugu/canvas/dotted-line';
|
import { drawDottedLine } from '@/qqbot/plugins/bangDream/tsugu/canvas/dotted-line';
|
||||||
|
import { createHorizontalSeparatorSpec } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/layout-spec';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
const songSeparatorLine = drawDottedLine({
|
const songSeparatorLine = drawDottedLine(
|
||||||
width: 800,
|
createHorizontalSeparatorSpec({ height: 10 }),
|
||||||
height: 10,
|
);
|
||||||
startX: 5,
|
|
||||||
startY: 5,
|
|
||||||
endX: 795,
|
|
||||||
endY: 5,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在QQBot 图片视图层中绘制歌曲列表数据块。
|
* 在QQBot 图片视图层中绘制歌曲列表数据块。
|
||||||
@ -393,7 +387,7 @@ export async function drawEventDetail(
|
|||||||
const eventBannerImage = await event.getBannerImage();
|
const eventBannerImage = await event.getBannerImage();
|
||||||
const eventBannerImageCanvas = drawBannerImageCanvas(eventBannerImage);
|
const eventBannerImageCanvas = drawBannerImageCanvas(eventBannerImage);
|
||||||
list.push(eventBannerImageCanvas);
|
list.push(eventBannerImageCanvas);
|
||||||
list.push(new Canvas(800, 30));
|
list.push(new Canvas(BANGDREAM_RENDER_THEME.layout.contentWidth, 30));
|
||||||
|
|
||||||
//标题
|
//标题
|
||||||
list.push(
|
list.push(
|
||||||
|
|||||||
@ -38,22 +38,15 @@ import { statConfig } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-s
|
|||||||
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
import { createTsuguEntityMatcher } from '@/qqbot/plugins/bangDream/tsugu/search/entity-list-matcher';
|
import { createTsuguEntityMatcher } from '@/qqbot/plugins/bangDream/tsugu/search/entity-list-matcher';
|
||||||
import { eventRepository } from '@/qqbot/plugins/bangDream/tsugu/models/event-repository';
|
import { eventRepository } from '@/qqbot/plugins/bangDream/tsugu/models/event-repository';
|
||||||
|
import { createVerticalSeparatorSpec } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/layout-spec';
|
||||||
|
|
||||||
const maxHeight = 7000;
|
const maxHeight = 7000;
|
||||||
const maxColumns = 7;
|
const maxColumns = 7;
|
||||||
|
|
||||||
//表格用默认虚线
|
//表格用默认虚线
|
||||||
export const line2: Canvas = drawDottedLine({
|
export const line2: Canvas = drawDottedLine(
|
||||||
width: 30,
|
createVerticalSeparatorSpec(7000, { startX: 5 }),
|
||||||
height: 7000,
|
);
|
||||||
startX: 5,
|
|
||||||
startY: 0,
|
|
||||||
endX: 15,
|
|
||||||
endY: 6995,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在QQBot 图片视图层中绘制活动列表。
|
* 在QQBot 图片视图层中绘制活动列表。
|
||||||
|
|||||||
@ -15,32 +15,16 @@ import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/con
|
|||||||
import { drawSongDetail } from './song-detail';
|
import { drawSongDetail } from './song-detail';
|
||||||
import { createTsuguEntityMatcher } from '@/qqbot/plugins/bangDream/tsugu/search/entity-list-matcher';
|
import { createTsuguEntityMatcher } from '@/qqbot/plugins/bangDream/tsugu/search/entity-list-matcher';
|
||||||
import { songRepository } from '@/qqbot/plugins/bangDream/tsugu/models/song-repository';
|
import { songRepository } from '@/qqbot/plugins/bangDream/tsugu/models/song-repository';
|
||||||
|
import {
|
||||||
|
createHorizontalSeparatorSpec,
|
||||||
|
createVerticalSeparatorSpec,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/layout-spec';
|
||||||
|
|
||||||
// 紧凑化虚线分割
|
// 紧凑化虚线分割
|
||||||
const line = drawDottedLine({
|
const line = drawDottedLine(createHorizontalSeparatorSpec({ height: 10 }));
|
||||||
width: 800,
|
|
||||||
height: 10,
|
|
||||||
startX: 5,
|
|
||||||
startY: 5,
|
|
||||||
endX: 795,
|
|
||||||
endY: 5,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
//表格用默认竖向虚线
|
//表格用默认竖向虚线
|
||||||
const line2: Canvas = drawDottedLine({
|
const line2: Canvas = drawDottedLine(createVerticalSeparatorSpec(6000));
|
||||||
width: 30,
|
|
||||||
height: 6000,
|
|
||||||
startX: 10,
|
|
||||||
startY: 0,
|
|
||||||
endX: 15,
|
|
||||||
endY: 5990,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在QQBot 图片视图层中绘制歌曲列表。
|
* 在QQBot 图片视图层中绘制歌曲列表。
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import { setFontStyle } from '@/qqbot/plugins/bangDream/tsugu/canvas/text';
|
import { setFontStyle } from '@/qqbot/plugins/bangDream/tsugu/canvas/text';
|
||||||
import { Band } from '@/qqbot/plugins/bangDream/tsugu/models/band';
|
import { Band } from '@/qqbot/plugins/bangDream/tsugu/models/band';
|
||||||
import { Attribute } from '@/qqbot/plugins/bangDream/tsugu/models/attribute';
|
import { Attribute } from '@/qqbot/plugins/bangDream/tsugu/models/attribute';
|
||||||
@ -6,10 +5,11 @@ import { Card } from '@/qqbot/plugins/bangDream/tsugu/models/card';
|
|||||||
import { Image, Canvas, loadImage } from 'skia-canvas';
|
import { Image, Canvas, loadImage } from 'skia-canvas';
|
||||||
import { downloadFileCache } from '@/qqbot/plugins/bangDream/tsugu/data-clients/asset-cache-client';
|
import { downloadFileCache } from '@/qqbot/plugins/bangDream/tsugu/data-clients/asset-cache-client';
|
||||||
import { drawCardIconSkill } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/skill-text';
|
import { drawCardIconSkill } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/skill-text';
|
||||||
import * as path from 'path';
|
|
||||||
import { Skill } from '@/qqbot/plugins/bangDream/tsugu/models/skill';
|
import { Skill } from '@/qqbot/plugins/bangDream/tsugu/models/skill';
|
||||||
import { bestdoriUrl } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
import { bestdoriUrl } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
const cardTypeIconList: { [type: string]: Image } = {};
|
const cardTypeIconList: { [type: string]: Image } = {};
|
||||||
const starList: { [type: string]: Image } = {};
|
const starList: { [type: string]: Image } = {};
|
||||||
@ -20,25 +20,23 @@ let limitBreakIcon: Image;
|
|||||||
*/
|
*/
|
||||||
async function loadImageOnce() {
|
async function loadImageOnce() {
|
||||||
cardTypeIconList.limited = await loadImageFromPath(
|
cardTypeIconList.limited = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/L.png'),
|
getBangDreamAssetPath('cardLimited'),
|
||||||
);
|
);
|
||||||
cardTypeIconList.dreamfes = await loadImageFromPath(
|
cardTypeIconList.dreamfes = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/D.png'),
|
getBangDreamAssetPath('cardDreamfes'),
|
||||||
);
|
);
|
||||||
cardTypeIconList.kirafes = await loadImageFromPath(
|
cardTypeIconList.kirafes = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/K.png'),
|
getBangDreamAssetPath('cardKirafes'),
|
||||||
);
|
);
|
||||||
cardTypeIconList.birthday = await loadImageFromPath(
|
cardTypeIconList.birthday = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/B.png'),
|
getBangDreamAssetPath('cardBirthday'),
|
||||||
);
|
|
||||||
starList.normal = await loadImageFromPath(
|
|
||||||
path.join(assetsRootPath, '/Card/star.png'),
|
|
||||||
);
|
);
|
||||||
|
starList.normal = await loadImageFromPath(getBangDreamAssetPath('cardStar'));
|
||||||
starList.trained = await loadImageFromPath(
|
starList.trained = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/star_trained.png'),
|
getBangDreamAssetPath('cardStarTrained'),
|
||||||
);
|
);
|
||||||
limitBreakIcon = await loadImageFromPath(
|
limitBreakIcon = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/limitBreakRank.png'),
|
getBangDreamAssetPath('cardLimitBreakRank'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,17 +134,17 @@ export async function drawCardIcon({
|
|||||||
if (cardIdVisible) {
|
if (cardIdVisible) {
|
||||||
ctx.textAlign = 'start';
|
ctx.textAlign = 'start';
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
setFontStyle(ctx, 30, 'old');
|
setFontStyle(ctx, 30, BANGDREAM_RENDER_THEME.font.body);
|
||||||
ctx.fillStyle = '#a7a7a7';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.mutedText;
|
||||||
ctx.fillText(`ID:${card.cardId}`, 4, 195);
|
ctx.fillText(`ID:${card.cardId}`, 4, 195);
|
||||||
}
|
}
|
||||||
//如果显示技能类型,在右上显示
|
//如果显示技能类型,在右上显示
|
||||||
if (skillLevel != undefined) {
|
if (skillLevel != undefined) {
|
||||||
ctx.fillStyle = '#ff0000';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.skillLevelBackground;
|
||||||
ctx.fillRect(138, 91, 35, 39);
|
ctx.fillRect(138, 91, 35, 39);
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.surface;
|
||||||
ctx.textAlign = 'center';
|
ctx.textAlign = 'center';
|
||||||
setFontStyle(ctx, 35, 'old');
|
setFontStyle(ctx, 35, BANGDREAM_RENDER_THEME.font.body);
|
||||||
ctx.fillText(skillLevel.toString(), 155.5, 107.5);
|
ctx.fillText(skillLevel.toString(), 155.5, 107.5);
|
||||||
}
|
}
|
||||||
//如果显示技能类型,在右上显示
|
//如果显示技能类型,在右上显示
|
||||||
@ -169,8 +167,8 @@ export async function drawCardIcon({
|
|||||||
ctx.drawImage(bandIcon, 0, 0, 45, 45);
|
ctx.drawImage(bandIcon, 0, 0, 45, 45);
|
||||||
if (limitBreakRank != 0) {
|
if (limitBreakRank != 0) {
|
||||||
ctx.drawImage(limitBreakIcon, 137, 51, 39, 39);
|
ctx.drawImage(limitBreakIcon, 137, 51, 39, 39);
|
||||||
setFontStyle(ctx, 25, 'old');
|
setFontStyle(ctx, 25, BANGDREAM_RENDER_THEME.font.body);
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.surface;
|
||||||
ctx.textAlign = 'center';
|
ctx.textAlign = 'center';
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
ctx.fillText(limitBreakRank.toString(), 155, 70);
|
ctx.fillText(limitBreakRank.toString(), 155, 70);
|
||||||
|
|||||||
@ -47,30 +47,22 @@ import {
|
|||||||
} from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
} from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
import { Canvas, Image } from 'skia-canvas';
|
import { Canvas, Image } from 'skia-canvas';
|
||||||
import { Band } from '@/qqbot/plugins/bangDream/tsugu/models/band';
|
import { Band } from '@/qqbot/plugins/bangDream/tsugu/models/band';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
import { createHorizontalSeparatorSpec } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/layout-spec';
|
||||||
|
|
||||||
const songDetailSeparator = drawDottedLine({
|
const songDetailSeparator = drawDottedLine(
|
||||||
width: 365,
|
createHorizontalSeparatorSpec({
|
||||||
height: 20,
|
width: 365,
|
||||||
startX: 5,
|
height: 20,
|
||||||
startY: 10,
|
endX: 360,
|
||||||
endX: 360,
|
}),
|
||||||
endY: 10,
|
);
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
const songMetaSeparator = drawDottedLine({
|
const songMetaSeparator = drawDottedLine(
|
||||||
width: 800,
|
createHorizontalSeparatorSpec({
|
||||||
height: 10,
|
height: 10,
|
||||||
startX: 5,
|
}),
|
||||||
startY: 5,
|
);
|
||||||
endX: 795,
|
|
||||||
endY: 5,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在图片布局层中绘制横幅Info块。
|
* 在图片布局层中绘制横幅Info块。
|
||||||
@ -327,7 +319,7 @@ export async function drawCharacterHalfBlock(
|
|||||||
await character.initFull(false);
|
await character.initFull(false);
|
||||||
const color = character.colorCode
|
const color = character.colorCode
|
||||||
? character.colorCode.toLowerCase()
|
? character.colorCode.toLowerCase()
|
||||||
: '#ffffff';
|
: BANGDREAM_RENDER_THEME.color.surface;
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
drawRoundedRect({
|
drawRoundedRect({
|
||||||
width,
|
width,
|
||||||
@ -382,14 +374,14 @@ export async function drawCharacterHalfBlock(
|
|||||||
const nameTextImage = drawText({
|
const nameTextImage = drawText({
|
||||||
text: character.characterName[server],
|
text: character.characterName[server],
|
||||||
textSize: 40,
|
textSize: 40,
|
||||||
color: '#ffffff',
|
color: BANGDREAM_RENDER_THEME.color.surface,
|
||||||
maxWidth: width,
|
maxWidth: width,
|
||||||
});
|
});
|
||||||
list.push(drawImageListCenter([nameTextImage], width));
|
list.push(drawImageListCenter([nameTextImage], width));
|
||||||
const idTextImage = drawText({
|
const idTextImage = drawText({
|
||||||
text: `ID: ${character.characterId}`,
|
text: `ID: ${character.characterId}`,
|
||||||
textSize: 30,
|
textSize: 30,
|
||||||
color: '#ffffff',
|
color: BANGDREAM_RENDER_THEME.color.surface,
|
||||||
maxWidth: width,
|
maxWidth: width,
|
||||||
});
|
});
|
||||||
list.push(drawImageListCenter([idTextImage], width));
|
list.push(drawImageListCenter([idTextImage], width));
|
||||||
@ -409,13 +401,13 @@ export async function drawPlayerDetailBlockWithIllustration(
|
|||||||
const list: Array<Canvas | Image> = [];
|
const list: Array<Canvas | Image> = [];
|
||||||
const playerText = drawText({
|
const playerText = drawText({
|
||||||
text: player.profile.userName,
|
text: player.profile.userName,
|
||||||
maxWidth: 800,
|
maxWidth: BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
textSize: 75,
|
textSize: 75,
|
||||||
});
|
});
|
||||||
list.push(drawImageListCenter([playerText]));
|
list.push(drawImageListCenter([playerText]));
|
||||||
const levelText = drawText({
|
const levelText = drawText({
|
||||||
text: `等级 ${player.profile.rank}`,
|
text: `等级 ${player.profile.rank}`,
|
||||||
maxWidth: 800,
|
maxWidth: BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
textSize: 35,
|
textSize: 35,
|
||||||
});
|
});
|
||||||
list.push(drawImageListCenter([levelText]));
|
list.push(drawImageListCenter([levelText]));
|
||||||
@ -436,7 +428,7 @@ export async function drawPlayerDetailBlockWithIllustration(
|
|||||||
|
|
||||||
const introductionText = drawText({
|
const introductionText = drawText({
|
||||||
text: player.profile.introduction,
|
text: player.profile.introduction,
|
||||||
maxWidth: 800,
|
maxWidth: BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
textSize: 35,
|
textSize: 35,
|
||||||
});
|
});
|
||||||
list.push(drawImageListCenter([introductionText]));
|
list.push(drawImageListCenter([introductionText]));
|
||||||
@ -447,7 +439,7 @@ export async function drawPlayerDetailBlockWithIllustration(
|
|||||||
: 'ID未公开';
|
: 'ID未公开';
|
||||||
const idText = drawTextWithImages({
|
const idText = drawTextWithImages({
|
||||||
content: [await getIcon(player.server), userId],
|
content: [await getIcon(player.server), userId],
|
||||||
maxWidth: 800,
|
maxWidth: BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
textSize: 35,
|
textSize: 35,
|
||||||
});
|
});
|
||||||
list.push(drawImageListCenter([idText]));
|
list.push(drawImageListCenter([idText]));
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
|
interface SeparatorSpecOptions {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
startX?: number;
|
||||||
|
endX?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建横向虚线分割规格。
|
||||||
|
*
|
||||||
|
* @param options - 分割线宽高和横向端点。
|
||||||
|
*/
|
||||||
|
export function createHorizontalSeparatorSpec({
|
||||||
|
width = BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
|
height = 30,
|
||||||
|
startX = 5,
|
||||||
|
endX = width - 5,
|
||||||
|
}: SeparatorSpecOptions = {}) {
|
||||||
|
const y = height / 2;
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
startX,
|
||||||
|
startY: y,
|
||||||
|
endX,
|
||||||
|
endY: y,
|
||||||
|
radius: 2,
|
||||||
|
gap: 10,
|
||||||
|
color: BANGDREAM_RENDER_THEME.color.separator,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建纵向虚线分割规格。
|
||||||
|
*
|
||||||
|
* @param height - 分割线高度。
|
||||||
|
* @param options - 纵向端点配置。
|
||||||
|
*/
|
||||||
|
export function createVerticalSeparatorSpec(
|
||||||
|
height: number,
|
||||||
|
options: Pick<SeparatorSpecOptions, 'startX' | 'endX'> = {},
|
||||||
|
) {
|
||||||
|
const { startX = 10, endX = 15 } = options;
|
||||||
|
return {
|
||||||
|
width: 30,
|
||||||
|
height,
|
||||||
|
startX,
|
||||||
|
startY: 0,
|
||||||
|
endX,
|
||||||
|
endY: height - 10,
|
||||||
|
radius: 2,
|
||||||
|
gap: 10,
|
||||||
|
color: BANGDREAM_RENDER_THEME.color.separator,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -12,19 +12,14 @@ import {
|
|||||||
} from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
} from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
import { stackImageHorizontal } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/image-stack';
|
import { stackImageHorizontal } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/image-stack';
|
||||||
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
import {
|
||||||
|
createHorizontalSeparatorSpec,
|
||||||
|
createVerticalSeparatorSpec,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/layout-spec';
|
||||||
|
|
||||||
//表格用默认虚线
|
//表格用默认虚线
|
||||||
export const line: Canvas = drawDottedLine({
|
export const line: Canvas = drawDottedLine(createHorizontalSeparatorSpec());
|
||||||
width: 800,
|
|
||||||
height: 30,
|
|
||||||
startX: 5,
|
|
||||||
startY: 15,
|
|
||||||
endX: 795,
|
|
||||||
endY: 15,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
|
|
||||||
interface ListOptions {
|
interface ListOptions {
|
||||||
key?: string;
|
key?: string;
|
||||||
@ -51,8 +46,8 @@ export function drawList({
|
|||||||
textSize = 40,
|
textSize = 40,
|
||||||
lineHeight = textSize * 1.5,
|
lineHeight = textSize * 1.5,
|
||||||
spacing = textSize / 3,
|
spacing = textSize / 3,
|
||||||
color = '#505050',
|
color = BANGDREAM_RENDER_THEME.color.primaryText,
|
||||||
maxWidth = 800,
|
maxWidth = BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
}: ListOptions): Canvas {
|
}: ListOptions): Canvas {
|
||||||
const xmax = maxWidth - 40;
|
const xmax = maxWidth - 40;
|
||||||
const keyImage = drawRoundedRectWithText({
|
const keyImage = drawRoundedRectWithText({
|
||||||
@ -76,14 +71,21 @@ export function drawList({
|
|||||||
textImage = new Canvas(0, 0);
|
textImage = new Canvas(0, 0);
|
||||||
}
|
}
|
||||||
if (key == undefined) {
|
if (key == undefined) {
|
||||||
return stackImageHorizontal([new Canvas(20, 1), textImage]);
|
return stackImageHorizontal([
|
||||||
|
new Canvas(BANGDREAM_RENDER_THEME.layout.listIndent, 1),
|
||||||
|
textImage,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
const ymax = textImage.height + keyImage.height + 10;
|
const ymax = textImage.height + keyImage.height + 10;
|
||||||
const canvas = new Canvas(maxWidth, ymax);
|
const canvas = new Canvas(maxWidth, ymax);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.drawImage(keyImage, 0, 0);
|
ctx.drawImage(keyImage, 0, 0);
|
||||||
if (textImage.height != 0) {
|
if (textImage.height != 0) {
|
||||||
ctx.drawImage(textImage, 20, keyImage.height + 10);
|
ctx.drawImage(
|
||||||
|
textImage,
|
||||||
|
BANGDREAM_RENDER_THEME.layout.listIndent,
|
||||||
|
keyImage.height + 10,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
@ -107,7 +109,9 @@ export function drawTipsInList({
|
|||||||
lineHeight = textSize * 1.5,
|
lineHeight = textSize * 1.5,
|
||||||
spacing = textSize / 3,
|
spacing = textSize / 3,
|
||||||
}: tipsOptions) {
|
}: tipsOptions) {
|
||||||
const xmax = 760;
|
const xmax =
|
||||||
|
BANGDREAM_RENDER_THEME.layout.contentWidth -
|
||||||
|
BANGDREAM_RENDER_THEME.layout.listIndent * 2;
|
||||||
let textImage: Canvas;
|
let textImage: Canvas;
|
||||||
if (typeof text == 'string') {
|
if (typeof text == 'string') {
|
||||||
textImage = drawText({ text, textSize, maxWidth: xmax, lineHeight });
|
textImage = drawText({ text, textSize, maxWidth: xmax, lineHeight });
|
||||||
@ -122,11 +126,19 @@ export function drawTipsInList({
|
|||||||
} else {
|
} else {
|
||||||
textImage = new Canvas(1, 1);
|
textImage = new Canvas(1, 1);
|
||||||
}
|
}
|
||||||
const canvas = new Canvas(800, textImage.height + 10);
|
const canvas = new Canvas(
|
||||||
|
BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
|
textImage.height + 10,
|
||||||
|
);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = '#f1f1f1';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.subtlePanel;
|
||||||
ctx.fillRect(0, 10, 800, textImage.height);
|
ctx.fillRect(
|
||||||
ctx.drawImage(textImage, 20, 10);
|
0,
|
||||||
|
10,
|
||||||
|
BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
|
textImage.height,
|
||||||
|
);
|
||||||
|
ctx.drawImage(textImage, BANGDREAM_RENDER_THEME.layout.listIndent, 10);
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +154,7 @@ export async function drawListByServerList(
|
|||||||
content: Array<string | null>,
|
content: Array<string | null>,
|
||||||
key?: string,
|
key?: string,
|
||||||
serverList: Server[] = globalDefaultServer,
|
serverList: Server[] = globalDefaultServer,
|
||||||
maxWidth = 800,
|
maxWidth: number = BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
) {
|
) {
|
||||||
const tempcontent: Array<string | Image | Canvas> = [];
|
const tempcontent: Array<string | Image | Canvas> = [];
|
||||||
|
|
||||||
@ -211,13 +223,16 @@ export function drawListMerge(imageList: Array<Canvas | Image>): Canvas {
|
|||||||
maxHeight = element.height;
|
maxHeight = element.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const canvas = new Canvas(800, maxHeight);
|
const canvas = new Canvas(
|
||||||
|
BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
|
maxHeight,
|
||||||
|
);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
let x = 0;
|
let x = 0;
|
||||||
for (let i = 0; i < imageList.length; i++) {
|
for (let i = 0; i < imageList.length; i++) {
|
||||||
const element = imageList[i];
|
const element = imageList[i];
|
||||||
ctx.drawImage(element, x, 0);
|
ctx.drawImage(element, x, 0);
|
||||||
x += 800 / imageList.length;
|
x += BANGDREAM_RENDER_THEME.layout.contentWidth / imageList.length;
|
||||||
}
|
}
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
@ -232,7 +247,7 @@ export function drawListMerge(imageList: Array<Canvas | Image>): Canvas {
|
|||||||
*/
|
*/
|
||||||
export function drawImageListCenter(
|
export function drawImageListCenter(
|
||||||
imageList: Array<Canvas | Image>,
|
imageList: Array<Canvas | Image>,
|
||||||
maxWidth = 800,
|
maxWidth: number = BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
): Canvas {
|
): Canvas {
|
||||||
interface imageLine {
|
interface imageLine {
|
||||||
imageList: Array<Canvas | Image>;
|
imageList: Array<Canvas | Image>;
|
||||||
@ -320,10 +335,14 @@ export function drawListWithLine(textImageList: Array<Canvas | Image>): Canvas {
|
|||||||
const element = textImageList[i];
|
const element = textImageList[i];
|
||||||
height += element.height;
|
height += element.height;
|
||||||
}
|
}
|
||||||
const canvas = new Canvas(800, height + 10);
|
const canvas = new Canvas(
|
||||||
|
BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
|
height + 10,
|
||||||
|
);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = '#a8a8a8';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.separator;
|
||||||
ctx.fillRect(10, 10, 5, height + 20);
|
const lineSpec = createVerticalSeparatorSpec(height + 20);
|
||||||
|
ctx.fillRect(lineSpec.startX, 10, 5, height + 20);
|
||||||
for (let i = 0; i < textImageList.length; i++) {
|
for (let i = 0; i < textImageList.length; i++) {
|
||||||
const element = textImageList[i];
|
const element = textImageList[i];
|
||||||
ctx.drawImage(element, x, y);
|
ctx.drawImage(element, x, y);
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { Canvas, Image } from 'skia-canvas';
|
import { Canvas, Image } from 'skia-canvas';
|
||||||
import { drawList } from './list-frame';
|
import { drawList } from './list-frame';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
|
||||||
interface RarityInListOptions {
|
interface RarityInListOptions {
|
||||||
key?: string;
|
key?: string;
|
||||||
@ -16,11 +15,9 @@ export const starList: { [type: string]: Image } = {};
|
|||||||
* 在图片布局层中加载图片Once。
|
* 在图片布局层中加载图片Once。
|
||||||
*/
|
*/
|
||||||
async function loadImageOnce() {
|
async function loadImageOnce() {
|
||||||
starList.normal = await loadImageFromPath(
|
starList.normal = await loadImageFromPath(getBangDreamAssetPath('cardStar'));
|
||||||
path.join(assetsRootPath, '/Card/star.png'),
|
|
||||||
);
|
|
||||||
starList.trained = await loadImageFromPath(
|
starList.trained = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/star_trained.png'),
|
getBangDreamAssetPath('cardStarTrained'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
loadImageOnce();
|
loadImageOnce();
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import { drawDifficultyList, drawDifficulty } from './list-difficulty';
|
|||||||
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
import { drawList } from './list-frame';
|
import { drawList } from './list-frame';
|
||||||
import { drawDottedLine } from '@/qqbot/plugins/bangDream/tsugu/canvas/dotted-line';
|
import { drawDottedLine } from '@/qqbot/plugins/bangDream/tsugu/canvas/dotted-line';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
import { createHorizontalSeparatorSpec } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/layout-spec';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在图片布局层中绘制歌曲In列表。
|
* 在图片布局层中绘制歌曲In列表。
|
||||||
@ -34,7 +36,7 @@ export async function drawSongInList(
|
|||||||
heightMax: 80,
|
heightMax: 80,
|
||||||
});
|
});
|
||||||
|
|
||||||
const canvas = new Canvas(800, 75);
|
const canvas = new Canvas(BANGDREAM_RENDER_THEME.layout.contentWidth, 75);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.drawImage(songImage, 50, 5, 65, 65);
|
ctx.drawImage(songImage, 50, 5, 65, 65);
|
||||||
//id
|
//id
|
||||||
@ -42,7 +44,7 @@ export async function drawSongInList(
|
|||||||
text: song.songId.toString(),
|
text: song.songId.toString(),
|
||||||
textSize: 23,
|
textSize: 23,
|
||||||
lineHeight: 37.5,
|
lineHeight: 37.5,
|
||||||
maxWidth: 800,
|
maxWidth: BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
});
|
});
|
||||||
ctx.drawImage(idImage, 0, 0);
|
ctx.drawImage(idImage, 0, 0);
|
||||||
//曲名与乐队名
|
//曲名与乐队名
|
||||||
@ -58,7 +60,7 @@ export async function drawSongInList(
|
|||||||
text: fullText,
|
text: fullText,
|
||||||
textSize: 23,
|
textSize: 23,
|
||||||
lineHeight: 37.5,
|
lineHeight: 37.5,
|
||||||
maxWidth: 800,
|
maxWidth: BANGDREAM_RENDER_THEME.layout.contentWidth,
|
||||||
});
|
});
|
||||||
ctx.drawImage(textImage, 120, 0);
|
ctx.drawImage(textImage, 120, 0);
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ export async function drawSongInList(
|
|||||||
: drawDifficulty(difficulty, song.difficulty[difficulty].playLevel, 45);
|
: drawDifficulty(difficulty, song.difficulty[difficulty].playLevel, 45);
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
difficultyImage,
|
difficultyImage,
|
||||||
800 - difficultyImage.width,
|
BANGDREAM_RENDER_THEME.layout.contentWidth - difficultyImage.width,
|
||||||
75 / 2 - difficultyImage.height / 2,
|
75 / 2 - difficultyImage.height / 2,
|
||||||
);
|
);
|
||||||
return canvas;
|
return canvas;
|
||||||
@ -96,17 +98,7 @@ export async function drawSongListInList(
|
|||||||
const x = 0;
|
const x = 0;
|
||||||
let y = 0;
|
let y = 0;
|
||||||
const views: Canvas[] = [];
|
const views: Canvas[] = [];
|
||||||
const line = drawDottedLine({
|
const line = drawDottedLine(createHorizontalSeparatorSpec({ height: 10 }));
|
||||||
width: 800,
|
|
||||||
height: 10,
|
|
||||||
startX: 5,
|
|
||||||
startY: 5,
|
|
||||||
endX: 795,
|
|
||||||
endY: 5,
|
|
||||||
radius: 2,
|
|
||||||
gap: 10,
|
|
||||||
color: '#a8a8a8',
|
|
||||||
});
|
|
||||||
for (let i = 0; i < songs.length; i++) {
|
for (let i = 0; i < songs.length; i++) {
|
||||||
views.push(
|
views.push(
|
||||||
resizeImage({
|
resizeImage({
|
||||||
|
|||||||
@ -1,23 +1,21 @@
|
|||||||
import { Skill } from '@/qqbot/plugins/bangDream/tsugu/models/skill';
|
import { Skill } from '@/qqbot/plugins/bangDream/tsugu/models/skill';
|
||||||
import { Image, Canvas } from 'skia-canvas';
|
import { Image, Canvas } from 'skia-canvas';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import { drawTextWithImages } from '@/qqbot/plugins/bangDream/tsugu/canvas/text';
|
import { drawTextWithImages } from '@/qqbot/plugins/bangDream/tsugu/canvas/text';
|
||||||
import * as path from 'path';
|
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
const skillIcon: { [skillType: string]: Image } = {};
|
const skillIcon: { [skillType: string]: Image } = {};
|
||||||
/**
|
/**
|
||||||
* 在图片布局层中加载图片Once。
|
* 在图片布局层中加载图片Once。
|
||||||
*/
|
*/
|
||||||
async function loadImageOnce() {
|
async function loadImageOnce() {
|
||||||
skillIcon.life = await loadImageFromPath(
|
skillIcon.life = await loadImageFromPath(getBangDreamAssetPath('skillLife'));
|
||||||
path.join(assetsRootPath, '/Skill/life.png'),
|
|
||||||
);
|
|
||||||
skillIcon.judge = await loadImageFromPath(
|
skillIcon.judge = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Skill/judge.png'),
|
getBangDreamAssetPath('skillJudge'),
|
||||||
);
|
);
|
||||||
skillIcon.damage = await loadImageFromPath(
|
skillIcon.damage = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Skill/damage.png'),
|
getBangDreamAssetPath('skillDamage'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
loadImageOnce();
|
loadImageOnce();
|
||||||
@ -70,11 +68,11 @@ export async function drawCardIconSkill(skill: Skill): Promise<Canvas> {
|
|||||||
textSize: 27,
|
textSize: 27,
|
||||||
lineHeight: 30,
|
lineHeight: 30,
|
||||||
spacing: 3,
|
spacing: 3,
|
||||||
color: '#ffffff',
|
color: BANGDREAM_RENDER_THEME.color.surface,
|
||||||
font: 'old',
|
font: BANGDREAM_RENDER_THEME.font.body,
|
||||||
});
|
});
|
||||||
const textbase = await loadImageFromPath(
|
const textbase = await loadImageFromPath(
|
||||||
path.join(assetsRootPath, '/Card/text.png'),
|
getBangDreamAssetPath('cardSkillTextBase'),
|
||||||
);
|
);
|
||||||
const canvas = new Canvas(stringWithImage.width + 15, 45);
|
const canvas = new Canvas(stringWithImage.width + 15, 45);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { Canvas, Image, loadImage } from 'skia-canvas';
|
import { Canvas, Image, loadImage } from 'skia-canvas';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import {
|
||||||
|
BangDreamLocalAssetKey,
|
||||||
|
getBangDreamAssetPath,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
interface BestdoriPreviewPayload {
|
interface BestdoriPreviewPayload {
|
||||||
id: number;
|
id: number;
|
||||||
@ -70,6 +74,23 @@ const NOTE_IMAGE_KEYS = [
|
|||||||
'RightArrow',
|
'RightArrow',
|
||||||
'RightArrowEnd',
|
'RightArrowEnd',
|
||||||
] as const;
|
] as const;
|
||||||
|
const NOTE_IMAGE_ASSET_KEYS: Record<
|
||||||
|
(typeof NOTE_IMAGE_KEYS)[number],
|
||||||
|
BangDreamLocalAssetKey
|
||||||
|
> = {
|
||||||
|
Flick: 'songChartNoteFlick',
|
||||||
|
FlickTop: 'songChartNoteFlickTop',
|
||||||
|
LeftArrow: 'songChartNoteLeftArrow',
|
||||||
|
LeftArrowEnd: 'songChartNoteLeftArrowEnd',
|
||||||
|
Long: 'songChartNoteLong',
|
||||||
|
RightArrow: 'songChartNoteRightArrow',
|
||||||
|
RightArrowEnd: 'songChartNoteRightArrowEnd',
|
||||||
|
Sim: 'songChartNoteSim',
|
||||||
|
Single: 'songChartNoteSingle',
|
||||||
|
SingleOff: 'songChartNoteSingleOff',
|
||||||
|
Skill: 'songChartNoteSkill',
|
||||||
|
Tick: 'songChartNoteTick',
|
||||||
|
};
|
||||||
const DISPLAY_NOTE_TYPES = [
|
const DISPLAY_NOTE_TYPES = [
|
||||||
'Single',
|
'Single',
|
||||||
'SingleOff',
|
'SingleOff',
|
||||||
@ -451,7 +472,9 @@ async function loadNoteImages(): Promise<Record<string, Image>> {
|
|||||||
const entries = await Promise.all(
|
const entries = await Promise.all(
|
||||||
NOTE_IMAGE_KEYS.map(async (key) => [
|
NOTE_IMAGE_KEYS.map(async (key) => [
|
||||||
key,
|
key,
|
||||||
await loadImageFromPath(`${assetsRootPath}/SongChart/note/${key}.png`),
|
await loadImageFromPath(
|
||||||
|
getBangDreamAssetPath(NOTE_IMAGE_ASSET_KEYS[key]),
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
return Object.fromEntries(entries);
|
return Object.fromEntries(entries);
|
||||||
@ -467,7 +490,7 @@ async function loadCoverImage(cover: string | Buffer): Promise<Image> {
|
|||||||
try {
|
try {
|
||||||
return await loadImage(cover);
|
return await loadImage(cover);
|
||||||
} catch {
|
} catch {
|
||||||
return await loadImageFromPath(`${assetsRootPath}/SongChart/jacket.png`);
|
return await loadImageFromPath(getBangDreamAssetPath('songChartJacket'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +549,7 @@ function drawBaseInfo(
|
|||||||
): void {
|
): void {
|
||||||
const { id, diff, level } = payload;
|
const { id, diff, level } = payload;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = '#000';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartBackground;
|
||||||
ctx.fillRect(0, 0, layout.width, layout.height);
|
ctx.fillRect(0, 0, layout.width, layout.height);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|
||||||
@ -539,10 +562,10 @@ function drawBaseInfo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = '#1f1e33';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartPanel;
|
||||||
ctx.fillRect(OFFSET - 8, OFFSET - 8, 128, 24);
|
ctx.fillRect(OFFSET - 8, OFFSET - 8, 128, 24);
|
||||||
ctx.fillStyle = '#FFF';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartText;
|
||||||
ctx.font = '16px "Arial"';
|
ctx.font = `16px "${BANGDREAM_RENDER_THEME.font.chart}"`;
|
||||||
ctx.textAlign = 'center';
|
ctx.textAlign = 'center';
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
ctx.fillText(`${id}`, OFFSET + 56, OFFSET + 4, 128);
|
ctx.fillText(`${id}`, OFFSET + 56, OFFSET + 4, 128);
|
||||||
@ -550,10 +573,12 @@ function drawBaseInfo(
|
|||||||
|
|
||||||
const coverWidth = layout.infoAreaWidth - 16;
|
const coverWidth = layout.infoAreaWidth - 16;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = DIFFICULTY_COLOR_LIST[diff] ?? '#777';
|
ctx.fillStyle =
|
||||||
|
DIFFICULTY_COLOR_LIST[diff] ??
|
||||||
|
BANGDREAM_RENDER_THEME.color.chartDifficultyFallback;
|
||||||
ctx.fillRect(8 + coverWidth - 116, 8 + coverWidth - 12, 128, 24);
|
ctx.fillRect(8 + coverWidth - 116, 8 + coverWidth - 12, 128, 24);
|
||||||
ctx.fillStyle = '#FFF';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartText;
|
||||||
ctx.font = '16px "Arial"';
|
ctx.font = `16px "${BANGDREAM_RENDER_THEME.font.chart}"`;
|
||||||
ctx.textAlign = 'center';
|
ctx.textAlign = 'center';
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
ctx.fillText(`${diff} ${level}`, 8 + coverWidth - 52, 8 + coverWidth, 128);
|
ctx.fillText(`${diff} ${level}`, 8 + coverWidth - 52, 8 + coverWidth, 128);
|
||||||
@ -657,8 +682,8 @@ function drawBeatLines(
|
|||||||
*/
|
*/
|
||||||
function drawTimeline(ctx: any, layout: PreviewLayout): void {
|
function drawTimeline(ctx: any, layout: PreviewLayout): void {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.font = '18px "Arial"';
|
ctx.font = `18px "${BANGDREAM_RENDER_THEME.font.chart}"`;
|
||||||
ctx.fillStyle = '#FFF';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartText;
|
||||||
ctx.textAlign = 'right';
|
ctx.textAlign = 'right';
|
||||||
for (let i = 0; i <= layout.chartLength; i += 5) {
|
for (let i = 0; i <= layout.chartLength; i += 5) {
|
||||||
const { x, y } = getTimePosition(layout, i);
|
const { x, y } = getTimePosition(layout, i);
|
||||||
@ -692,20 +717,20 @@ function drawCountAndBpmLines(
|
|||||||
if (count % 50 !== 0) {
|
if (count % 50 !== 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ctx.font = '18px "Arial"';
|
ctx.font = `18px "${BANGDREAM_RENDER_THEME.font.chart}"`;
|
||||||
ctx.fillStyle = 'rgba(128, 128, 128, 0.5)';
|
ctx.fillStyle = 'rgba(128, 128, 128, 0.5)';
|
||||||
ctx.textAlign = 'left';
|
ctx.textAlign = 'left';
|
||||||
ctx.fillRect(x, y - 1, w, 2);
|
ctx.fillRect(x, y - 1, w, 2);
|
||||||
ctx.fillStyle = '#FFF';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartText;
|
||||||
setAdaptiveTextBaseline(ctx, layout, 18, y);
|
setAdaptiveTextBaseline(ctx, layout, 18, y);
|
||||||
ctx.fillText(`${count}`, x + w + 8, y);
|
ctx.fillText(`${count}`, x + w + 8, y);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.type === 'BPM') {
|
if (note.type === 'BPM') {
|
||||||
ctx.fillStyle = '#C34FBB';
|
ctx.fillStyle = BANGDREAM_RENDER_THEME.color.chartBpm;
|
||||||
ctx.fillRect(x, y - 1, w, 2);
|
ctx.fillRect(x, y - 1, w, 2);
|
||||||
ctx.font = '18px "Arial"';
|
ctx.font = `18px "${BANGDREAM_RENDER_THEME.font.chart}"`;
|
||||||
ctx.textAlign = 'left';
|
ctx.textAlign = 'left';
|
||||||
setAdaptiveTextBaseline(ctx, layout, 18, y);
|
setAdaptiveTextBaseline(ctx, layout, 18, y);
|
||||||
ctx.fillText(`${note.bpm}`, x + w + 8, y);
|
ctx.fillText(`${note.bpm}`, x + w + 8, y);
|
||||||
|
|||||||
31
src/qqbot/plugins/bangDream/tsugu/render-blocks/theme.ts
Normal file
31
src/qqbot/plugins/bangDream/tsugu/render-blocks/theme.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export const BANGDREAM_RENDER_THEME = {
|
||||||
|
color: {
|
||||||
|
backgroundEasy: '#fef3ef',
|
||||||
|
chartBackground: '#000',
|
||||||
|
chartBpm: '#C34FBB',
|
||||||
|
chartDifficultyFallback: '#777',
|
||||||
|
chartPanel: '#1f1e33',
|
||||||
|
chartText: '#FFF',
|
||||||
|
labelBackground: '#5b5b5b',
|
||||||
|
mutedText: '#a7a7a7',
|
||||||
|
primaryText: '#505050',
|
||||||
|
separator: '#a8a8a8',
|
||||||
|
skillLevelBackground: '#ff0000',
|
||||||
|
subtlePanel: '#f1f1f1',
|
||||||
|
surface: '#ffffff',
|
||||||
|
},
|
||||||
|
font: {
|
||||||
|
body: 'old',
|
||||||
|
chart: 'Arial',
|
||||||
|
chinese: 'FangZhengHeiTi',
|
||||||
|
fallback: 'Microsoft Yahei',
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
contentWidth: 800,
|
||||||
|
defaultGap: 20,
|
||||||
|
listIndent: 20,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BangDreamRenderFont =
|
||||||
|
(typeof BANGDREAM_RENDER_THEME.font)[keyof typeof BANGDREAM_RENDER_THEME.font];
|
||||||
@ -1,15 +1,15 @@
|
|||||||
import { Canvas, Image } from 'skia-canvas';
|
import { Canvas, Image } from 'skia-canvas';
|
||||||
import { drawText } from '@/qqbot/plugins/bangDream/tsugu/canvas/text';
|
import { drawText } from '@/qqbot/plugins/bangDream/tsugu/canvas/text';
|
||||||
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
import { loadImageFromPath } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest';
|
||||||
|
import { BANGDREAM_RENDER_THEME } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/theme';
|
||||||
|
|
||||||
let titleImage: Image;
|
let titleImage: Image;
|
||||||
/**
|
/**
|
||||||
* 在图片布局层中加载图片Once。
|
* 在图片布局层中加载图片Once。
|
||||||
*/
|
*/
|
||||||
async function loadImageOnce() {
|
async function loadImageOnce() {
|
||||||
titleImage = await loadImageFromPath(path.join(assetsRootPath, '/title.png'));
|
titleImage = await loadImageFromPath(getBangDreamAssetPath('title'));
|
||||||
}
|
}
|
||||||
loadImageOnce();
|
loadImageOnce();
|
||||||
|
|
||||||
@ -29,16 +29,16 @@ export function drawTitle(title1: string, title2: string): Canvas {
|
|||||||
maxWidth: 900,
|
maxWidth: 900,
|
||||||
lineHeight: 50,
|
lineHeight: 50,
|
||||||
textSize: 30,
|
textSize: 30,
|
||||||
color: '#ffffff',
|
color: BANGDREAM_RENDER_THEME.color.surface,
|
||||||
font: 'old',
|
font: BANGDREAM_RENDER_THEME.font.body,
|
||||||
});
|
});
|
||||||
const text2 = drawText({
|
const text2 = drawText({
|
||||||
text: title2,
|
text: title2,
|
||||||
maxWidth: 900,
|
maxWidth: 900,
|
||||||
lineHeight: 68,
|
lineHeight: 68,
|
||||||
textSize: 40,
|
textSize: 40,
|
||||||
color: '#5b5b5b',
|
color: BANGDREAM_RENDER_THEME.color.labelBackground,
|
||||||
font: 'old',
|
font: BANGDREAM_RENDER_THEME.font.body,
|
||||||
});
|
});
|
||||||
ctx.drawImage(text1, 74, 0);
|
ctx.drawImage(text1, 74, 0);
|
||||||
ctx.drawImage(text2, 74, 42);
|
ctx.drawImage(text2, 74, 42);
|
||||||
|
|||||||
49
src/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest.ts
Normal file
49
src/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
import { assetsRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
|
|
||||||
|
export const BANGDREAM_LOCAL_ASSETS = {
|
||||||
|
backgroundLive: 'BG/live.png',
|
||||||
|
backgroundObjectBig: 'BG/bg_object_big.png',
|
||||||
|
backgroundStar1: 'BG/star1.png',
|
||||||
|
backgroundStar2: 'BG/star2.png',
|
||||||
|
cardBirthday: 'Card/B.png',
|
||||||
|
cardDreamfes: 'Card/D.png',
|
||||||
|
cardKirafes: 'Card/K.png',
|
||||||
|
cardLimited: 'Card/L.png',
|
||||||
|
cardLimitBreakRank: 'Card/limitBreakRank.png',
|
||||||
|
cardSkillTextBase: 'Card/text.png',
|
||||||
|
cardStar: 'Card/star.png',
|
||||||
|
cardStarTrained: 'Card/star_trained.png',
|
||||||
|
fontFangZhengHeiTi: 'Fonts/FangZhengHeiTi_GBK.ttf',
|
||||||
|
fontOld: 'Fonts/old.ttf',
|
||||||
|
skillDamage: 'Skill/damage.png',
|
||||||
|
skillJudge: 'Skill/judge.png',
|
||||||
|
skillLife: 'Skill/life.png',
|
||||||
|
songChartJacket: 'SongChart/jacket.png',
|
||||||
|
songChartNoteBar: 'SongChart/note/Bar.png',
|
||||||
|
songChartNoteFlick: 'SongChart/note/Flick.png',
|
||||||
|
songChartNoteFlickTop: 'SongChart/note/FlickTop.png',
|
||||||
|
songChartNoteLeftArrow: 'SongChart/note/LeftArrow.png',
|
||||||
|
songChartNoteLeftArrowEnd: 'SongChart/note/LeftArrowEnd.png',
|
||||||
|
songChartNoteLong: 'SongChart/note/Long.png',
|
||||||
|
songChartNoteRightArrow: 'SongChart/note/RightArrow.png',
|
||||||
|
songChartNoteRightArrowEnd: 'SongChart/note/RightArrowEnd.png',
|
||||||
|
songChartNoteSim: 'SongChart/note/Sim.png',
|
||||||
|
songChartNoteSingle: 'SongChart/note/Single.png',
|
||||||
|
songChartNoteSingleOff: 'SongChart/note/SingleOff.png',
|
||||||
|
songChartNoteSkill: 'SongChart/note/Skill.png',
|
||||||
|
songChartNoteTick: 'SongChart/note/Tick.png',
|
||||||
|
title: 'title.png',
|
||||||
|
twServerIcon: 'tw.png',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BangDreamLocalAssetKey = keyof typeof BANGDREAM_LOCAL_ASSETS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 Tsugu 本地资源路径。
|
||||||
|
*
|
||||||
|
* @param key - 本地资源 manifest 键名。
|
||||||
|
*/
|
||||||
|
export function getBangDreamAssetPath(key: BangDreamLocalAssetKey): string {
|
||||||
|
return path.join(assetsRootPath, BANGDREAM_LOCAL_ASSETS[key]);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user