@luna-editor/engine 0.5.10 → 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 +42 -5
- package/dist/types.d.ts +3 -1
- 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, _c
|
|
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(),
|
|
@@ -37,7 +72,8 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
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,
|
|
39
74
|
speakerId: (_c = block.speakerId) !== null && _c !== void 0 ? _c : undefined,
|
|
40
|
-
speakerImageUrl:
|
|
75
|
+
speakerImageUrl: speakerImage.imageUrl,
|
|
76
|
+
speakerCropArea: speakerImage.cropArea,
|
|
41
77
|
options: block.options,
|
|
42
78
|
};
|
|
43
79
|
addLogEntry(logEntry);
|
|
@@ -48,7 +84,7 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
48
84
|
}, [scenario.blocks, addLogEntry]);
|
|
49
85
|
// 新しいブロックを処理
|
|
50
86
|
useEffect(() => {
|
|
51
|
-
var _a, _b, _c
|
|
87
|
+
var _a, _b, _c;
|
|
52
88
|
if (!currentBlock || !hasBuiltInitialHistory.current) {
|
|
53
89
|
return;
|
|
54
90
|
}
|
|
@@ -56,7 +92,7 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
56
92
|
if (currentBlock.blockType === "dialogue" ||
|
|
57
93
|
currentBlock.blockType === "narration") {
|
|
58
94
|
if (!processedBlocks.current.has(currentBlockIndex)) {
|
|
59
|
-
|
|
95
|
+
const speakerImage = resolveSpeakerImage(currentBlock, scenario.blocks);
|
|
60
96
|
const logEntry = {
|
|
61
97
|
id: `${currentBlock.id}_${Date.now()}`,
|
|
62
98
|
timestamp: Date.now(),
|
|
@@ -66,7 +102,8 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
|
|
|
66
102
|
speakerName: (_a = currentBlock.speaker) === null || _a === void 0 ? void 0 : _a.name,
|
|
67
103
|
speakerState: (_b = currentBlock.speakerState) === null || _b === void 0 ? void 0 : _b.name,
|
|
68
104
|
speakerId: (_c = currentBlock.speakerId) !== null && _c !== void 0 ? _c : undefined,
|
|
69
|
-
speakerImageUrl:
|
|
105
|
+
speakerImageUrl: speakerImage.imageUrl,
|
|
106
|
+
speakerCropArea: speakerImage.cropArea,
|
|
70
107
|
options: currentBlock.options,
|
|
71
108
|
};
|
|
72
109
|
addLogEntry(logEntry);
|
package/dist/types.d.ts
CHANGED
|
@@ -392,8 +392,10 @@ export interface BacklogEntry {
|
|
|
392
392
|
speakerState?: string;
|
|
393
393
|
/** 話者のオブジェクトID */
|
|
394
394
|
speakerId?: string;
|
|
395
|
-
/** 話者の画像URL
|
|
395
|
+
/** 話者の画像URL(そのブロック時点の状態の画像、またはレイヤーキャラの素体画像) */
|
|
396
396
|
speakerImageUrl?: string;
|
|
397
|
+
/** 話者の画像クロップ情報(JSON: {x, y, width, height}) */
|
|
398
|
+
speakerCropArea?: string;
|
|
397
399
|
/** Block options (for plugin-defined options like bubble style) */
|
|
398
400
|
options?: BlockOptions | null;
|
|
399
401
|
}
|