Skip to content

Commit 368793c

Browse files
LIlGGCopilot
andcommitted
Refine Live2D loading behavior
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1f86880 commit 368793c

8 files changed

Lines changed: 217 additions & 80 deletions

File tree

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,14 @@ TIPS 文件格式
7272
"hour": "6-7", // 时间,小时为单位,需要为区间,例如 6-7 代表 6 点到 7 点之间
7373
"text": [] // Live2d 消息框显示内容。为数组则随机选择一条显示
7474
],
75-
"message": { // 固定消息,通常代表特定事件
76-
"default": [], // 页面空闲时显示的消息
77-
"console": [], // 打开控制台时显示的消息
78-
"copy": [], // 复制内容时显示的消息
79-
"visibilitychange": [] // 多标签页,从其他标签页返回当前标签页时显示的消息
80-
}
81-
}
75+
"message": { // 固定消息,通常代表特定事件
76+
"default": [], // 页面空闲时显示的消息
77+
"console": [], // 打开控制台时显示的消息
78+
"copy": [], // 复制内容时显示的消息
79+
"loading": [], // 模型加载时显示的消息
80+
"visibilitychange": [] // 多标签页,从其他标签页返回当前标签页时显示的消息
81+
}
82+
}
8283
```
8384

8485
#### 1. 使用主题提供的 TIPS 文件(推荐)

packages/live2d/src/context/config-context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface TipMessage extends ObjectAny {
2727
default?: string[] | string;
2828
console?: string[] | string;
2929
copy?: string[] | string;
30+
loading?: string[] | string;
3031
visibilitychange?: string[] | string;
3132
}
3233

packages/live2d/src/events/tip-events.ts

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ import {
1414
BEFORE_INIT_EVENT_NAME,
1515
type BeforeInitEvent,
1616
} from "@/live2d/events/before-init";
17+
import { MODEL_READY_EVENT_NAME } from "@/live2d/events/model-ready";
1718
import { dataWithinRange } from "@/live2d/helpers/dateWithinRange";
18-
import { getPluginTips } from "@/live2d/helpers/getPluginTips";
19-
import { loadFullTipsResource } from "@/live2d/helpers/loadFullTipsResource";
20-
import { loadTipsResource } from "@/live2d/helpers/loadTipsResource";
21-
import { mergeTips } from "@/live2d/helpers/mergeTips";
19+
import { loadMergedTips } from "@/live2d/helpers/loadMergedTips";
2220
import { sendMessage } from "@/live2d/helpers/sendMessage";
2321
import { timeWithinRange } from "@/live2d/helpers/timeWithinRange";
2422
import { isString } from "@/live2d/utils/isString";
@@ -29,6 +27,7 @@ import {
2927
hasWebsiteHome,
3028
} from "@/live2d/utils/util";
3129
let activeTipEvents: TipEventController | undefined;
30+
let isInitialModelReady = false;
3231

3332
const _getWelComeMessage = (times: TipTime[]) => {
3433
if (hasWebsiteHome) {
@@ -216,16 +215,24 @@ const _userActionEvent = (
216215
class TipEventController {
217216
private readonly abortController = new AbortController();
218217
private readonly disposers: Array<() => void> = [];
218+
private hasShownWelcome = false;
219219

220220
constructor(
221221
private readonly config: Live2dConfig,
222222
private readonly tips: TipConfig,
223223
) {}
224224

225-
start(): void {
225+
start(modelReady: boolean): void {
226226
const { signal } = this.abortController;
227227
if (this.config.firstOpenSite) {
228-
_welcomeEvent(this.tips.time);
228+
if (modelReady) {
229+
this.showWelcomeMessage();
230+
} else {
231+
window.addEventListener(MODEL_READY_EVENT_NAME, this.handleModelReady, {
232+
signal,
233+
once: true,
234+
});
235+
}
229236
}
230237

231238
const userActionState = _userActionEvent(this.tips.message, signal);
@@ -266,52 +273,38 @@ class TipEventController {
266273
}
267274
this.disposers.length = 0;
268275
}
269-
}
270276

271-
const _loadTips = async (config: Live2dConfig) => {
272-
if (!config) {
273-
return;
274-
}
275-
// 后台配置 tips,其中包含 mouseover 及 click 两种配置,以及单独配置的 message
276-
const pluginTips = getPluginTips(config);
277-
// 主题设置 tips,只会包含 mouseover 及 click 两种配置(会过滤掉其他配置)
278-
const themeTipsResult = await loadTipsResource(config.themeTipsPath);
279-
const themeTips: TipConfig = {
280-
click: themeTipsResult?.click || [],
281-
mouseover: themeTipsResult?.mouseover || [],
282-
seasons: [],
283-
time: [],
284-
message: {},
277+
private readonly handleModelReady = () => {
278+
this.showWelcomeMessage();
285279
};
286-
const fullOrDefaultTips = await _getFullOrDefaultTips(config);
287-
// 合并三种 tips
288-
return mergeTips({
289-
pluginTips,
290-
themeTips,
291-
fullOrDefaultTips,
292-
});
293-
};
294280

295-
export const _getFullOrDefaultTips = async (
296-
config: Live2dConfig,
297-
): Promise<TipConfig> => {
298-
return loadFullTipsResource(config?.tipsPath, async () => {
299-
return (await import("../libs/live2d-tips.json")).default;
300-
});
301-
};
281+
private showWelcomeMessage(): void {
282+
if (this.hasShownWelcome) {
283+
return;
284+
}
285+
286+
this.hasShownWelcome = true;
287+
_welcomeEvent(this.tips.time);
288+
}
289+
}
302290

303291
window.addEventListener(BEFORE_INIT_EVENT_NAME, async (event) => {
292+
isInitialModelReady = false;
304293
const config = (event as BeforeInitEvent).detail.config;
305294
if (!config) {
306295
return;
307296
}
308297

309-
const tips = await _loadTips(config);
298+
const tips = await loadMergedTips(config);
310299
if (!tips) {
311300
return;
312301
}
313302

314303
activeTipEvents?.dispose();
315304
activeTipEvents = new TipEventController(config, tips);
316-
activeTipEvents.start();
305+
activeTipEvents.start(isInitialModelReady);
306+
});
307+
308+
window.addEventListener(MODEL_READY_EVENT_NAME, () => {
309+
isInitialModelReady = true;
317310
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { Live2dConfig, TipConfig } from "@/live2d/context/config-context";
2+
import { getPluginTips } from "@/live2d/helpers/getPluginTips";
3+
import { loadFullTipsResource } from "@/live2d/helpers/loadFullTipsResource";
4+
import { loadTipsResource } from "@/live2d/helpers/loadTipsResource";
5+
import { mergeTips } from "@/live2d/helpers/mergeTips";
6+
7+
const mergedTipsCache = new WeakMap<Live2dConfig, Promise<TipConfig>>();
8+
9+
const loadDefaultTips = async (): Promise<TipConfig> => {
10+
return (await import("../libs/live2d-tips.json")).default;
11+
};
12+
13+
const createThemeTips = async (config: Live2dConfig): Promise<TipConfig> => {
14+
const themeTipsResult = await loadTipsResource(config.themeTipsPath);
15+
return {
16+
click: themeTipsResult?.click || [],
17+
mouseover: themeTipsResult?.mouseover || [],
18+
seasons: [],
19+
time: [],
20+
message: {},
21+
};
22+
};
23+
24+
const createMergedTips = async (config: Live2dConfig): Promise<TipConfig> => {
25+
const pluginTips = getPluginTips(config);
26+
const themeTips = await createThemeTips(config);
27+
const fullOrDefaultTips = await loadFullTipsResource(
28+
config?.tipsPath,
29+
loadDefaultTips,
30+
);
31+
return mergeTips({
32+
pluginTips,
33+
themeTips,
34+
fullOrDefaultTips,
35+
});
36+
};
37+
38+
export const loadMergedTips = (config: Live2dConfig): Promise<TipConfig> => {
39+
const cachedTips = mergedTipsCache.get(config);
40+
if (cachedTips) {
41+
return cachedTips;
42+
}
43+
44+
const nextTips = createMergedTips(config);
45+
mergedTipsCache.set(config, nextTips);
46+
return nextTips;
47+
};

packages/live2d/src/helpers/loadTipsResource.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ const isTipMessage = (value: unknown): value is TipMessage => {
8080
if (!isRecord(value)) {
8181
return false;
8282
}
83-
const optionalFields = ["default", "console", "copy", "visibilitychange"];
83+
const optionalFields = [
84+
"default",
85+
"console",
86+
"copy",
87+
"loading",
88+
"visibilitychange",
89+
];
8490
return optionalFields.every((field) => {
8591
const nextValue = value[field];
8692
return nextValue === undefined || isTipText(nextValue);

packages/live2d/src/libs/live2d-tips.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,11 @@
407407
],
408408
"console": "哈哈,你打开了控制台,是想要看看我的小秘密吗?",
409409
"copy": "你都复制了些什么呀,转载要记得加上出处哦!",
410+
"loading": [
411+
"稍等一下下哦,人家正在梳理小裙摆,马上就来陪你啦~",
412+
"呜喵~正在努力赶来中,请再给人家一点点时间嘛!",
413+
"正在元气加载中!等我整理好发饰,就出来和你贴贴啦~"
414+
],
410415
"visibilitychange": "哇,你终于回来了~"
411416
}
412417
}

0 commit comments

Comments
 (0)