react-three-game 0.0.92 → 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 +81 -88
- package/dist/helpers/index.d.ts +0 -3
- package/dist/helpers/index.js +1 -8
- package/dist/index.d.ts +10 -10
- package/dist/index.js +7 -6
- package/dist/tools/prefabeditor/EditorTree.js +10 -14
- package/dist/tools/prefabeditor/EditorUI.js +4 -4
- package/dist/tools/prefabeditor/GameEvents.d.ts +6 -12
- package/dist/tools/prefabeditor/GameEvents.js +0 -8
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +6 -4
- package/dist/tools/prefabeditor/InstanceProvider.js +84 -199
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +12 -21
- package/dist/tools/prefabeditor/PrefabEditor.js +138 -146
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +30 -11
- package/dist/tools/prefabeditor/PrefabRoot.js +182 -139
- package/dist/tools/prefabeditor/assetRuntime.d.ts +9 -13
- package/dist/tools/prefabeditor/assetRuntime.js +13 -13
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +1 -1
- package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +3 -3
- 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 +4 -6
- 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/components/index.js +0 -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/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/usePointerEvents.d.ts +3 -3
- package/dist/tools/prefabeditor/usePointerEvents.js +5 -5
- package/package.json +49 -51
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +0 -26
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +0 -302
- package/dist/tools/prefabeditor/scene.d.ts +0 -70
- package/dist/tools/prefabeditor/scene.js +0 -237
|
@@ -10,11 +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,
|
|
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 PrefabRoot from "./PrefabRoot";
|
|
17
|
-
import { Physics } from "@react-three/rapier";
|
|
16
|
+
import { PrefabEditorMode, PrefabRoot } from "./PrefabRoot";
|
|
18
17
|
import EditorUI from "./EditorUI";
|
|
19
18
|
import { base, toolbar } from "./styles";
|
|
20
19
|
import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, exportGLBData, focusCameraOnObject, regenerateIds } from "./utils";
|
|
@@ -38,12 +37,8 @@ function SelectionHelper({ object }) {
|
|
|
38
37
|
useHelper(object ? objectRef : null, BoxHelper, "cyan");
|
|
39
38
|
return null;
|
|
40
39
|
}
|
|
41
|
-
export var PrefabEditorMode;
|
|
42
|
-
(function (PrefabEditorMode) {
|
|
43
|
-
PrefabEditorMode["Edit"] = "edit";
|
|
44
|
-
PrefabEditorMode["Play"] = "play";
|
|
45
|
-
})(PrefabEditorMode || (PrefabEditorMode = {}));
|
|
46
40
|
export const EditorContext = createContext(null);
|
|
41
|
+
export const EditorRefContext = createContext(null);
|
|
47
42
|
export function useEditorContext() {
|
|
48
43
|
const context = useContext(EditorContext);
|
|
49
44
|
if (!context) {
|
|
@@ -51,6 +46,13 @@ export function useEditorContext() {
|
|
|
51
46
|
}
|
|
52
47
|
return context;
|
|
53
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
|
+
}
|
|
54
56
|
const MAX_HISTORY_LENGTH = 50;
|
|
55
57
|
const HISTORY_DEBOUNCE_MS = 500;
|
|
56
58
|
const DEFAULT_PREFAB = {
|
|
@@ -58,8 +60,7 @@ const DEFAULT_PREFAB = {
|
|
|
58
60
|
name: "New Prefab",
|
|
59
61
|
root: createNode('Root', {}, { id: 'root' })
|
|
60
62
|
};
|
|
61
|
-
const PrefabEditor = forwardRef(({ basePath, initialPrefab,
|
|
62
|
-
var _a, _b;
|
|
63
|
+
const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode = PrefabEditorMode.Edit, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
|
|
63
64
|
const [mode, setMode] = useState(initialMode);
|
|
64
65
|
const [selectedId, setSelectedId] = useState(null);
|
|
65
66
|
const [transformMode, setTransformMode] = useState("translate");
|
|
@@ -70,19 +71,68 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
70
71
|
const [prefabStore] = useState(() => createPrefabStore(startingPrefab));
|
|
71
72
|
const [history, setHistory] = useState([startingPrefab]);
|
|
72
73
|
const [historyIndex, setHistoryIndex] = useState(0);
|
|
73
|
-
const changeOriginRef = useRef(null);
|
|
74
74
|
const historyIndexRef = useRef(0);
|
|
75
|
+
const historyTimeoutRef = useRef(null);
|
|
75
76
|
const prefabRootRef = useRef(null);
|
|
76
77
|
const canvasRef = useRef(null);
|
|
77
78
|
const controlsRef = useRef(null);
|
|
78
79
|
const transformControlsRef = useRef(null);
|
|
79
|
-
const transformProxyRef = useRef(null);
|
|
80
80
|
const onChangeRef = useRef(onChange);
|
|
81
81
|
const isEditMode = mode === PrefabEditorMode.Edit;
|
|
82
82
|
const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
|
|
83
|
-
const
|
|
83
|
+
const getNode = useCallback((nodeId) => { var _a; return (_a = prefabStore.getState().nodesById[nodeId]) !== null && _a !== void 0 ? _a : null; }, [prefabStore]);
|
|
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; }, []);
|
|
84
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; }, []);
|
|
85
|
-
const
|
|
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]);
|
|
86
136
|
onChangeRef.current = onChange;
|
|
87
137
|
const setSelection = useCallback((nodeId) => {
|
|
88
138
|
const nextNode = nodeId ? prefabStore.getState().nodesById[nodeId] : null;
|
|
@@ -108,10 +158,14 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
108
158
|
updateMode(initialMode);
|
|
109
159
|
}, [initialMode, updateMode]);
|
|
110
160
|
const loadPrefab = useCallback((prefab, options) => {
|
|
111
|
-
var _a;
|
|
112
|
-
changeOriginRef.current = (options === null || options === void 0 ? void 0 : options.notifyChange) === false ? "replace-silent" : "replace";
|
|
161
|
+
var _a, _b;
|
|
113
162
|
(_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
|
|
163
|
+
const before = prefabStore.getState();
|
|
114
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
|
+
}
|
|
115
169
|
if (options === null || options === void 0 ? void 0 : options.resetHistory) {
|
|
116
170
|
setSelectedId(null);
|
|
117
171
|
setHistory([prefab]);
|
|
@@ -127,46 +181,12 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
127
181
|
loadPrefab(initialPrefab, { resetHistory: true, notifyChange: false });
|
|
128
182
|
}, [initialPrefab, loadPrefab]);
|
|
129
183
|
useEffect(() => {
|
|
130
|
-
let historyTimeout = null;
|
|
131
|
-
let lastRevision = prefabStore.getState().revision;
|
|
132
|
-
const unsubscribe = prefabStore.subscribe((state) => {
|
|
133
|
-
var _a;
|
|
134
|
-
if (state.revision === lastRevision) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
lastRevision = state.revision;
|
|
138
|
-
const nextPrefab = denormalizePrefab(state);
|
|
139
|
-
const changeOrigin = changeOriginRef.current;
|
|
140
|
-
if (changeOrigin !== "replace-silent") {
|
|
141
|
-
(_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, nextPrefab);
|
|
142
|
-
}
|
|
143
|
-
if (historyTimeout) {
|
|
144
|
-
clearTimeout(historyTimeout);
|
|
145
|
-
historyTimeout = null;
|
|
146
|
-
}
|
|
147
|
-
if (changeOrigin || !isEditMode) {
|
|
148
|
-
changeOriginRef.current = null;
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
historyTimeout = setTimeout(() => {
|
|
152
|
-
const currentHistoryIndex = historyIndexRef.current;
|
|
153
|
-
setHistory(prev => {
|
|
154
|
-
const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
|
|
155
|
-
return nextHistory.length > MAX_HISTORY_LENGTH ? nextHistory.slice(1) : nextHistory;
|
|
156
|
-
});
|
|
157
|
-
const nextHistoryIndex = Math.min(currentHistoryIndex + 1, MAX_HISTORY_LENGTH - 1);
|
|
158
|
-
historyIndexRef.current = nextHistoryIndex;
|
|
159
|
-
setHistoryIndex(nextHistoryIndex);
|
|
160
|
-
historyTimeout = null;
|
|
161
|
-
}, HISTORY_DEBOUNCE_MS);
|
|
162
|
-
});
|
|
163
184
|
return () => {
|
|
164
|
-
if (
|
|
165
|
-
clearTimeout(
|
|
185
|
+
if (historyTimeoutRef.current) {
|
|
186
|
+
clearTimeout(historyTimeoutRef.current);
|
|
166
187
|
}
|
|
167
|
-
unsubscribe();
|
|
168
188
|
};
|
|
169
|
-
}, [
|
|
189
|
+
}, []);
|
|
170
190
|
useEffect(() => {
|
|
171
191
|
if (!selectedId)
|
|
172
192
|
return;
|
|
@@ -177,54 +197,19 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
177
197
|
});
|
|
178
198
|
return () => unsubscribe();
|
|
179
199
|
}, [prefabStore, selectedId]);
|
|
180
|
-
const selectedNode = selectedId ? (_a = prefabStore.getState().nodesById[selectedId]) !== null && _a !== void 0 ? _a : null : null;
|
|
181
200
|
const selectedObject = selectedId ? getObject(selectedId) : null;
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
? (selectedHasPhysics ? transformProxyRef.current : selectedObject)
|
|
201
|
+
const transformObject = isEditMode && selectedObject
|
|
202
|
+
&& isObjectAttachedToRoot(getRoot(), selectedObject)
|
|
203
|
+
? selectedObject
|
|
186
204
|
: null;
|
|
187
|
-
useLayoutEffect(() => {
|
|
188
|
-
if (!isEditMode || !selectedHasPhysics || !selectedObject || !transformProxyRef.current) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
selectedObject.updateMatrixWorld(true);
|
|
192
|
-
transformProxyRef.current.matrixAutoUpdate = true;
|
|
193
|
-
selectedObject.matrixWorld.decompose(transformProxyRef.current.position, transformProxyRef.current.quaternion, transformProxyRef.current.scale);
|
|
194
|
-
transformProxyRef.current.updateMatrix();
|
|
195
|
-
transformProxyRef.current.updateMatrixWorld(true);
|
|
196
|
-
}, [isEditMode, selectedHasPhysics, selectedId, selectedObject]);
|
|
197
|
-
const addNode = useCallback((node, options) => {
|
|
198
|
-
var _a;
|
|
199
|
-
const { addChild, rootId } = prefabStore.getState();
|
|
200
|
-
addChild((_a = options === null || options === void 0 ? void 0 : options.parentId) !== null && _a !== void 0 ? _a : rootId, node);
|
|
201
|
-
if ((options === null || options === void 0 ? void 0 : options.select) !== false) {
|
|
202
|
-
setSelection(node.id);
|
|
203
|
-
}
|
|
204
|
-
return node;
|
|
205
|
-
}, [prefabStore, setSelection]);
|
|
206
205
|
const importPrefab = useCallback((prefab) => {
|
|
207
|
-
|
|
208
|
-
}, [
|
|
209
|
-
const addModel = useCallback((path, model, options) => {
|
|
210
|
-
var _a;
|
|
211
|
-
const node = createModelNode(path, options === null || options === void 0 ? void 0 : options.name);
|
|
212
|
-
addNode(node, options);
|
|
213
|
-
(_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model);
|
|
214
|
-
return node;
|
|
215
|
-
}, [addNode]);
|
|
216
|
-
const addTexture = useCallback((path, texture, options) => {
|
|
217
|
-
var _a;
|
|
218
|
-
const node = createImageNode(path, options === null || options === void 0 ? void 0 : options.name);
|
|
219
|
-
addNode(node, options);
|
|
220
|
-
(_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture);
|
|
221
|
-
return node;
|
|
222
|
-
}, [addNode]);
|
|
206
|
+
add(regenerateIds(prefab.root));
|
|
207
|
+
}, [add]);
|
|
223
208
|
const applyHistory = (index) => {
|
|
224
|
-
var _a;
|
|
225
|
-
changeOriginRef.current = "history";
|
|
209
|
+
var _a, _b;
|
|
226
210
|
(_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
|
|
227
211
|
prefabStore.getState().replacePrefab(history[index]);
|
|
212
|
+
(_b = onChangeRef.current) === null || _b === void 0 ? void 0 : _b.call(onChangeRef, history[index]);
|
|
228
213
|
historyIndexRef.current = index;
|
|
229
214
|
setHistoryIndex(index);
|
|
230
215
|
setSelectedId(prev => prev && prefabStore.getState().nodesById[prev] ? prev : null);
|
|
@@ -272,18 +257,18 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
272
257
|
}), [setSelection]);
|
|
273
258
|
const handleExportGLB = useCallback((...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
|
|
274
259
|
yield clearSelection();
|
|
275
|
-
const rootObject =
|
|
260
|
+
const rootObject = getRoot();
|
|
276
261
|
if (!rootObject)
|
|
277
262
|
return;
|
|
278
263
|
return exportGLBFile(rootObject, Object.assign({ filename: `${prefabStore.getState().prefabName || 'prefab'}.glb` }, options));
|
|
279
|
-
}), [clearSelection,
|
|
264
|
+
}), [clearSelection, getRoot, prefabStore]);
|
|
280
265
|
const handleExportGLBData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
281
266
|
yield clearSelection();
|
|
282
|
-
const rootObject =
|
|
267
|
+
const rootObject = getRoot();
|
|
283
268
|
if (!rootObject)
|
|
284
269
|
return;
|
|
285
270
|
return exportGLBData(rootObject);
|
|
286
|
-
}), [clearSelection,
|
|
271
|
+
}), [clearSelection, getRoot]);
|
|
287
272
|
const handleFocusNode = useCallback((nodeId) => {
|
|
288
273
|
const object = getObject(nodeId);
|
|
289
274
|
const controls = controlsRef.current;
|
|
@@ -295,13 +280,13 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
295
280
|
const handleTransformChange = () => {
|
|
296
281
|
if (!selectedId)
|
|
297
282
|
return;
|
|
298
|
-
const object =
|
|
283
|
+
const object = getObject(selectedId);
|
|
299
284
|
if (!object)
|
|
300
285
|
return;
|
|
301
286
|
const parentWorld = computeParentWorldMatrix(prefabStore.getState(), selectedId);
|
|
302
287
|
const local = parentWorld.clone().invert().multiply(object.matrixWorld);
|
|
303
288
|
const { position, rotation, scale } = decompose(local);
|
|
304
|
-
|
|
289
|
+
update(selectedId, node => {
|
|
305
290
|
var _a;
|
|
306
291
|
const entry = findComponentEntry(node, "Transform");
|
|
307
292
|
const key = (_a = entry === null || entry === void 0 ? void 0 : entry[0]) !== null && _a !== void 0 ? _a : "transform";
|
|
@@ -324,16 +309,17 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
324
309
|
e.preventDefault();
|
|
325
310
|
e.stopPropagation();
|
|
326
311
|
const files = ((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) ? Array.from(e.dataTransfer.files) : [];
|
|
312
|
+
const scene = prefabRootRef.current;
|
|
327
313
|
void loadFiles(files, {
|
|
328
314
|
onModelLoaded: (model, filename) => {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
315
|
+
const path = `models/${filename}`;
|
|
316
|
+
scene === null || scene === void 0 ? void 0 : scene.addModel(path, model);
|
|
317
|
+
add(createModelNode(path, filename.replace(/\.[^.]+$/, '')));
|
|
332
318
|
},
|
|
333
319
|
onTextureLoaded: (texture, filename) => {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
320
|
+
const path = `textures/${filename}`;
|
|
321
|
+
scene === null || scene === void 0 ? void 0 : scene.addTexture(path, texture);
|
|
322
|
+
add(createImageNode(path, filename.replace(/\.[^.]+$/, '')));
|
|
337
323
|
},
|
|
338
324
|
onLoadError: error => {
|
|
339
325
|
console.error('Drop asset error:', error);
|
|
@@ -346,52 +332,58 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
346
332
|
window.removeEventListener('dragover', handleDragOver);
|
|
347
333
|
window.removeEventListener('drop', handleDrop);
|
|
348
334
|
};
|
|
349
|
-
}, [
|
|
350
|
-
|
|
351
|
-
root
|
|
352
|
-
|
|
335
|
+
}, [add, isEditMode, enableWindowDrop]);
|
|
336
|
+
const sceneValue = useMemo(() => ({
|
|
337
|
+
get root() {
|
|
338
|
+
return getRoot();
|
|
339
|
+
},
|
|
340
|
+
mode,
|
|
341
|
+
get: getNode,
|
|
353
342
|
getObject,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}), [
|
|
365
|
-
const
|
|
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 })] }));
|
|
366
358
|
const handleCanvasCreated = useCallback((state) => {
|
|
367
359
|
var _a;
|
|
368
360
|
canvasRef.current = state.gl.domElement;
|
|
369
361
|
(_a = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onCreated) === null || _a === void 0 ? void 0 : _a.call(canvasProps, state);
|
|
370
362
|
}, [canvasProps]);
|
|
371
|
-
return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsxs(EditorContext.Provider, { value: {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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);
|
|
391
385
|
}
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
: canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [physics ? (_jsx(Physics, { colliders: false, debug: isEditMode, paused: isEditMode, children: content })) : content, _jsx("group", { ref: transformProxyRef, visible: false }), 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 }))] }))] }) }) });
|
|
395
387
|
});
|
|
396
388
|
PrefabEditor.displayName = "PrefabEditor";
|
|
397
389
|
export default PrefabEditor;
|
|
@@ -1,35 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Matrix4, Object3D, Texture } from "three";
|
|
2
2
|
import { ThreeEvent } from "@react-three/fiber";
|
|
3
3
|
import { GameObject as GameObjectType, Prefab } from "./types";
|
|
4
4
|
import { LoadedModels } from "../dragdrop";
|
|
5
5
|
import { PrefabStoreApi } from "./prefabStore";
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
getRigidBody: (nodeId: string) => any;
|
|
10
|
-
addModel: (path: string, model: Object3D) => void;
|
|
11
|
-
addTexture: (path: string, texture: Texture) => void;
|
|
12
|
-
addSound: (path: string, sound: AudioBuffer) => void;
|
|
6
|
+
export declare enum PrefabEditorMode {
|
|
7
|
+
Edit = "edit",
|
|
8
|
+
Play = "play"
|
|
13
9
|
}
|
|
10
|
+
export type PrefabNode = Omit<GameObjectType, "children">;
|
|
11
|
+
export interface Scene {
|
|
12
|
+
root: Object3D | null;
|
|
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;
|
|
26
|
+
}
|
|
27
|
+
export declare const SceneContext: import("react").Context<Scene | null>;
|
|
28
|
+
export declare function useScene(): Scene;
|
|
14
29
|
export interface PrefabRootProps {
|
|
15
30
|
editMode?: boolean;
|
|
16
31
|
data?: Prefab;
|
|
17
32
|
store?: PrefabStoreApi;
|
|
18
33
|
selectedId?: string | null;
|
|
19
34
|
onSelect?: (id: string | null) => void;
|
|
20
|
-
onClick?: (event: ThreeEvent<PointerEvent>,
|
|
35
|
+
onClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
36
|
+
onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
21
37
|
basePath?: string;
|
|
38
|
+
children?: React.ReactNode;
|
|
22
39
|
}
|
|
23
|
-
export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<
|
|
40
|
+
export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<Scene>>;
|
|
24
41
|
export declare function GameObjectRenderer(props: RendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
25
42
|
interface RendererProps {
|
|
26
43
|
nodeId: string;
|
|
27
44
|
selectedId?: string | null;
|
|
28
45
|
onSelect?: (id: string) => void;
|
|
29
|
-
onClick?: (event: ThreeEvent<PointerEvent>,
|
|
46
|
+
onClick?: (event: ThreeEvent<PointerEvent>, nodeId: string, object: Object3D | null) => void;
|
|
47
|
+
onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
30
48
|
registerRef: (id: string, obj: Object3D | null) => void;
|
|
31
49
|
loadedModels: LoadedModels;
|
|
32
50
|
editMode?: boolean;
|
|
33
51
|
parentMatrix?: Matrix4;
|
|
52
|
+
isVisible?: boolean;
|
|
34
53
|
}
|
|
35
54
|
export default PrefabRoot;
|