react-three-game 0.0.93 → 0.0.94
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/README.md +35 -77
- package/dist/index.d.ts +9 -6
- package/dist/index.js +5 -3
- package/dist/tools/prefabeditor/EditorTree.js +8 -12
- package/dist/tools/prefabeditor/EditorUI.js +4 -4
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +12 -33
- package/dist/tools/prefabeditor/PrefabEditor.js +137 -161
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +24 -12
- package/dist/tools/prefabeditor/PrefabRoot.js +60 -41
- package/dist/tools/prefabeditor/assetRuntime.d.ts +11 -17
- package/dist/tools/prefabeditor/assetRuntime.js +15 -15
- package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/Input.js +5 -9
- package/dist/tools/prefabeditor/components/ModelComponent.js +3 -5
- package/dist/tools/prefabeditor/components/PointLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SoundComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -2
- package/dist/tools/prefabeditor/prefab.d.ts +1 -2
- package/dist/tools/prefabeditor/prefab.js +2 -3
- package/dist/tools/prefabeditor/prefabStore.d.ts +0 -6
- package/dist/tools/prefabeditor/prefabStore.js +1 -33
- package/package.json +49 -49
|
@@ -10,10 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
11
|
import { MapControls, TransformControls, useHelper } from "@react-three/drei";
|
|
12
12
|
import GameCanvas from "../../shared/GameCanvas";
|
|
13
|
-
import { useCallback, useEffect, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
|
|
13
|
+
import { useCallback, useEffect, useMemo, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
|
|
14
14
|
import { BoxHelper } from "three";
|
|
15
15
|
import { findComponentEntry } from "./types";
|
|
16
|
-
import {
|
|
16
|
+
import { PrefabEditorMode, PrefabRoot } from "./PrefabRoot";
|
|
17
17
|
import EditorUI from "./EditorUI";
|
|
18
18
|
import { base, toolbar } from "./styles";
|
|
19
19
|
import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, exportGLBData, focusCameraOnObject, regenerateIds } from "./utils";
|
|
@@ -37,12 +37,8 @@ function SelectionHelper({ object }) {
|
|
|
37
37
|
useHelper(object ? objectRef : null, BoxHelper, "cyan");
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
|
-
export var PrefabEditorMode;
|
|
41
|
-
(function (PrefabEditorMode) {
|
|
42
|
-
PrefabEditorMode["Edit"] = "edit";
|
|
43
|
-
PrefabEditorMode["Play"] = "play";
|
|
44
|
-
})(PrefabEditorMode || (PrefabEditorMode = {}));
|
|
45
40
|
export const EditorContext = createContext(null);
|
|
41
|
+
export const EditorRefContext = createContext(null);
|
|
46
42
|
export function useEditorContext() {
|
|
47
43
|
const context = useContext(EditorContext);
|
|
48
44
|
if (!context) {
|
|
@@ -50,6 +46,13 @@ export function useEditorContext() {
|
|
|
50
46
|
}
|
|
51
47
|
return context;
|
|
52
48
|
}
|
|
49
|
+
export function useEditorRef() {
|
|
50
|
+
const editorRef = useContext(EditorRefContext);
|
|
51
|
+
if (!editorRef) {
|
|
52
|
+
throw new Error("useEditorRef must be used within PrefabEditor");
|
|
53
|
+
}
|
|
54
|
+
return editorRef;
|
|
55
|
+
}
|
|
53
56
|
const MAX_HISTORY_LENGTH = 50;
|
|
54
57
|
const HISTORY_DEBOUNCE_MS = 500;
|
|
55
58
|
const DEFAULT_PREFAB = {
|
|
@@ -68,35 +71,68 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
68
71
|
const [prefabStore] = useState(() => createPrefabStore(startingPrefab));
|
|
69
72
|
const [history, setHistory] = useState([startingPrefab]);
|
|
70
73
|
const [historyIndex, setHistoryIndex] = useState(0);
|
|
71
|
-
const changeOriginRef = useRef(null);
|
|
72
74
|
const historyIndexRef = useRef(0);
|
|
75
|
+
const historyTimeoutRef = useRef(null);
|
|
73
76
|
const prefabRootRef = useRef(null);
|
|
74
77
|
const canvasRef = useRef(null);
|
|
75
78
|
const controlsRef = useRef(null);
|
|
76
79
|
const transformControlsRef = useRef(null);
|
|
77
80
|
const onChangeRef = useRef(onChange);
|
|
78
|
-
const sceneChangeListenersRef = useRef(new Set());
|
|
79
81
|
const isEditMode = mode === PrefabEditorMode.Edit;
|
|
80
82
|
const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
|
|
81
83
|
const getNode = useCallback((nodeId) => { var _a; return (_a = prefabStore.getState().nodesById[nodeId]) !== null && _a !== void 0 ? _a : null; }, [prefabStore]);
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
84
|
+
const getRoot = useCallback(() => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null; }, []);
|
|
85
|
+
const getObject = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
86
|
+
const getHandle = useCallback((nodeId, kind) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getHandle(nodeId, kind)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
87
|
+
const scheduleHistory = useCallback((nextPrefab) => {
|
|
88
|
+
if (historyTimeoutRef.current) {
|
|
89
|
+
clearTimeout(historyTimeoutRef.current);
|
|
90
|
+
historyTimeoutRef.current = null;
|
|
91
|
+
}
|
|
92
|
+
historyTimeoutRef.current = setTimeout(() => {
|
|
93
|
+
const currentHistoryIndex = historyIndexRef.current;
|
|
94
|
+
setHistory(prev => {
|
|
95
|
+
const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
|
|
96
|
+
return nextHistory.length > MAX_HISTORY_LENGTH ? nextHistory.slice(1) : nextHistory;
|
|
97
|
+
});
|
|
98
|
+
const nextHistoryIndex = Math.min(currentHistoryIndex + 1, MAX_HISTORY_LENGTH - 1);
|
|
99
|
+
historyIndexRef.current = nextHistoryIndex;
|
|
100
|
+
setHistoryIndex(nextHistoryIndex);
|
|
101
|
+
historyTimeoutRef.current = null;
|
|
102
|
+
}, HISTORY_DEBOUNCE_MS);
|
|
103
|
+
}, []);
|
|
104
|
+
const mutate = useCallback((run, pushHistory = isEditMode) => {
|
|
105
|
+
var _a;
|
|
106
|
+
const before = prefabStore.getState();
|
|
107
|
+
const result = run(before);
|
|
108
|
+
const after = prefabStore.getState();
|
|
109
|
+
if (after === before)
|
|
110
|
+
return result;
|
|
111
|
+
const prefab = denormalizePrefab(after);
|
|
112
|
+
(_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, prefab);
|
|
113
|
+
if (pushHistory)
|
|
114
|
+
scheduleHistory(prefab);
|
|
115
|
+
return result;
|
|
116
|
+
}, [isEditMode, prefabStore, scheduleHistory]);
|
|
117
|
+
const update = useCallback((id, fn) => {
|
|
118
|
+
mutate(s => s.updateNode(id, fn));
|
|
119
|
+
}, [mutate]);
|
|
120
|
+
const remove = useCallback((id) => {
|
|
121
|
+
mutate(s => s.deleteNode(id));
|
|
122
|
+
}, [mutate]);
|
|
123
|
+
const duplicate = useCallback((id) => {
|
|
124
|
+
return mutate(s => s.duplicateNode(id));
|
|
125
|
+
}, [mutate]);
|
|
126
|
+
const move = useCallback((draggedId, targetId, position) => {
|
|
127
|
+
mutate(s => s.moveNode(draggedId, targetId, position));
|
|
128
|
+
}, [mutate]);
|
|
129
|
+
const add = useCallback((node, parentId) => {
|
|
130
|
+
mutate(s => s.addChild(parentId !== null && parentId !== void 0 ? parentId : s.rootId, node));
|
|
131
|
+
return node;
|
|
132
|
+
}, [mutate]);
|
|
133
|
+
const replace = useCallback((prefab) => {
|
|
134
|
+
mutate(s => s.replacePrefab(prefab), false);
|
|
135
|
+
}, [mutate]);
|
|
100
136
|
onChangeRef.current = onChange;
|
|
101
137
|
const setSelection = useCallback((nodeId) => {
|
|
102
138
|
const nextNode = nodeId ? prefabStore.getState().nodesById[nodeId] : null;
|
|
@@ -122,10 +158,14 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
122
158
|
updateMode(initialMode);
|
|
123
159
|
}, [initialMode, updateMode]);
|
|
124
160
|
const loadPrefab = useCallback((prefab, options) => {
|
|
125
|
-
var _a;
|
|
126
|
-
changeOriginRef.current = (options === null || options === void 0 ? void 0 : options.notifyChange) === false ? "replace-silent" : "replace";
|
|
161
|
+
var _a, _b;
|
|
127
162
|
(_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
|
|
163
|
+
const before = prefabStore.getState();
|
|
128
164
|
prefabStore.getState().replacePrefab(prefab);
|
|
165
|
+
const after = prefabStore.getState();
|
|
166
|
+
if (after !== before && (options === null || options === void 0 ? void 0 : options.notifyChange) !== false) {
|
|
167
|
+
(_b = onChangeRef.current) === null || _b === void 0 ? void 0 : _b.call(onChangeRef, prefab);
|
|
168
|
+
}
|
|
129
169
|
if (options === null || options === void 0 ? void 0 : options.resetHistory) {
|
|
130
170
|
setSelectedId(null);
|
|
131
171
|
setHistory([prefab]);
|
|
@@ -141,47 +181,12 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
141
181
|
loadPrefab(initialPrefab, { resetHistory: true, notifyChange: false });
|
|
142
182
|
}, [initialPrefab, loadPrefab]);
|
|
143
183
|
useEffect(() => {
|
|
144
|
-
let historyTimeout = null;
|
|
145
|
-
let lastRevision = prefabStore.getState().revision;
|
|
146
|
-
const unsubscribe = prefabStore.subscribe((state) => {
|
|
147
|
-
var _a;
|
|
148
|
-
if (state.revision === lastRevision) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
lastRevision = state.revision;
|
|
152
|
-
sceneChangeListenersRef.current.forEach(listener => listener(state.revision));
|
|
153
|
-
const nextPrefab = denormalizePrefab(state);
|
|
154
|
-
const changeOrigin = changeOriginRef.current;
|
|
155
|
-
if (changeOrigin !== "replace-silent") {
|
|
156
|
-
(_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, nextPrefab);
|
|
157
|
-
}
|
|
158
|
-
if (historyTimeout) {
|
|
159
|
-
clearTimeout(historyTimeout);
|
|
160
|
-
historyTimeout = null;
|
|
161
|
-
}
|
|
162
|
-
if (changeOrigin || !isEditMode) {
|
|
163
|
-
changeOriginRef.current = null;
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
historyTimeout = setTimeout(() => {
|
|
167
|
-
const currentHistoryIndex = historyIndexRef.current;
|
|
168
|
-
setHistory(prev => {
|
|
169
|
-
const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
|
|
170
|
-
return nextHistory.length > MAX_HISTORY_LENGTH ? nextHistory.slice(1) : nextHistory;
|
|
171
|
-
});
|
|
172
|
-
const nextHistoryIndex = Math.min(currentHistoryIndex + 1, MAX_HISTORY_LENGTH - 1);
|
|
173
|
-
historyIndexRef.current = nextHistoryIndex;
|
|
174
|
-
setHistoryIndex(nextHistoryIndex);
|
|
175
|
-
historyTimeout = null;
|
|
176
|
-
}, HISTORY_DEBOUNCE_MS);
|
|
177
|
-
});
|
|
178
184
|
return () => {
|
|
179
|
-
if (
|
|
180
|
-
clearTimeout(
|
|
185
|
+
if (historyTimeoutRef.current) {
|
|
186
|
+
clearTimeout(historyTimeoutRef.current);
|
|
181
187
|
}
|
|
182
|
-
unsubscribe();
|
|
183
188
|
};
|
|
184
|
-
}, [
|
|
189
|
+
}, []);
|
|
185
190
|
useEffect(() => {
|
|
186
191
|
if (!selectedId)
|
|
187
192
|
return;
|
|
@@ -192,42 +197,19 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
192
197
|
});
|
|
193
198
|
return () => unsubscribe();
|
|
194
199
|
}, [prefabStore, selectedId]);
|
|
195
|
-
const selectedObject = selectedId ?
|
|
200
|
+
const selectedObject = selectedId ? getObject(selectedId) : null;
|
|
196
201
|
const transformObject = isEditMode && selectedObject
|
|
197
|
-
&& isObjectAttachedToRoot(
|
|
202
|
+
&& isObjectAttachedToRoot(getRoot(), selectedObject)
|
|
198
203
|
? selectedObject
|
|
199
204
|
: null;
|
|
200
|
-
const addNode = useCallback((node, options) => {
|
|
201
|
-
var _a;
|
|
202
|
-
const { addChild, rootId } = prefabStore.getState();
|
|
203
|
-
addChild((_a = options === null || options === void 0 ? void 0 : options.parentId) !== null && _a !== void 0 ? _a : rootId, node);
|
|
204
|
-
if ((options === null || options === void 0 ? void 0 : options.select) !== false) {
|
|
205
|
-
setSelection(node.id);
|
|
206
|
-
}
|
|
207
|
-
return node;
|
|
208
|
-
}, [prefabStore, setSelection]);
|
|
209
205
|
const importPrefab = useCallback((prefab) => {
|
|
210
|
-
|
|
211
|
-
}, [
|
|
212
|
-
const addModel = useCallback((path, model, options) => {
|
|
213
|
-
var _a;
|
|
214
|
-
const node = createModelNode(path, options === null || options === void 0 ? void 0 : options.name);
|
|
215
|
-
addNode(node, options);
|
|
216
|
-
(_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model);
|
|
217
|
-
return node;
|
|
218
|
-
}, [addNode]);
|
|
219
|
-
const addTexture = useCallback((path, texture, options) => {
|
|
220
|
-
var _a;
|
|
221
|
-
const node = createImageNode(path, options === null || options === void 0 ? void 0 : options.name);
|
|
222
|
-
addNode(node, options);
|
|
223
|
-
(_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture);
|
|
224
|
-
return node;
|
|
225
|
-
}, [addNode]);
|
|
206
|
+
add(regenerateIds(prefab.root));
|
|
207
|
+
}, [add]);
|
|
226
208
|
const applyHistory = (index) => {
|
|
227
|
-
var _a;
|
|
228
|
-
changeOriginRef.current = "history";
|
|
209
|
+
var _a, _b;
|
|
229
210
|
(_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
|
|
230
211
|
prefabStore.getState().replacePrefab(history[index]);
|
|
212
|
+
(_b = onChangeRef.current) === null || _b === void 0 ? void 0 : _b.call(onChangeRef, history[index]);
|
|
231
213
|
historyIndexRef.current = index;
|
|
232
214
|
setHistoryIndex(index);
|
|
233
215
|
setSelectedId(prev => prev && prefabStore.getState().nodesById[prev] ? prev : null);
|
|
@@ -275,36 +257,36 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
275
257
|
}), [setSelection]);
|
|
276
258
|
const handleExportGLB = useCallback((...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
|
|
277
259
|
yield clearSelection();
|
|
278
|
-
const rootObject =
|
|
260
|
+
const rootObject = getRoot();
|
|
279
261
|
if (!rootObject)
|
|
280
262
|
return;
|
|
281
263
|
return exportGLBFile(rootObject, Object.assign({ filename: `${prefabStore.getState().prefabName || 'prefab'}.glb` }, options));
|
|
282
|
-
}), [clearSelection,
|
|
264
|
+
}), [clearSelection, getRoot, prefabStore]);
|
|
283
265
|
const handleExportGLBData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
284
266
|
yield clearSelection();
|
|
285
|
-
const rootObject =
|
|
267
|
+
const rootObject = getRoot();
|
|
286
268
|
if (!rootObject)
|
|
287
269
|
return;
|
|
288
270
|
return exportGLBData(rootObject);
|
|
289
|
-
}), [clearSelection,
|
|
271
|
+
}), [clearSelection, getRoot]);
|
|
290
272
|
const handleFocusNode = useCallback((nodeId) => {
|
|
291
|
-
const object =
|
|
273
|
+
const object = getObject(nodeId);
|
|
292
274
|
const controls = controlsRef.current;
|
|
293
275
|
const camera = controls === null || controls === void 0 ? void 0 : controls.object;
|
|
294
276
|
if (!object || !controls || !camera)
|
|
295
277
|
return;
|
|
296
278
|
focusCameraOnObject(object, camera, controls.target, () => { var _a; return (_a = controls.update) === null || _a === void 0 ? void 0 : _a.call(controls); });
|
|
297
|
-
}, [
|
|
279
|
+
}, [getObject]);
|
|
298
280
|
const handleTransformChange = () => {
|
|
299
281
|
if (!selectedId)
|
|
300
282
|
return;
|
|
301
|
-
const object =
|
|
283
|
+
const object = getObject(selectedId);
|
|
302
284
|
if (!object)
|
|
303
285
|
return;
|
|
304
286
|
const parentWorld = computeParentWorldMatrix(prefabStore.getState(), selectedId);
|
|
305
287
|
const local = parentWorld.clone().invert().multiply(object.matrixWorld);
|
|
306
288
|
const { position, rotation, scale } = decompose(local);
|
|
307
|
-
|
|
289
|
+
update(selectedId, node => {
|
|
308
290
|
var _a;
|
|
309
291
|
const entry = findComponentEntry(node, "Transform");
|
|
310
292
|
const key = (_a = entry === null || entry === void 0 ? void 0 : entry[0]) !== null && _a !== void 0 ? _a : "transform";
|
|
@@ -327,16 +309,17 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
327
309
|
e.preventDefault();
|
|
328
310
|
e.stopPropagation();
|
|
329
311
|
const files = ((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) ? Array.from(e.dataTransfer.files) : [];
|
|
312
|
+
const scene = prefabRootRef.current;
|
|
330
313
|
void loadFiles(files, {
|
|
331
314
|
onModelLoaded: (model, filename) => {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
315
|
+
const path = `models/${filename}`;
|
|
316
|
+
scene === null || scene === void 0 ? void 0 : scene.addModel(path, model);
|
|
317
|
+
add(createModelNode(path, filename.replace(/\.[^.]+$/, '')));
|
|
335
318
|
},
|
|
336
319
|
onTextureLoaded: (texture, filename) => {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
320
|
+
const path = `textures/${filename}`;
|
|
321
|
+
scene === null || scene === void 0 ? void 0 : scene.addTexture(path, texture);
|
|
322
|
+
add(createImageNode(path, filename.replace(/\.[^.]+$/, '')));
|
|
340
323
|
},
|
|
341
324
|
onLoadError: error => {
|
|
342
325
|
console.error('Drop asset error:', error);
|
|
@@ -349,65 +332,58 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
349
332
|
window.removeEventListener('dragover', handleDragOver);
|
|
350
333
|
window.removeEventListener('drop', handleDrop);
|
|
351
334
|
};
|
|
352
|
-
}, [
|
|
353
|
-
|
|
335
|
+
}, [add, isEditMode, enableWindowDrop]);
|
|
336
|
+
const sceneValue = useMemo(() => ({
|
|
354
337
|
get root() {
|
|
355
|
-
return
|
|
356
|
-
},
|
|
357
|
-
getNode,
|
|
358
|
-
getNodeObject,
|
|
359
|
-
getNodeHandle,
|
|
360
|
-
onSceneChange: (listener) => {
|
|
361
|
-
sceneChangeListenersRef.current.add(listener);
|
|
362
|
-
return () => {
|
|
363
|
-
sceneChangeListenersRef.current.delete(listener);
|
|
364
|
-
};
|
|
338
|
+
return getRoot();
|
|
365
339
|
},
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
340
|
+
mode,
|
|
341
|
+
get: getNode,
|
|
342
|
+
getObject,
|
|
343
|
+
getHandle,
|
|
344
|
+
add,
|
|
345
|
+
update,
|
|
346
|
+
remove,
|
|
347
|
+
duplicate,
|
|
348
|
+
move,
|
|
349
|
+
replace,
|
|
350
|
+
addModel: (path, model) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model); },
|
|
351
|
+
addTexture: (path, texture) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture); },
|
|
352
|
+
addSound: (path, sound) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addSound(path, sound); },
|
|
353
|
+
}), [add, duplicate, getHandle, getNode, getObject, getRoot, mode, move, remove, replace, update]);
|
|
354
|
+
const editorRefValue = useMemo(() => (Object.assign(Object.assign({}, sceneValue), { save: getPrefab, load: loadPrefab, undo,
|
|
355
|
+
redo, screenshot: handleScreenshot, exportGLB: handleExportGLB, exportGLBData: handleExportGLBData, clearSelection })), [clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, redo, sceneValue, undo]);
|
|
356
|
+
useImperativeHandle(ref, () => editorRefValue, [editorRefValue]);
|
|
357
|
+
const content = (_jsxs(_Fragment, { children: [isEditMode ? _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }) : null, _jsx(PrefabRoot, { ref: prefabRootRef, store: prefabStore, editMode: isEditMode, selectedId: selectedId, onSelect: setSelection, basePath: basePath, children: children })] }));
|
|
382
358
|
const handleCanvasCreated = useCallback((state) => {
|
|
383
359
|
var _a;
|
|
384
360
|
canvasRef.current = state.gl.domElement;
|
|
385
361
|
(_a = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onCreated) === null || _a === void 0 ? void 0 : _a.call(canvasProps, state);
|
|
386
362
|
}, [canvasProps]);
|
|
387
|
-
return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsxs(EditorContext.Provider, { value: {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
363
|
+
return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsx(EditorRefContext.Provider, { value: editorRefValue, children: _jsxs(EditorContext.Provider, { value: {
|
|
364
|
+
mode,
|
|
365
|
+
setMode: updateMode,
|
|
366
|
+
transformMode,
|
|
367
|
+
setTransformMode,
|
|
368
|
+
scaleSnap,
|
|
369
|
+
setScaleSnap,
|
|
370
|
+
positionSnap,
|
|
371
|
+
setPositionSnap,
|
|
372
|
+
rotationSnap,
|
|
373
|
+
setRotationSnap,
|
|
374
|
+
onFocusNode: isEditMode ? handleFocusNode : undefined,
|
|
375
|
+
onScreenshot: handleScreenshot,
|
|
376
|
+
onExportGLB: handleExportGLB
|
|
377
|
+
}, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] } }, canvasProps, { onCreated: handleCanvasCreated, onPointerMissed: isEditMode
|
|
378
|
+
? (event) => {
|
|
379
|
+
var _a, _b, _c, _d;
|
|
380
|
+
const button = (_c = (_a = event.button) !== null && _a !== void 0 ? _a : (_b = event.sourceEvent) === null || _b === void 0 ? void 0 : _b.button) !== null && _c !== void 0 ? _c : 0;
|
|
381
|
+
if (button === 0 && selectedId) {
|
|
382
|
+
setSelection(null);
|
|
383
|
+
}
|
|
384
|
+
(_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
|
|
407
385
|
}
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
: canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [content, isEditMode ? _jsx(SelectionHelper, { object: transformObject }) : null, isEditMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, enableDamping: false, makeDefault: true }), transformObject && (_jsx(TransformControls, { ref: transformControlsRef, object: transformObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${selectedId}-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleMode, children: isEditMode ? "▶" : "⏸" }), uiPlugins] }), isEditMode && (_jsx(EditorUI, { selectedId: selectedId, setSelectedId: setSelection, getPrefab: getPrefab, onReplacePrefab: (prefab) => loadPrefab(prefab, { resetHistory: true }), onImportPrefab: importPrefab, basePath: basePath, onUndo: undo, onRedo: redo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1 }))] }))] }) });
|
|
386
|
+
: canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [content, isEditMode ? _jsx(SelectionHelper, { object: transformObject }) : null, isEditMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, enableDamping: false, makeDefault: true }), transformObject && (_jsx(TransformControls, { ref: transformControlsRef, object: transformObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${selectedId}-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleMode, children: isEditMode ? "▶" : "⏸" }), uiPlugins] }), isEditMode && (_jsx(EditorUI, { selectedId: selectedId, setSelectedId: setSelection, getPrefab: getPrefab, onReplacePrefab: (prefab) => loadPrefab(prefab, { resetHistory: true }), onImportPrefab: importPrefab, basePath: basePath, onUndo: undo, onRedo: redo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1 }))] }))] }) }) });
|
|
411
387
|
});
|
|
412
388
|
PrefabEditor.displayName = "PrefabEditor";
|
|
413
389
|
export default PrefabEditor;
|
|
@@ -1,31 +1,43 @@
|
|
|
1
|
-
import { type ForwardRefExoticComponent, type RefAttributes } from "react";
|
|
2
1
|
import { Matrix4, Object3D, Texture } from "three";
|
|
3
2
|
import { ThreeEvent } from "@react-three/fiber";
|
|
4
3
|
import { GameObject as GameObjectType, Prefab } from "./types";
|
|
5
4
|
import { LoadedModels } from "../dragdrop";
|
|
6
5
|
import { PrefabStoreApi } from "./prefabStore";
|
|
7
|
-
export
|
|
6
|
+
export declare enum PrefabEditorMode {
|
|
7
|
+
Edit = "edit",
|
|
8
|
+
Play = "play"
|
|
9
|
+
}
|
|
10
|
+
export type PrefabNode = Omit<GameObjectType, "children">;
|
|
11
|
+
export interface Scene {
|
|
8
12
|
root: Object3D | null;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
mode: PrefabEditorMode;
|
|
14
|
+
get(id: string): GameObjectType | null;
|
|
15
|
+
getObject(id: string): Object3D | null;
|
|
16
|
+
getHandle<T = unknown>(id: string, kind: string): T | null;
|
|
17
|
+
add(node: GameObjectType, parentId?: string): GameObjectType;
|
|
18
|
+
update(id: string, fn: (node: PrefabNode) => PrefabNode): void;
|
|
19
|
+
remove(id: string): void;
|
|
20
|
+
duplicate(id: string): string | null;
|
|
21
|
+
move(draggedId: string, targetId: string, position: "before" | "inside"): void;
|
|
22
|
+
replace(prefab: Prefab): void;
|
|
23
|
+
addModel(path: string, model: Object3D): void;
|
|
24
|
+
addTexture(path: string, texture: Texture): void;
|
|
25
|
+
addSound(path: string, sound: AudioBuffer): void;
|
|
14
26
|
}
|
|
27
|
+
export declare const SceneContext: import("react").Context<Scene | null>;
|
|
28
|
+
export declare function useScene(): Scene;
|
|
15
29
|
export interface PrefabRootProps {
|
|
16
30
|
editMode?: boolean;
|
|
17
31
|
data?: Prefab;
|
|
32
|
+
store?: PrefabStoreApi;
|
|
18
33
|
selectedId?: string | null;
|
|
19
34
|
onSelect?: (id: string | null) => void;
|
|
20
35
|
onClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
21
36
|
onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
22
37
|
basePath?: string;
|
|
38
|
+
children?: React.ReactNode;
|
|
23
39
|
}
|
|
24
|
-
|
|
25
|
-
store?: PrefabStoreApi;
|
|
26
|
-
}
|
|
27
|
-
export declare const PrefabRootInternal: ForwardRefExoticComponent<PrefabRootInternalProps & RefAttributes<PrefabRootRef>>;
|
|
28
|
-
export declare const PrefabRoot: ForwardRefExoticComponent<PrefabRootProps & RefAttributes<PrefabRootRef>>;
|
|
40
|
+
export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<Scene>>;
|
|
29
41
|
export declare function GameObjectRenderer(props: RendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
30
42
|
interface RendererProps {
|
|
31
43
|
nodeId: string;
|