@luna-editor/engine 0.5.9 → 0.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useBacklog.js +44 -3
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
package/dist/hooks/useBacklog.js
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* speakerIdからキャラクター画像URLとクロップ情報を解決する
|
|
4
|
+
* 優先順位: speakerState > baseBodyState > characters[].entityState
|
|
5
|
+
*/
|
|
6
|
+
function resolveSpeakerImage(block, allBlocks) {
|
|
7
|
+
var _a, _b, _c, _d;
|
|
8
|
+
// 1. speakerState(単一画像キャラ)
|
|
9
|
+
if ((_a = block.speakerState) === null || _a === void 0 ? void 0 : _a.imageUrl) {
|
|
10
|
+
return {
|
|
11
|
+
imageUrl: block.speakerState.imageUrl,
|
|
12
|
+
cropArea: (_b = block.speakerState.cropArea) !== null && _b !== void 0 ? _b : undefined,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
if (!block.speakerId)
|
|
16
|
+
return {};
|
|
17
|
+
// 2. character_entranceブロックからbaseBodyState or entityStateを探す
|
|
18
|
+
for (const b of allBlocks) {
|
|
19
|
+
if (b.characters) {
|
|
20
|
+
const char = b.characters.find((c) => c.object.id === block.speakerId);
|
|
21
|
+
if (char) {
|
|
22
|
+
if ((_c = char.baseBodyState) === null || _c === void 0 ? void 0 : _c.imageUrl) {
|
|
23
|
+
return { imageUrl: char.baseBodyState.imageUrl };
|
|
24
|
+
}
|
|
25
|
+
if (char.entityState.imageUrl) {
|
|
26
|
+
return {
|
|
27
|
+
imageUrl: char.entityState.imageUrl,
|
|
28
|
+
cropArea: (_d = char.entityState.cropArea) !== null && _d !== void 0 ? _d : undefined,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
2
36
|
export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
3
37
|
const [logs, setLogs] = useState([]);
|
|
4
38
|
const hasBuiltInitialHistory = useRef(false);
|
|
@@ -26,8 +60,9 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
26
60
|
.map((block, index) => ({ block, realIndex: index }))
|
|
27
61
|
.filter(({ block }) => block.blockType === "dialogue" || block.blockType === "narration");
|
|
28
62
|
conversationBlocks.forEach(({ block, realIndex }) => {
|
|
29
|
-
var _a, _b;
|
|
63
|
+
var _a, _b, _c;
|
|
30
64
|
if (!processedBlocks.current.has(realIndex)) {
|
|
65
|
+
const speakerImage = resolveSpeakerImage(block, scenario.blocks);
|
|
31
66
|
const logEntry = {
|
|
32
67
|
id: `${block.id}_init`,
|
|
33
68
|
timestamp: Date.now(),
|
|
@@ -36,6 +71,9 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
36
71
|
content: block.content,
|
|
37
72
|
speakerName: (_a = block.speaker) === null || _a === void 0 ? void 0 : _a.name,
|
|
38
73
|
speakerState: (_b = block.speakerState) === null || _b === void 0 ? void 0 : _b.name,
|
|
74
|
+
speakerId: (_c = block.speakerId) !== null && _c !== void 0 ? _c : undefined,
|
|
75
|
+
speakerImageUrl: speakerImage.imageUrl,
|
|
76
|
+
speakerCropArea: speakerImage.cropArea,
|
|
39
77
|
options: block.options,
|
|
40
78
|
};
|
|
41
79
|
addLogEntry(logEntry);
|
|
@@ -46,7 +84,7 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
46
84
|
}, [scenario.blocks, addLogEntry]);
|
|
47
85
|
// 新しいブロックを処理
|
|
48
86
|
useEffect(() => {
|
|
49
|
-
var _a, _b;
|
|
87
|
+
var _a, _b, _c;
|
|
50
88
|
if (!currentBlock || !hasBuiltInitialHistory.current) {
|
|
51
89
|
return;
|
|
52
90
|
}
|
|
@@ -54,7 +92,7 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
54
92
|
if (currentBlock.blockType === "dialogue" ||
|
|
55
93
|
currentBlock.blockType === "narration") {
|
|
56
94
|
if (!processedBlocks.current.has(currentBlockIndex)) {
|
|
57
|
-
|
|
95
|
+
const speakerImage = resolveSpeakerImage(currentBlock, scenario.blocks);
|
|
58
96
|
const logEntry = {
|
|
59
97
|
id: `${currentBlock.id}_${Date.now()}`,
|
|
60
98
|
timestamp: Date.now(),
|
|
@@ -63,6 +101,9 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
63
101
|
content: currentBlock.content,
|
|
64
102
|
speakerName: (_a = currentBlock.speaker) === null || _a === void 0 ? void 0 : _a.name,
|
|
65
103
|
speakerState: (_b = currentBlock.speakerState) === null || _b === void 0 ? void 0 : _b.name,
|
|
104
|
+
speakerId: (_c = currentBlock.speakerId) !== null && _c !== void 0 ? _c : undefined,
|
|
105
|
+
speakerImageUrl: speakerImage.imageUrl,
|
|
106
|
+
speakerCropArea: speakerImage.cropArea,
|
|
66
107
|
options: currentBlock.options,
|
|
67
108
|
};
|
|
68
109
|
addLogEntry(logEntry);
|
package/dist/types.d.ts
CHANGED
|
@@ -390,6 +390,12 @@ export interface BacklogEntry {
|
|
|
390
390
|
content: string | null;
|
|
391
391
|
speakerName?: string;
|
|
392
392
|
speakerState?: string;
|
|
393
|
+
/** 話者のオブジェクトID */
|
|
394
|
+
speakerId?: string;
|
|
395
|
+
/** 話者の画像URL(そのブロック時点の状態の画像、またはレイヤーキャラの素体画像) */
|
|
396
|
+
speakerImageUrl?: string;
|
|
397
|
+
/** 話者の画像クロップ情報(JSON: {x, y, width, height}) */
|
|
398
|
+
speakerCropArea?: string;
|
|
393
399
|
/** Block options (for plugin-defined options like bubble style) */
|
|
394
400
|
options?: BlockOptions | null;
|
|
395
401
|
}
|