react-three-game 0.0.85 → 0.0.87
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 +87 -35
- package/dist/index.d.ts +5 -7
- package/dist/index.js +2 -4
- package/dist/tools/prefabeditor/GameEvents.d.ts +36 -117
- package/dist/tools/prefabeditor/GameEvents.js +44 -96
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +0 -4
- package/dist/tools/prefabeditor/InstanceProvider.js +13 -44
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +7 -2
- package/dist/tools/prefabeditor/PrefabEditor.js +13 -24
- package/dist/tools/prefabeditor/PrefabRoot.js +93 -44
- package/dist/tools/prefabeditor/{runtime.d.ts → assetRuntime.d.ts} +0 -25
- package/dist/tools/prefabeditor/assetRuntime.js +37 -0
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +4 -2
- package/dist/tools/prefabeditor/components/CameraComponent.js +1 -1
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +0 -3
- package/dist/tools/prefabeditor/components/DataComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/DataComponent.js +87 -0
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/EnvironmentComponent.js +1 -1
- package/dist/tools/prefabeditor/components/GeometryComponent.js +4 -2
- package/dist/tools/prefabeditor/components/Input.d.ts +2 -13
- package/dist/tools/prefabeditor/components/Input.js +0 -55
- package/dist/tools/prefabeditor/components/MaterialComponent.js +1 -1
- package/dist/tools/prefabeditor/components/ModelComponent.js +3 -3
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +4 -0
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +64 -130
- package/dist/tools/prefabeditor/components/PointLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/SoundComponent.js +18 -11
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/index.js +2 -2
- package/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/types.js +18 -0
- package/dist/tools/prefabeditor/usePointerEvents.d.ts +27 -0
- package/dist/tools/prefabeditor/usePointerEvents.js +52 -0
- package/package.json +1 -1
- package/dist/tools/prefabeditor/components/ClickComponent.d.ts +0 -3
- package/dist/tools/prefabeditor/components/ClickComponent.js +0 -52
- package/dist/tools/prefabeditor/runtime.js +0 -184
|
@@ -15,8 +15,7 @@ import { Merged, useHelper } from '@react-three/drei';
|
|
|
15
15
|
import { InstancedRigidBodies } from "@react-three/rapier";
|
|
16
16
|
import { ActiveCollisionTypes } from "@dimforge/rapier3d-compat";
|
|
17
17
|
import { Mesh, Matrix4, Vector3, Quaternion, Euler, BoxHelper } from "three";
|
|
18
|
-
import {
|
|
19
|
-
import { useClickValid } from "./useClickValid";
|
|
18
|
+
import { usePointerEvents } from "./usePointerEvents";
|
|
20
19
|
export const DEFAULT_REPEAT_AXES = [{ axis: 'x', count: 1, offset: 1 }];
|
|
21
20
|
export function normalizeRepeatAxes(value) {
|
|
22
21
|
if (!Array.isArray(value)) {
|
|
@@ -103,32 +102,9 @@ function hasPhysics(instance) {
|
|
|
103
102
|
function getColliderType(physics) {
|
|
104
103
|
return physics.colliders || (physics.type === 'fixed' ? 'trimesh' : 'hull');
|
|
105
104
|
}
|
|
106
|
-
function emitPhysicsEvent(sourceId, eventName, payload) {
|
|
107
|
-
if (!eventName)
|
|
108
|
-
return;
|
|
109
|
-
gameEvents.emit(eventName, {
|
|
110
|
-
sourceEntityId: sourceId,
|
|
111
|
-
targetEntityId: getEntityIdFromRigidBody(payload.other.rigidBody),
|
|
112
|
-
targetRigidBody: payload.other.rigidBody,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
function emitClick(sourceId, instanceId, eventName, event) {
|
|
116
|
-
gameEvents.emit(eventName, {
|
|
117
|
-
sourceEntityId: sourceId,
|
|
118
|
-
instanceEntityId: instanceId && instanceId !== sourceId ? instanceId : undefined,
|
|
119
|
-
point: [event.point.x, event.point.y, event.point.z],
|
|
120
|
-
button: event.button,
|
|
121
|
-
altKey: event.nativeEvent.altKey,
|
|
122
|
-
ctrlKey: event.nativeEvent.ctrlKey,
|
|
123
|
-
metaKey: event.nativeEvent.metaKey,
|
|
124
|
-
shiftKey: event.nativeEvent.shiftKey,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
105
|
function instanceEquals(a, b) {
|
|
128
106
|
return a.id === b.id &&
|
|
129
107
|
a.sourceId === b.sourceId &&
|
|
130
|
-
a.clickable === b.clickable &&
|
|
131
|
-
a.clickEventName === b.clickEventName &&
|
|
132
108
|
a.locked === b.locked &&
|
|
133
109
|
a.meshPath === b.meshPath &&
|
|
134
110
|
arrayEquals(a.position, b.position) &&
|
|
@@ -245,7 +221,7 @@ function InstancedRigidGroup({ group, modelKey, partCount, flatMeshes, onSelect,
|
|
|
245
221
|
const rigidBodiesRef = useRef(null);
|
|
246
222
|
const instances = useMemo(() => group.instances.filter(hasPhysics).map(inst => {
|
|
247
223
|
const _a = inst.physics, { activeCollisionTypes: _activeCollisionTypes, colliders: _colliders, userData } = _a, rigidBodyProps = __rest(_a, ["activeCollisionTypes", "colliders", "userData"]);
|
|
248
|
-
return Object.assign(Object.assign({ key: inst.id, position: inst.position, rotation: inst.rotation, scale: inst.scale }, rigidBodyProps), { colliders: getColliderType(inst.physics), userData: Object.assign(Object.assign({}, userData), { entityId: inst.sourceId })
|
|
224
|
+
return Object.assign(Object.assign({ key: inst.id, position: inst.position, rotation: inst.rotation, scale: inst.scale }, rigidBodyProps), { colliders: getColliderType(inst.physics), userData: Object.assign(Object.assign({}, userData), { entityId: inst.sourceId }) });
|
|
249
225
|
}), [group.instances]);
|
|
250
226
|
// Apply scale to visual meshes (InstancedRigidBodies only scales colliders, not visuals)
|
|
251
227
|
useEffect(() => {
|
|
@@ -317,12 +293,8 @@ function InstancedRigidGroup({ group, modelKey, partCount, flatMeshes, onSelect,
|
|
|
317
293
|
onSelect(instance.sourceId);
|
|
318
294
|
return;
|
|
319
295
|
}
|
|
320
|
-
if (!instance.clickable)
|
|
321
|
-
return;
|
|
322
|
-
e.stopPropagation();
|
|
323
|
-
emitClick(instance.sourceId, instance.id, instance.clickEventName || 'click', e);
|
|
324
296
|
};
|
|
325
|
-
const shouldHandleClick = editMode
|
|
297
|
+
const shouldHandleClick = editMode;
|
|
326
298
|
// Add key to force remount when instance count changes significantly (helps with cleanup)
|
|
327
299
|
const rigidBodyKey = `rb_${modelKey}_${group.instances.map(inst => `${inst.id}:${getPhysicsSignature(inst.physics)}`).join('|')}`;
|
|
328
300
|
return (_jsx(InstancedRigidBodies, { ref: rigidBodiesRef, instances: instances, children: Array.from({ length: partCount }).map((_, i) => {
|
|
@@ -344,14 +316,15 @@ function InstanceGroupItem({ instance, InstanceComponents, onSelect, registerRef
|
|
|
344
316
|
const isLocked = Boolean(instance.locked);
|
|
345
317
|
const isSelected = selectedId === instance.id || selectedId === instance.sourceId;
|
|
346
318
|
const canSelect = editMode && !isLocked;
|
|
347
|
-
const canClick =
|
|
348
|
-
const pointerHandlers =
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
319
|
+
const canClick = false;
|
|
320
|
+
const pointerHandlers = usePointerEvents({
|
|
321
|
+
enabled: canSelect || canClick,
|
|
322
|
+
entity: instance,
|
|
323
|
+
onClick: () => {
|
|
324
|
+
if (editMode) {
|
|
325
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(instance.sourceId);
|
|
326
|
+
}
|
|
327
|
+
},
|
|
355
328
|
});
|
|
356
329
|
// Use BoxHelper when object is selected in edit mode
|
|
357
330
|
useHelper(editMode && isSelected ? groupRef : null, BoxHelper, 'cyan');
|
|
@@ -370,7 +343,7 @@ export function useInstanceCheck(id) {
|
|
|
370
343
|
return (_a = ctx === null || ctx === void 0 ? void 0 : ctx.hasInstance(id)) !== null && _a !== void 0 ? _a : false;
|
|
371
344
|
}
|
|
372
345
|
// GameInstance component: registers an instance for batch rendering (renders nothing itself)
|
|
373
|
-
export const GameInstance = React.forwardRef(({ id, sourceId,
|
|
346
|
+
export const GameInstance = React.forwardRef(({ id, sourceId, modelUrl, locked = false, position, rotation, scale, physics = undefined, }, ref) => {
|
|
374
347
|
const ctx = useContext(GameInstanceContext);
|
|
375
348
|
const addInstance = ctx === null || ctx === void 0 ? void 0 : ctx.addInstance;
|
|
376
349
|
const removeInstance = ctx === null || ctx === void 0 ? void 0 : ctx.removeInstance;
|
|
@@ -381,8 +354,6 @@ export const GameInstance = React.forwardRef(({ id, sourceId, clickable = false,
|
|
|
381
354
|
const instance = useMemo(() => ({
|
|
382
355
|
id,
|
|
383
356
|
sourceId: sourceId !== null && sourceId !== void 0 ? sourceId : id,
|
|
384
|
-
clickable,
|
|
385
|
-
clickEventName,
|
|
386
357
|
locked,
|
|
387
358
|
meshPath: modelUrl,
|
|
388
359
|
position,
|
|
@@ -392,8 +363,6 @@ export const GameInstance = React.forwardRef(({ id, sourceId, clickable = false,
|
|
|
392
363
|
}), [
|
|
393
364
|
id,
|
|
394
365
|
sourceId,
|
|
395
|
-
clickable,
|
|
396
|
-
clickEventName,
|
|
397
366
|
locked,
|
|
398
367
|
modelUrl,
|
|
399
368
|
positionX,
|
|
@@ -2,18 +2,23 @@ import GameCanvas from "../../shared/GameCanvas";
|
|
|
2
2
|
import { Object3D, Texture } from "three";
|
|
3
3
|
import { GameObject, Prefab } from "./types";
|
|
4
4
|
import type { ExportGLBOptions } from "./utils";
|
|
5
|
-
import { type
|
|
5
|
+
import { type PrefabStoreApi } from "./prefabStore";
|
|
6
|
+
import type { SpawnOptions } from "./scene";
|
|
6
7
|
export interface PrefabEditorRef {
|
|
8
|
+
root: Object3D | null;
|
|
9
|
+
store: PrefabStoreApi;
|
|
10
|
+
getObject: (nodeId: string) => Object3D | null;
|
|
11
|
+
getRigidBody: (nodeId: string) => any;
|
|
7
12
|
screenshot: () => void;
|
|
8
13
|
exportGLB: (options?: ExportGLBOptions) => Promise<ArrayBuffer | undefined>;
|
|
9
14
|
exportGLBData: () => Promise<ArrayBuffer | undefined>;
|
|
10
15
|
clearSelection: () => Promise<void>;
|
|
11
16
|
save: () => Prefab;
|
|
12
|
-
scene: Scene;
|
|
13
17
|
load: (prefab: Prefab, options?: {
|
|
14
18
|
resetHistory?: boolean;
|
|
15
19
|
notifyChange?: boolean;
|
|
16
20
|
}) => void;
|
|
21
|
+
addNode: (node: GameObject, options?: SpawnOptions) => GameObject;
|
|
17
22
|
addModel: (path: string, model: Object3D, options?: SpawnOptions) => GameObject;
|
|
18
23
|
addTexture: (path: string, texture: Texture, options?: SpawnOptions) => GameObject;
|
|
19
24
|
}
|
|
@@ -10,7 +10,7 @@ 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 } from "@react-three/drei";
|
|
12
12
|
import GameCanvas from "../../shared/GameCanvas";
|
|
13
|
-
import { useCallback, useEffect,
|
|
13
|
+
import { useCallback, useEffect, useReducer, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
|
|
14
14
|
import { findComponentEntry } from "./types";
|
|
15
15
|
import PrefabRoot from "./PrefabRoot";
|
|
16
16
|
import { Physics } from "@react-three/rapier";
|
|
@@ -20,7 +20,6 @@ import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, export
|
|
|
20
20
|
import { loadFiles } from "../dragdrop";
|
|
21
21
|
import { denormalizePrefab, createImageNode, createModelNode, createNode } from './prefab';
|
|
22
22
|
import { createPrefabStore, PrefabStoreProvider } from "./prefabStore";
|
|
23
|
-
import { createScene } from "./scene";
|
|
24
23
|
function isObjectAttachedToRoot(root, object) {
|
|
25
24
|
if (!root || !object)
|
|
26
25
|
return false;
|
|
@@ -53,7 +52,6 @@ const DEFAULT_PREFAB = {
|
|
|
53
52
|
root: createNode('Root', {}, { id: 'root' })
|
|
54
53
|
};
|
|
55
54
|
const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode: initialMode = PrefabEditorMode.Edit, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
|
|
56
|
-
var _a, _b;
|
|
57
55
|
const [mode, setMode] = useState(initialMode);
|
|
58
56
|
const [selectedId, setSelectedId] = useState(null);
|
|
59
57
|
const [transformMode, setTransformMode] = useState("translate");
|
|
@@ -73,6 +71,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
73
71
|
const onChangeRef = useRef(onChange);
|
|
74
72
|
const isEditMode = mode === PrefabEditorMode.Edit;
|
|
75
73
|
const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
|
|
74
|
+
const getRootObject = useCallback(() => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null; }, []);
|
|
76
75
|
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; }, []);
|
|
77
76
|
const getRigidBody = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getRigidBody(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
78
77
|
const handleObjectRefChange = useCallback((nodeId) => {
|
|
@@ -173,7 +172,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
173
172
|
return () => unsubscribe();
|
|
174
173
|
}, [prefabStore, selectedId]);
|
|
175
174
|
const selectedObject = selectedId ? getObject(selectedId) : null;
|
|
176
|
-
const transformObject = isObjectAttachedToRoot((
|
|
175
|
+
const transformObject = isObjectAttachedToRoot(getRootObject(), selectedObject)
|
|
177
176
|
? selectedObject
|
|
178
177
|
: null;
|
|
179
178
|
const addNode = useCallback((node, options) => {
|
|
@@ -251,21 +250,19 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
251
250
|
});
|
|
252
251
|
}), [setSelection]);
|
|
253
252
|
const handleExportGLB = useCallback((...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
|
|
254
|
-
var _a;
|
|
255
253
|
yield clearSelection();
|
|
256
|
-
const rootObject = (
|
|
254
|
+
const rootObject = getRootObject();
|
|
257
255
|
if (!rootObject)
|
|
258
256
|
return;
|
|
259
257
|
return exportGLBFile(rootObject, Object.assign({ filename: `${prefabStore.getState().prefabName || 'prefab'}.glb` }, options));
|
|
260
|
-
}), [clearSelection, prefabStore]);
|
|
258
|
+
}), [clearSelection, getRootObject, prefabStore]);
|
|
261
259
|
const handleExportGLBData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
262
|
-
var _a;
|
|
263
260
|
yield clearSelection();
|
|
264
|
-
const rootObject = (
|
|
261
|
+
const rootObject = getRootObject();
|
|
265
262
|
if (!rootObject)
|
|
266
263
|
return;
|
|
267
264
|
return exportGLBData(rootObject);
|
|
268
|
-
}), [clearSelection]);
|
|
265
|
+
}), [clearSelection, getRootObject]);
|
|
269
266
|
const handleFocusNode = useCallback((nodeId) => {
|
|
270
267
|
const object = getObject(nodeId);
|
|
271
268
|
const controls = controlsRef.current;
|
|
@@ -274,18 +271,6 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
274
271
|
return;
|
|
275
272
|
focusCameraOnObject(object, camera, controls.target, () => { var _a; return (_a = controls.update) === null || _a === void 0 ? void 0 : _a.call(controls); });
|
|
276
273
|
}, [getObject]);
|
|
277
|
-
const scene = useMemo(() => createScene({
|
|
278
|
-
getRootId: () => prefabStore.getState().rootId,
|
|
279
|
-
getNode: (id) => { var _a; return (_a = prefabStore.getState().nodesById[id]) !== null && _a !== void 0 ? _a : null; },
|
|
280
|
-
getChildIds: (id) => { var _a; return (_a = prefabStore.getState().childIdsById[id]) !== null && _a !== void 0 ? _a : []; },
|
|
281
|
-
getParentId: (id) => { var _a; return (_a = prefabStore.getState().parentIdById[id]) !== null && _a !== void 0 ? _a : null; },
|
|
282
|
-
updateNode: (id, update) => prefabStore.getState().updateNode(id, update),
|
|
283
|
-
updateNodes: (updates) => prefabStore.getState().updateNodes(Object.entries(updates).map(([id, update]) => ({ id, update }))),
|
|
284
|
-
addNode: (node, options) => addNode(node, options).id,
|
|
285
|
-
removeNode: (id) => prefabStore.getState().deleteNode(id),
|
|
286
|
-
getObject,
|
|
287
|
-
getRigidBody,
|
|
288
|
-
}), [addNode, getObject, getRigidBody, prefabStore]);
|
|
289
274
|
const handleTransformChange = () => {
|
|
290
275
|
if (!selectedId)
|
|
291
276
|
return;
|
|
@@ -342,16 +327,20 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
342
327
|
};
|
|
343
328
|
}, [addModel, addTexture, isEditMode, enableWindowDrop]);
|
|
344
329
|
useImperativeHandle(ref, () => ({
|
|
330
|
+
root: getRootObject(),
|
|
331
|
+
store: prefabStore,
|
|
332
|
+
getObject,
|
|
333
|
+
getRigidBody,
|
|
345
334
|
screenshot: handleScreenshot,
|
|
346
335
|
exportGLB: handleExportGLB,
|
|
347
336
|
exportGLBData: handleExportGLBData,
|
|
348
337
|
clearSelection,
|
|
349
338
|
save: getPrefab,
|
|
350
|
-
scene,
|
|
351
339
|
load: loadPrefab,
|
|
340
|
+
addNode,
|
|
352
341
|
addModel,
|
|
353
342
|
addTexture
|
|
354
|
-
}), [addModel, addTexture, clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab,
|
|
343
|
+
}), [addModel, addNode, addTexture, clearSelection, getObject, getPrefab, getRigidBody, getRootObject, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, prefabStore]);
|
|
355
344
|
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, onObjectRefChange: handleObjectRefChange, basePath: basePath }), children] }));
|
|
356
345
|
const handleCanvasCreated = useCallback((state) => {
|
|
357
346
|
var _a;
|
|
@@ -13,10 +13,9 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
13
13
|
import { useHelper } from "@react-three/drei";
|
|
14
14
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
15
15
|
import { BoxHelper, Euler, Matrix4, } from "three";
|
|
16
|
-
import { useFrame } from "@react-three/fiber";
|
|
17
16
|
import { useStore } from "zustand";
|
|
18
17
|
import { useClickValid } from "./useClickValid";
|
|
19
|
-
import { findComponent } from "./types";
|
|
18
|
+
import { findComponent, getNodeUserData } from "./types";
|
|
20
19
|
import { getComponentDef, getComponentAssetRefs, registerComponent } from "./components/ComponentRegistry";
|
|
21
20
|
import { builtinComponents } from "./components";
|
|
22
21
|
import { loadModel, loadSound, loadTexture } from "../dragdrop";
|
|
@@ -24,7 +23,8 @@ import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties, u
|
|
|
24
23
|
import { composeTransform, decompose } from "./utils";
|
|
25
24
|
import { isPhysicsProps } from "./components/PhysicsComponent";
|
|
26
25
|
import { createPrefabStore, PrefabStoreProvider, useOptionalPrefabStoreApi, usePrefabChildIds, usePrefabNode, usePrefabRootId } from "./prefabStore";
|
|
27
|
-
import { AssetRuntimeContext, EntityRuntimeScope
|
|
26
|
+
import { AssetRuntimeContext, EntityRuntimeScope } from "./assetRuntime";
|
|
27
|
+
import { gameEvents } from "./GameEvents";
|
|
28
28
|
import { sound as soundManager } from "../../helpers/SoundManager";
|
|
29
29
|
builtinComponents.forEach(registerComponent);
|
|
30
30
|
const IDENTITY = new Matrix4();
|
|
@@ -45,6 +45,30 @@ function isNodeReady(node, loadedModels) {
|
|
|
45
45
|
return true;
|
|
46
46
|
return Boolean(loadedModels[model.properties.filename]);
|
|
47
47
|
}
|
|
48
|
+
function getNodeClickEventName(node) {
|
|
49
|
+
var _a;
|
|
50
|
+
const clickComponents = [
|
|
51
|
+
findComponent(node, 'BufferGeometry'),
|
|
52
|
+
findComponent(node, 'Geometry'),
|
|
53
|
+
];
|
|
54
|
+
for (const component of clickComponents) {
|
|
55
|
+
if (!((_a = component === null || component === void 0 ? void 0 : component.properties) === null || _a === void 0 ? void 0 : _a.emitClickEvent))
|
|
56
|
+
continue;
|
|
57
|
+
const eventName = component.properties.clickEventName;
|
|
58
|
+
if (typeof eventName === 'string' && eventName.trim()) {
|
|
59
|
+
return eventName.trim();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function getNodeMetadataProps(node) {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
|
|
67
|
+
return {
|
|
68
|
+
name: nodeName,
|
|
69
|
+
userData: Object.assign(Object.assign({ prefabNodeId: node.id }, (nodeName ? { prefabNodeName: nodeName } : {})), getNodeUserData(node)),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
48
72
|
export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick, onObjectRefChange, basePath = "" }, ref) => {
|
|
49
73
|
var _a;
|
|
50
74
|
const [models, setModels] = useState({});
|
|
@@ -94,29 +118,13 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
94
118
|
setInjectedSounds(prev => (Object.assign(Object.assign({}, prev), { [path]: sound })));
|
|
95
119
|
},
|
|
96
120
|
}), [getObject]);
|
|
97
|
-
const runtimeEngine = useMemo(() => createRuntimeEngine({
|
|
98
|
-
store: resolvedStore,
|
|
99
|
-
getObject,
|
|
100
|
-
getRigidBody,
|
|
101
|
-
}), [resolvedStore, getObject, getRigidBody]);
|
|
102
121
|
const registerRef = useCallback((id, obj) => {
|
|
103
122
|
objectRefs.current[id] = obj;
|
|
104
|
-
runtimeEngine.invalidate();
|
|
105
123
|
onObjectRefChange === null || onObjectRefChange === void 0 ? void 0 : onObjectRefChange(id, obj);
|
|
106
|
-
}, [onObjectRefChange
|
|
124
|
+
}, [onObjectRefChange]);
|
|
107
125
|
const registerRigidBodyRef = useCallback((id, rb) => {
|
|
108
126
|
rigidBodyRefs.current.set(id, rb);
|
|
109
|
-
|
|
110
|
-
}, [runtimeEngine]);
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
runtimeEngine.setActive(!editMode);
|
|
113
|
-
}, [editMode, runtimeEngine]);
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
return () => runtimeEngine.dispose();
|
|
116
|
-
}, [runtimeEngine]);
|
|
117
|
-
useFrame((_, dt) => {
|
|
118
|
-
runtimeEngine.tick(dt);
|
|
119
|
-
});
|
|
127
|
+
}, []);
|
|
120
128
|
useEffect(() => {
|
|
121
129
|
if (usesOwnedStore && data) {
|
|
122
130
|
resolvedStore.getState().replacePrefab(data);
|
|
@@ -189,15 +197,36 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
189
197
|
getAssetRevision: () => `${Object.keys(availableTextures).sort().join('|')}::${Object.keys(availableModels).sort().join('|')}`,
|
|
190
198
|
}), [getObject, getRigidBody, registerRigidBodyRef, availableModels, availableTextures, availableSounds]);
|
|
191
199
|
const content = (_jsx("group", { ref: rootRef, children: _jsx(GameInstanceProvider, { models: availableModels, selectedId: selectedId, editMode: editMode, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, children: _jsx(StoreRootNode, { selectedId: selectedId, onSelect: editMode ? onSelect : undefined, onClick: onClick, registerRef: registerRef, loadedModels: availableModels, editMode: editMode, parentMatrix: IDENTITY }) }) }));
|
|
200
|
+
const runtimeContent = _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content });
|
|
192
201
|
if (!shouldProvideStoreContext) {
|
|
193
|
-
return
|
|
202
|
+
return runtimeContent;
|
|
194
203
|
}
|
|
195
|
-
return _jsx(PrefabStoreProvider, { store: resolvedStore, children:
|
|
204
|
+
return _jsx(PrefabStoreProvider, { store: resolvedStore, children: runtimeContent });
|
|
196
205
|
});
|
|
197
206
|
function StoreRootNode(props) {
|
|
198
207
|
const rootId = usePrefabRootId();
|
|
199
208
|
return _jsx(GameObjectRenderer, Object.assign({}, props, { nodeId: rootId }));
|
|
200
209
|
}
|
|
210
|
+
function emitNodePointerEvent(eventName, event, nodeId, node, fallbackObject) {
|
|
211
|
+
var _a;
|
|
212
|
+
const trimmedEventName = eventName === null || eventName === void 0 ? void 0 : eventName.trim();
|
|
213
|
+
if (!trimmedEventName)
|
|
214
|
+
return;
|
|
215
|
+
gameEvents.emit(trimmedEventName, {
|
|
216
|
+
sourceEntityId: nodeId,
|
|
217
|
+
sourceNodeId: nodeId,
|
|
218
|
+
nodeId,
|
|
219
|
+
node,
|
|
220
|
+
object: (_a = event.object) !== null && _a !== void 0 ? _a : fallbackObject,
|
|
221
|
+
point: [event.point.x, event.point.y, event.point.z],
|
|
222
|
+
button: event.button,
|
|
223
|
+
altKey: event.nativeEvent.altKey,
|
|
224
|
+
ctrlKey: event.nativeEvent.ctrlKey,
|
|
225
|
+
metaKey: event.nativeEvent.metaKey,
|
|
226
|
+
shiftKey: event.nativeEvent.shiftKey,
|
|
227
|
+
r3fEvent: event,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
201
230
|
export function GameObjectRenderer(props) {
|
|
202
231
|
var _a, _b;
|
|
203
232
|
const node = usePrefabNode(props.nodeId);
|
|
@@ -221,20 +250,19 @@ export function GameObjectRenderer(props) {
|
|
|
221
250
|
: _jsx(StandardNode, Object.assign({}, props), key);
|
|
222
251
|
}
|
|
223
252
|
function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef, onSelect, onClick }) {
|
|
224
|
-
var _a, _b
|
|
253
|
+
var _a, _b;
|
|
225
254
|
const gameObject = usePrefabNode(nodeId);
|
|
226
255
|
if (!gameObject)
|
|
227
256
|
return null;
|
|
228
257
|
const localTransform = getNodeTransformProps(gameObject);
|
|
229
258
|
const isLocked = Boolean(gameObject.locked);
|
|
230
|
-
const
|
|
231
|
-
const
|
|
232
|
-
const clickEventName = (_a = clickComponent === null || clickComponent === void 0 ? void 0 : clickComponent.properties) === null || _a === void 0 ? void 0 : _a.eventName;
|
|
259
|
+
const metadataProps = getNodeMetadataProps(gameObject);
|
|
260
|
+
const groupProps = Object.assign(Object.assign({}, metadataProps), { position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale });
|
|
233
261
|
const physicsData = findComponent(gameObject, "Physics");
|
|
234
262
|
const physicsProps = isPhysicsProps(physicsData === null || physicsData === void 0 ? void 0 : physicsData.properties)
|
|
235
263
|
? physicsData === null || physicsData === void 0 ? void 0 : physicsData.properties
|
|
236
264
|
: undefined;
|
|
237
|
-
const modelUrl = (
|
|
265
|
+
const modelUrl = (_b = (_a = findComponent(gameObject, "Model")) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.filename;
|
|
238
266
|
const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physicsProps), [gameObject, modelUrl, parentMatrix, physicsProps]);
|
|
239
267
|
const groupRef = useRef(null);
|
|
240
268
|
const handleGroupRef = useCallback((object) => {
|
|
@@ -243,22 +271,27 @@ function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef,
|
|
|
243
271
|
registerRef(nodeId, object);
|
|
244
272
|
}
|
|
245
273
|
}, [editMode, nodeId, registerRef]);
|
|
246
|
-
const editClickHandlers = useClickValid(!!editMode && !isLocked, (
|
|
274
|
+
const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
|
|
247
275
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
|
|
248
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(
|
|
276
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
|
|
249
277
|
});
|
|
278
|
+
const renderedInstances = instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id)));
|
|
250
279
|
if (editMode) {
|
|
251
|
-
return (_jsxs(_Fragment, { children: [_jsx("group", Object.assign({ ref: handleGroupRef
|
|
280
|
+
return (_jsxs(_Fragment, { children: [_jsx("group", Object.assign({ ref: handleGroupRef }, groupProps, editClickHandlers, { children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) })), renderedInstances] }));
|
|
252
281
|
}
|
|
253
|
-
return
|
|
282
|
+
return _jsx(_Fragment, { children: renderedInstances });
|
|
254
283
|
}
|
|
255
284
|
function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, loadedModels, editMode, parentMatrix = IDENTITY, }) {
|
|
256
285
|
var _a, _b;
|
|
257
286
|
const gameObject = usePrefabNode(nodeId);
|
|
258
287
|
const childIds = usePrefabChildIds(nodeId);
|
|
288
|
+
if (!gameObject)
|
|
289
|
+
return null;
|
|
259
290
|
const isSelected = selectedId === nodeId;
|
|
260
|
-
const isLocked = Boolean(gameObject
|
|
291
|
+
const isLocked = Boolean(gameObject.locked);
|
|
261
292
|
const stillInstanced = useInstanceCheck(nodeId);
|
|
293
|
+
const clickEventName = getNodeClickEventName(gameObject);
|
|
294
|
+
const metadataProps = getNodeMetadataProps(gameObject);
|
|
262
295
|
const groupRef = useRef(null);
|
|
263
296
|
const helperRef = useRef(null);
|
|
264
297
|
const handleGroupRef = useCallback((object) => {
|
|
@@ -268,27 +301,43 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
268
301
|
const handleHelperRef = useCallback((object) => {
|
|
269
302
|
helperRef.current = object;
|
|
270
303
|
}, []);
|
|
271
|
-
const
|
|
304
|
+
const handleEditGroupRef = useCallback((object) => {
|
|
305
|
+
handleGroupRef(object);
|
|
306
|
+
handleHelperRef(object);
|
|
307
|
+
}, [handleGroupRef, handleHelperRef]);
|
|
308
|
+
const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
|
|
272
309
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
|
|
273
|
-
|
|
274
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(e, gameObject);
|
|
310
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
|
|
275
311
|
});
|
|
312
|
+
const primaryClickHandlers = !editMode && (clickEventName || onClick)
|
|
313
|
+
? {
|
|
314
|
+
onClick: (event) => {
|
|
315
|
+
event.stopPropagation();
|
|
316
|
+
emitNodePointerEvent(clickEventName, event, nodeId, gameObject, groupRef.current);
|
|
317
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
: undefined;
|
|
276
321
|
useHelper(editMode && isSelected ? helperRef : null, BoxHelper, "cyan");
|
|
277
|
-
if (!gameObject)
|
|
278
|
-
return null;
|
|
279
322
|
const world = parentMatrix.clone().multiply(compose(gameObject));
|
|
280
323
|
const physics = findComponent(gameObject, "Physics");
|
|
281
324
|
const ready = isNodeReady(gameObject, loadedModels);
|
|
282
325
|
const hasPhysics = physics && ready && !stillInstanced;
|
|
283
326
|
const transform = getNodeTransformProps(gameObject);
|
|
327
|
+
const transformProps = {
|
|
328
|
+
position: transform.position,
|
|
329
|
+
rotation: transform.rotation,
|
|
330
|
+
scale: transform.scale,
|
|
331
|
+
};
|
|
332
|
+
const groupProps = Object.assign(Object.assign({}, metadataProps), transformProps);
|
|
284
333
|
const physicsDef = hasPhysics ? getComponentDef(physics.type) : null;
|
|
285
334
|
const isInstanced = (_b = (_a = findComponent(gameObject, "Model")) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.instanced;
|
|
286
335
|
const physicsKey = `physics_${nodeId}_${isInstanced ? 'instanced' : 'standard'}`;
|
|
287
336
|
const renderCtx = { loadedModels, editMode, registerRef };
|
|
288
337
|
const childNodes = _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, registerRef: registerRef, loadedModels: loadedModels, editMode: editMode });
|
|
289
|
-
const inner =
|
|
338
|
+
const inner = renderCompositionNode(gameObject, renderCtx, primaryClickHandlers, childNodes);
|
|
290
339
|
const physicsInner = editMode ? _jsx("group", { visible: false, children: inner }) : inner;
|
|
291
|
-
return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: editMode ? (_jsxs(_Fragment, { children: [
|
|
340
|
+
return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: editMode ? (_jsxs(_Fragment, { children: [_jsxs("group", Object.assign({ ref: handleEditGroupRef }, groupProps, editClickHandlers, { children: [_jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }), inner] })), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, Object.assign({ properties: physics.properties }, transformProps, { children: physicsInner }), physicsKey)) : null] })) : hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, Object.assign({ properties: physics.properties }, transformProps, { children: _jsx("group", Object.assign({ ref: handleGroupRef }, metadataProps, { children: inner })) }), physicsKey)) : (_jsx("group", Object.assign({ ref: handleGroupRef }, groupProps, { children: inner }))) }));
|
|
292
341
|
}
|
|
293
342
|
function isRendererHandledComponent(componentType) {
|
|
294
343
|
return componentType === "Transform"
|
|
@@ -383,11 +432,11 @@ function getNodeTransformProps(node) {
|
|
|
383
432
|
scale: (_d = t === null || t === void 0 ? void 0 : t.scale) !== null && _d !== void 0 ? _d : [1, 1, 1],
|
|
384
433
|
};
|
|
385
434
|
}
|
|
386
|
-
function renderCompositionNode(gameObject, ctx, childNodes) {
|
|
387
|
-
const primaryContent = renderNodePrimaryContent(gameObject, ctx);
|
|
435
|
+
function renderCompositionNode(gameObject, ctx, primaryClickHandlers, childNodes) {
|
|
436
|
+
const primaryContent = renderNodePrimaryContent(gameObject, ctx, primaryClickHandlers);
|
|
388
437
|
return applyNodeComposition(gameObject, _jsxs(_Fragment, { children: [primaryContent, childNodes] }));
|
|
389
438
|
}
|
|
390
|
-
function renderNodePrimaryContent(gameObject, ctx) {
|
|
439
|
+
function renderNodePrimaryContent(gameObject, ctx, primaryClickHandlers) {
|
|
391
440
|
var _a, _b, _c;
|
|
392
441
|
const geometry = (_a = findComponent(gameObject, "BufferGeometry")) !== null && _a !== void 0 ? _a : findComponent(gameObject, "Geometry");
|
|
393
442
|
const material = findComponent(gameObject, "Material");
|
|
@@ -400,7 +449,7 @@ function renderNodePrimaryContent(gameObject, ctx) {
|
|
|
400
449
|
const meshCastShadow = meshVisible && geometryProperties.castShadow !== false;
|
|
401
450
|
const meshReceiveShadow = meshVisible && geometryProperties.receiveShadow !== false;
|
|
402
451
|
if ((geometry === null || geometry === void 0 ? void 0 : geometry.type) && (geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View)) {
|
|
403
|
-
return (_jsxs("mesh", { visible: meshVisible, castShadow: meshCastShadow, receiveShadow: meshReceiveShadow, children: [_jsx(geometryDef.View, { properties: geometry.properties }), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: material.properties }, "material"))] }));
|
|
452
|
+
return (_jsxs("mesh", Object.assign({ visible: meshVisible, castShadow: meshCastShadow, receiveShadow: meshReceiveShadow }, primaryClickHandlers, { children: [_jsx(geometryDef.View, { properties: geometry.properties }), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: material.properties }, "material"))] })));
|
|
404
453
|
}
|
|
405
454
|
if ((model === null || model === void 0 ? void 0 : model.type) && (modelDef === null || modelDef === void 0 ? void 0 : modelDef.View) && !((_c = model.properties) === null || _c === void 0 ? void 0 : _c.instanced) && isNodeReady(gameObject, ctx.loadedModels)) {
|
|
406
455
|
return _jsx(modelDef.View, { properties: model.properties });
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import type { Object3D, Texture } from "three";
|
|
3
|
-
import type { PrefabStoreApi } from "./prefabStore";
|
|
4
|
-
import { type EntityComponent, type Scene } from "./scene";
|
|
5
3
|
export interface AssetRuntime {
|
|
6
4
|
registerRigidBodyRef: (id: string, rb: any) => void;
|
|
7
5
|
getModel: (path: string) => Object3D | null;
|
|
@@ -36,26 +34,3 @@ export declare function EntityRuntimeScope({ nodeId, editMode, isSelected, child
|
|
|
36
34
|
isSelected?: boolean;
|
|
37
35
|
children: ReactNode;
|
|
38
36
|
}): import("react/jsx-runtime").JSX.Element;
|
|
39
|
-
/** Runtime behaviour produced by `Component.create(ctx)`. All methods optional. */
|
|
40
|
-
export interface ComponentInstance {
|
|
41
|
-
start?(): void;
|
|
42
|
-
update?(dt: number): void;
|
|
43
|
-
destroy?(): void;
|
|
44
|
-
}
|
|
45
|
-
export interface ComponentRuntimeContext<TProperties = Record<string, any>> {
|
|
46
|
-
scene: Scene;
|
|
47
|
-
component: EntityComponent<TProperties>;
|
|
48
|
-
object: Object3D;
|
|
49
|
-
rigidBody: any;
|
|
50
|
-
}
|
|
51
|
-
export interface RuntimeEngine {
|
|
52
|
-
tick: (dt: number) => void;
|
|
53
|
-
setActive: (active: boolean) => void;
|
|
54
|
-
invalidate: () => void;
|
|
55
|
-
dispose: () => void;
|
|
56
|
-
}
|
|
57
|
-
export declare function createRuntimeEngine({ store, getObject, getRigidBody, }: {
|
|
58
|
-
store: PrefabStoreApi;
|
|
59
|
-
getObject: (id: string) => Object3D | null;
|
|
60
|
-
getRigidBody: (id: string) => any;
|
|
61
|
-
}): RuntimeEngine;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
|
+
export const AssetRuntimeContext = createContext(null);
|
|
4
|
+
const EntityRuntimeContext = createContext(null);
|
|
5
|
+
export function useAssetRuntime() {
|
|
6
|
+
const ctx = useContext(AssetRuntimeContext);
|
|
7
|
+
if (!ctx)
|
|
8
|
+
throw new Error("useAssetRuntime must be used inside <PrefabRoot>");
|
|
9
|
+
return ctx;
|
|
10
|
+
}
|
|
11
|
+
export function useEntityRuntime() {
|
|
12
|
+
const ctx = useContext(EntityRuntimeContext);
|
|
13
|
+
if (!ctx)
|
|
14
|
+
throw new Error("useEntityRuntime must be used inside a component View rendered by <PrefabRoot>");
|
|
15
|
+
return ctx;
|
|
16
|
+
}
|
|
17
|
+
export function useEntityObjectRef() {
|
|
18
|
+
const { getObject } = useEntityRuntime();
|
|
19
|
+
return useMemo(() => ({ get current() { return getObject(); } }), [getObject]);
|
|
20
|
+
}
|
|
21
|
+
export function useEntityRigidBodyRef() {
|
|
22
|
+
const { getRigidBody } = useEntityRuntime();
|
|
23
|
+
return useMemo(() => ({ get current() { return getRigidBody(); } }), [getRigidBody]);
|
|
24
|
+
}
|
|
25
|
+
export function EntityRuntimeScope({ nodeId, editMode, isSelected, children, }) {
|
|
26
|
+
const asset = useContext(AssetRuntimeContext);
|
|
27
|
+
if (!asset)
|
|
28
|
+
throw new Error("EntityRuntimeScope must be used inside <PrefabRoot>");
|
|
29
|
+
const value = useMemo(() => ({
|
|
30
|
+
nodeId,
|
|
31
|
+
editMode,
|
|
32
|
+
isSelected,
|
|
33
|
+
getObject: () => asset.getObject(nodeId),
|
|
34
|
+
getRigidBody: () => asset.getRigidBody(nodeId),
|
|
35
|
+
}), [asset, editMode, isSelected, nodeId]);
|
|
36
|
+
return _jsx(EntityRuntimeContext.Provider, { value: value, children: children });
|
|
37
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { BooleanField, FieldGroup } from "./Input";
|
|
2
|
+
import { BooleanField, FieldGroup, StringField } from "./Input";
|
|
3
3
|
const DEFAULT_TRIANGLE_POSITIONS = [
|
|
4
4
|
0, 0, 0,
|
|
5
5
|
1, 0, 0,
|
|
@@ -63,7 +63,7 @@ function BufferArrayField({ label, value, fallback, onChange, rows = 4, }) {
|
|
|
63
63
|
function BufferGeometryComponentEditor({ component, onUpdate, }) {
|
|
64
64
|
var _a;
|
|
65
65
|
const properties = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
|
|
66
|
-
return (_jsxs(FieldGroup, { children: [_jsx(BufferArrayField, { label: "Positions", value: properties.positions, fallback: DEFAULT_TRIANGLE_POSITIONS, rows: 5, onChange: (positions) => onUpdate({ positions }) }), _jsx(BufferArrayField, { label: "Indices", value: properties.indices, fallback: DEFAULT_TRIANGLE_INDICES, onChange: (indices) => onUpdate({ indices }) }), _jsx(BufferArrayField, { label: "Normals", value: properties.normals, fallback: [], onChange: (normals) => onUpdate({ normals }) }), _jsx(BufferArrayField, { label: "UVs", value: properties.uvs, fallback: DEFAULT_TRIANGLE_UVS, onChange: (uvs) => onUpdate({ uvs }) }), _jsx(BooleanField, { name: "computeVertexNormals", label: "Compute Normals", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "visible", label: "Visible", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "receiveShadow", label: "Receive Shadow", values: properties, onChange: onUpdate, fallback: true })] }));
|
|
66
|
+
return (_jsxs(FieldGroup, { children: [_jsx(BufferArrayField, { label: "Positions", value: properties.positions, fallback: DEFAULT_TRIANGLE_POSITIONS, rows: 5, onChange: (positions) => onUpdate({ positions }) }), _jsx(BufferArrayField, { label: "Indices", value: properties.indices, fallback: DEFAULT_TRIANGLE_INDICES, onChange: (indices) => onUpdate({ indices }) }), _jsx(BufferArrayField, { label: "Normals", value: properties.normals, fallback: [], onChange: (normals) => onUpdate({ normals }) }), _jsx(BufferArrayField, { label: "UVs", value: properties.uvs, fallback: DEFAULT_TRIANGLE_UVS, onChange: (uvs) => onUpdate({ uvs }) }), _jsx(BooleanField, { name: "computeVertexNormals", label: "Compute Normals", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "visible", label: "Visible", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "receiveShadow", label: "Receive Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "emitClickEvent", label: "Emit Click Event", values: properties, onChange: onUpdate, fallback: false }), properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: properties, onChange: onUpdate, placeholder: "entity:click" })) : null] }));
|
|
67
67
|
}
|
|
68
68
|
function BufferGeometryComponentView({ properties }) {
|
|
69
69
|
const positions = normalizeNumberArray(properties.positions, DEFAULT_TRIANGLE_POSITIONS);
|
|
@@ -91,6 +91,8 @@ const BufferGeometryComponent = {
|
|
|
91
91
|
normals: [],
|
|
92
92
|
uvs: DEFAULT_TRIANGLE_UVS,
|
|
93
93
|
computeVertexNormals: true,
|
|
94
|
+
emitClickEvent: false,
|
|
95
|
+
clickEventName: '',
|
|
94
96
|
},
|
|
95
97
|
};
|
|
96
98
|
export default BufferGeometryComponent;
|
|
@@ -3,7 +3,7 @@ import { OrthographicCamera, PerspectiveCamera, useHelper } from '@react-three/d
|
|
|
3
3
|
import { useRef } from 'react';
|
|
4
4
|
import { CameraHelper } from 'three';
|
|
5
5
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
6
|
-
import { useEntityRuntime } from '../
|
|
6
|
+
import { useEntityRuntime } from '../assetRuntime';
|
|
7
7
|
import { FieldGroup, NumberField, SelectField } from './Input';
|
|
8
8
|
const CAMERA_PROJECTION_OPTIONS = [
|
|
9
9
|
{ value: 'perspective', label: 'Perspective' },
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
2
|
import { ComponentData, GameObject } from "../types";
|
|
3
|
-
import type { ComponentInstance, ComponentRuntimeContext } from "../runtime";
|
|
4
3
|
export type AssetRef = {
|
|
5
4
|
type: "model" | "texture" | "sound";
|
|
6
5
|
path: string;
|
|
@@ -28,8 +27,6 @@ export interface Component {
|
|
|
28
27
|
}>;
|
|
29
28
|
defaultProperties: any;
|
|
30
29
|
View?: FC<ComponentViewProps>;
|
|
31
|
-
/** Optional runtime factory for the non-React game loop. */
|
|
32
|
-
create?: (ctx: ComponentRuntimeContext) => ComponentInstance | void;
|
|
33
30
|
/** Declare which asset paths this component references (for asset loading). */
|
|
34
31
|
getAssetRefs?: (properties: Record<string, any>) => AssetRef[];
|
|
35
32
|
}
|