react-three-game 0.0.69 → 0.0.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/SoundManager.d.ts +2 -0
- package/dist/helpers/SoundManager.js +6 -0
- package/dist/index.d.ts +20 -13
- package/dist/index.js +14 -7
- package/dist/shared/GameCanvas.js +0 -2
- package/dist/tools/assetviewer/page.d.ts +5 -0
- package/dist/tools/assetviewer/page.js +3 -0
- package/dist/tools/dragdrop/DragDropLoader.d.ts +3 -2
- package/dist/tools/dragdrop/DragDropLoader.js +18 -3
- package/dist/tools/dragdrop/index.d.ts +2 -2
- package/dist/tools/dragdrop/index.js +1 -1
- package/dist/tools/dragdrop/modelLoader.d.ts +10 -0
- package/dist/tools/dragdrop/modelLoader.js +60 -0
- package/dist/tools/prefabeditor/EditorTree.js +6 -40
- package/dist/tools/prefabeditor/EditorTreeMenus.js +2 -20
- package/dist/tools/prefabeditor/EditorUI.js +8 -5
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +2 -0
- package/dist/tools/prefabeditor/InstanceProvider.js +54 -52
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +23 -1
- package/dist/tools/prefabeditor/PrefabEditor.js +79 -47
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +26 -9
- package/dist/tools/prefabeditor/PrefabRoot.js +195 -159
- package/dist/tools/prefabeditor/RefBridge.d.ts +24 -0
- package/dist/tools/prefabeditor/RefBridge.js +44 -0
- package/dist/tools/prefabeditor/components/AmbientLightComponent.js +10 -7
- package/dist/tools/prefabeditor/components/CameraComponent.js +8 -14
- package/dist/tools/prefabeditor/components/ClickComponent.js +12 -7
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +31 -5
- package/dist/tools/prefabeditor/components/ComponentRegistry.js +6 -6
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +124 -52
- package/dist/tools/prefabeditor/components/EnvironmentComponent.js +5 -3
- package/dist/tools/prefabeditor/components/GeometryComponent.js +1 -1
- package/dist/tools/prefabeditor/components/Input.d.ts +16 -0
- package/dist/tools/prefabeditor/components/Input.js +33 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.js +19 -8
- package/dist/tools/prefabeditor/components/ModelComponent.js +39 -45
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +10 -1
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +127 -31
- package/dist/tools/prefabeditor/components/PointLightComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/PointLightComponent.js +55 -0
- package/dist/tools/prefabeditor/components/SoundComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/SoundComponent.js +244 -0
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +53 -24
- package/dist/tools/prefabeditor/components/TransformComponent.js +2 -2
- package/dist/tools/prefabeditor/components/index.js +4 -0
- package/dist/tools/prefabeditor/components/lightUtils.d.ts +13 -0
- package/dist/tools/prefabeditor/components/lightUtils.js +64 -0
- package/dist/tools/prefabeditor/prefab.d.ts +37 -0
- package/dist/tools/prefabeditor/prefab.js +229 -0
- package/dist/tools/prefabeditor/prefabStore.d.ts +4 -16
- package/dist/tools/prefabeditor/prefabStore.js +32 -173
- package/dist/tools/prefabeditor/{sceneApi.d.ts → scene.d.ts} +15 -1
- package/dist/tools/prefabeditor/{sceneApi.js → scene.js} +66 -32
- package/dist/tools/prefabeditor/styles.d.ts +1 -0
- package/dist/tools/prefabeditor/styles.js +9 -0
- package/dist/tools/prefabeditor/types.d.ts +13 -0
- package/dist/tools/prefabeditor/types.js +28 -1
- package/dist/tools/prefabeditor/useClickValid.d.ts +13 -0
- package/dist/tools/prefabeditor/useClickValid.js +21 -0
- package/dist/tools/prefabeditor/utils.d.ts +2 -4
- package/dist/tools/prefabeditor/utils.js +8 -46
- package/package.json +1 -1
- package/dist/tools/prefabeditor/EditorContext.d.ts +0 -16
- package/dist/tools/prefabeditor/EditorContext.js +0 -9
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { getComponentAssetRefs, getComponentDef } from './components/ComponentRegistry';
|
|
13
|
+
function clonePrefabValue(value) {
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return value.map(item => clonePrefabValue(item));
|
|
16
|
+
}
|
|
17
|
+
if (value && typeof value === 'object') {
|
|
18
|
+
const clone = {};
|
|
19
|
+
Object.entries(value).forEach(([key, entry]) => {
|
|
20
|
+
clone[key] = clonePrefabValue(entry);
|
|
21
|
+
});
|
|
22
|
+
return clone;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function createComponentMap(components) {
|
|
27
|
+
const componentMap = {
|
|
28
|
+
transform: createComponentData('Transform'),
|
|
29
|
+
};
|
|
30
|
+
Object.entries(components).forEach(([key, component]) => {
|
|
31
|
+
componentMap[key] = createComponentData(component.type, component.properties);
|
|
32
|
+
});
|
|
33
|
+
return componentMap;
|
|
34
|
+
}
|
|
35
|
+
function getNodeNameFromPath(path, name) {
|
|
36
|
+
return name !== null && name !== void 0 ? name : path.replace(/^.*[\/]/, '').replace(/\.[^.]+$/, '');
|
|
37
|
+
}
|
|
38
|
+
function getAssetManifestKey(assetRefCounts) {
|
|
39
|
+
return Object.keys(assetRefCounts).sort().join('|');
|
|
40
|
+
}
|
|
41
|
+
function sameStringArrays(left, right) {
|
|
42
|
+
if (left.length !== right.length)
|
|
43
|
+
return false;
|
|
44
|
+
return left.every((value, index) => value === right[index]);
|
|
45
|
+
}
|
|
46
|
+
function getAssetRefs(node) {
|
|
47
|
+
var _a;
|
|
48
|
+
const refs = [];
|
|
49
|
+
Object.values((_a = node === null || node === void 0 ? void 0 : node.components) !== null && _a !== void 0 ? _a : {}).forEach(component => {
|
|
50
|
+
var _a;
|
|
51
|
+
if (!(component === null || component === void 0 ? void 0 : component.type))
|
|
52
|
+
return;
|
|
53
|
+
for (const ref of getComponentAssetRefs(component.type, (_a = component.properties) !== null && _a !== void 0 ? _a : {})) {
|
|
54
|
+
refs.push(`${ref.type}:${ref.path}`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return refs.sort();
|
|
58
|
+
}
|
|
59
|
+
function addAssetRefs(assetRefCounts, refs) {
|
|
60
|
+
refs.forEach(ref => {
|
|
61
|
+
var _a;
|
|
62
|
+
assetRefCounts[ref] = ((_a = assetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function removeAssetRefs(assetRefCounts, refs) {
|
|
66
|
+
refs.forEach(ref => {
|
|
67
|
+
var _a;
|
|
68
|
+
const nextCount = ((_a = assetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) - 1;
|
|
69
|
+
if (nextCount > 0) {
|
|
70
|
+
assetRefCounts[ref] = nextCount;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
delete assetRefCounts[ref];
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function createAssetRefCounts(nodesById) {
|
|
77
|
+
const assetRefCounts = {};
|
|
78
|
+
Object.values(nodesById).forEach(node => addAssetRefs(assetRefCounts, getAssetRefs(node)));
|
|
79
|
+
return assetRefCounts;
|
|
80
|
+
}
|
|
81
|
+
function denormalizeNode(id, nodesById, childIdsById) {
|
|
82
|
+
var _a;
|
|
83
|
+
const node = nodesById[id];
|
|
84
|
+
return Object.assign(Object.assign({}, node), { children: ((_a = childIdsById[id]) !== null && _a !== void 0 ? _a : []).map(childId => denormalizeNode(childId, nodesById, childIdsById)) });
|
|
85
|
+
}
|
|
86
|
+
export function createDefaultComponentProperties(type) {
|
|
87
|
+
var _a, _b;
|
|
88
|
+
return clonePrefabValue((_b = (_a = getComponentDef(type)) === null || _a === void 0 ? void 0 : _a.defaultProperties) !== null && _b !== void 0 ? _b : {});
|
|
89
|
+
}
|
|
90
|
+
export function createComponentData(type, properties) {
|
|
91
|
+
return {
|
|
92
|
+
type,
|
|
93
|
+
properties: properties ? clonePrefabValue(properties) : createDefaultComponentProperties(type),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function createNode(name, components = {}, options) {
|
|
97
|
+
var _a;
|
|
98
|
+
return Object.assign({ id: (_a = options === null || options === void 0 ? void 0 : options.id) !== null && _a !== void 0 ? _a : crypto.randomUUID(), name, components: createComponentMap(components) }, ((options === null || options === void 0 ? void 0 : options.children) ? { children: options.children } : null));
|
|
99
|
+
}
|
|
100
|
+
export function createEmptyNode(name = 'New Node') {
|
|
101
|
+
return createNode(name);
|
|
102
|
+
}
|
|
103
|
+
export function createEmptyPrefab() {
|
|
104
|
+
return {
|
|
105
|
+
id: crypto.randomUUID(),
|
|
106
|
+
name: 'New Prefab',
|
|
107
|
+
root: createNode('Root', {}, { id: crypto.randomUUID(), children: [] }),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export function createModelNode(filename, name) {
|
|
111
|
+
return createNode(getNodeNameFromPath(filename, name), {
|
|
112
|
+
model: {
|
|
113
|
+
type: 'Model',
|
|
114
|
+
properties: {
|
|
115
|
+
filename,
|
|
116
|
+
instanced: false,
|
|
117
|
+
repeat: false,
|
|
118
|
+
repeatAxes: [{ axis: 'x', count: 1, offset: 1 }],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
export function createImageNode(texturePath, name) {
|
|
124
|
+
return createNode(getNodeNameFromPath(texturePath, name), {
|
|
125
|
+
geometry: {
|
|
126
|
+
type: 'Geometry',
|
|
127
|
+
properties: { geometryType: 'plane', args: [1, 1] },
|
|
128
|
+
},
|
|
129
|
+
material: {
|
|
130
|
+
type: 'Material',
|
|
131
|
+
properties: { color: '#ffffff', texture: texturePath },
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
export function normalizePrefab(prefab, revision = 0) {
|
|
136
|
+
const nodesById = {};
|
|
137
|
+
const childIdsById = {};
|
|
138
|
+
const parentIdById = {};
|
|
139
|
+
insertSubtree(prefab.root, null, nodesById, childIdsById, parentIdById);
|
|
140
|
+
const assetRefCounts = createAssetRefCounts(nodesById);
|
|
141
|
+
return {
|
|
142
|
+
prefabId: prefab.id,
|
|
143
|
+
prefabName: prefab.name,
|
|
144
|
+
rootId: prefab.root.id,
|
|
145
|
+
nodesById,
|
|
146
|
+
childIdsById,
|
|
147
|
+
parentIdById,
|
|
148
|
+
revision,
|
|
149
|
+
assetManifestKey: getAssetManifestKey(assetRefCounts),
|
|
150
|
+
assetRefCounts,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export function createPrefabPatch(state, patch, nextAssetRefCounts = state.assetRefCounts) {
|
|
154
|
+
const assetRefsChanged = nextAssetRefCounts !== state.assetRefCounts;
|
|
155
|
+
return Object.assign(Object.assign(Object.assign({}, patch), { revision: state.revision + 1 }), (assetRefsChanged ? {
|
|
156
|
+
assetRefCounts: nextAssetRefCounts,
|
|
157
|
+
assetManifestKey: getAssetManifestKey(nextAssetRefCounts),
|
|
158
|
+
} : null));
|
|
159
|
+
}
|
|
160
|
+
export function denormalizePrefab(state) {
|
|
161
|
+
return {
|
|
162
|
+
id: state.prefabId,
|
|
163
|
+
name: state.prefabName,
|
|
164
|
+
root: denormalizeNode(state.rootId, state.nodesById, state.childIdsById),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export function collectSubtreeIds(id, childIdsById) {
|
|
168
|
+
var _a;
|
|
169
|
+
const ids = [id];
|
|
170
|
+
for (const childId of (_a = childIdsById[id]) !== null && _a !== void 0 ? _a : []) {
|
|
171
|
+
ids.push(...collectSubtreeIds(childId, childIdsById));
|
|
172
|
+
}
|
|
173
|
+
return ids;
|
|
174
|
+
}
|
|
175
|
+
export function insertSubtree(node, parentId, nodesById, childIdsById, parentIdById) {
|
|
176
|
+
var _a;
|
|
177
|
+
const { children } = node, nodeRecord = __rest(node, ["children"]);
|
|
178
|
+
nodesById[node.id] = nodeRecord;
|
|
179
|
+
childIdsById[node.id] = (_a = children === null || children === void 0 ? void 0 : children.map(child => child.id)) !== null && _a !== void 0 ? _a : [];
|
|
180
|
+
parentIdById[node.id] = parentId;
|
|
181
|
+
children === null || children === void 0 ? void 0 : children.forEach(child => insertSubtree(child, node.id, nodesById, childIdsById, parentIdById));
|
|
182
|
+
}
|
|
183
|
+
export function cloneSubtree(id, parentId, source, nodesById, childIdsById, parentIdById) {
|
|
184
|
+
var _a, _b;
|
|
185
|
+
const originalNode = source.nodesById[id];
|
|
186
|
+
if (!originalNode)
|
|
187
|
+
return null;
|
|
188
|
+
const clonedId = crypto.randomUUID();
|
|
189
|
+
const clonedNode = Object.assign(Object.assign({}, originalNode), { id: clonedId, name: `${(_a = originalNode.name) !== null && _a !== void 0 ? _a : originalNode.id} Copy` });
|
|
190
|
+
nodesById[clonedId] = clonedNode;
|
|
191
|
+
parentIdById[clonedId] = parentId;
|
|
192
|
+
const clonedChildIds = ((_b = source.childIdsById[id]) !== null && _b !== void 0 ? _b : [])
|
|
193
|
+
.map(childId => cloneSubtree(childId, clonedId, source, nodesById, childIdsById, parentIdById))
|
|
194
|
+
.filter((childId) => Boolean(childId));
|
|
195
|
+
childIdsById[clonedId] = clonedChildIds;
|
|
196
|
+
return clonedId;
|
|
197
|
+
}
|
|
198
|
+
export function isDescendant(id, potentialAncestorId, parentIdById) {
|
|
199
|
+
let currentId = id;
|
|
200
|
+
while (currentId) {
|
|
201
|
+
if (currentId === potentialAncestorId)
|
|
202
|
+
return true;
|
|
203
|
+
currentId = parentIdById[currentId];
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
export function updateAssetRefsForNodeChange(assetRefCounts, currentNode, nextNode) {
|
|
208
|
+
const currentRefs = getAssetRefs(currentNode);
|
|
209
|
+
const nextRefs = getAssetRefs(nextNode);
|
|
210
|
+
if (sameStringArrays(currentRefs, nextRefs)) {
|
|
211
|
+
return assetRefCounts;
|
|
212
|
+
}
|
|
213
|
+
const nextAssetRefCounts = Object.assign({}, assetRefCounts);
|
|
214
|
+
removeAssetRefs(nextAssetRefCounts, currentRefs);
|
|
215
|
+
addAssetRefs(nextAssetRefCounts, nextRefs);
|
|
216
|
+
return nextAssetRefCounts;
|
|
217
|
+
}
|
|
218
|
+
export function collectSubtreeAssetRefs(node) {
|
|
219
|
+
var _a;
|
|
220
|
+
const refs = getAssetRefs(node);
|
|
221
|
+
(_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(child => refs.push(...collectSubtreeAssetRefs(child)));
|
|
222
|
+
return refs;
|
|
223
|
+
}
|
|
224
|
+
export function collectAssetRefsForIds(ids, nodesById) {
|
|
225
|
+
return ids.reduce((refs, id) => {
|
|
226
|
+
refs.push(...getAssetRefs(nodesById[id]));
|
|
227
|
+
return refs;
|
|
228
|
+
}, []);
|
|
229
|
+
}
|
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import { type StoreApi } from "zustand/vanilla";
|
|
3
3
|
import { GameObject, Prefab } from "./types";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
type PrefabDocumentSnapshot = {
|
|
7
|
-
prefabId?: string;
|
|
8
|
-
prefabName?: string;
|
|
9
|
-
rootId: string;
|
|
10
|
-
nodesById: Record<string, PrefabNodeRecord>;
|
|
11
|
-
childIdsById: Record<string, string[]>;
|
|
12
|
-
parentIdById: Record<string, string | null>;
|
|
13
|
-
revision: number;
|
|
14
|
-
assetManifestKey: string;
|
|
15
|
-
assetRefCounts: PrefabAssetRefCounts;
|
|
16
|
-
};
|
|
17
|
-
export interface PrefabStoreState extends PrefabDocumentSnapshot {
|
|
4
|
+
import { denormalizePrefab, PrefabState, PrefabNodeRecord } from "./prefab";
|
|
5
|
+
export interface PrefabStoreState extends PrefabState {
|
|
18
6
|
replacePrefab: (prefab: Prefab) => void;
|
|
19
7
|
updateNode: (id: string, update: (node: PrefabNodeRecord) => PrefabNodeRecord) => void;
|
|
20
8
|
updateNodes: (updates: Array<{
|
|
@@ -33,10 +21,10 @@ export declare function PrefabStoreProvider({ store, children, }: {
|
|
|
33
21
|
children: ReactNode;
|
|
34
22
|
}): import("react").FunctionComponentElement<import("react").ProviderProps<PrefabStoreApi | null>>;
|
|
35
23
|
export declare function usePrefabStoreApi(): PrefabStoreApi;
|
|
24
|
+
export declare function useOptionalPrefabStoreApi(): PrefabStoreApi | null;
|
|
36
25
|
export declare function usePrefabStore<T>(selector: (state: PrefabStoreState) => T): T;
|
|
37
26
|
export declare function usePrefabRootId(): string;
|
|
38
27
|
export declare function usePrefabNode(nodeId: string | null | undefined): PrefabNodeRecord | null;
|
|
39
28
|
export declare function usePrefabChildIds(nodeId: string | null | undefined): string[];
|
|
40
29
|
export declare function createPrefabStore(prefab: Prefab): PrefabStoreApi;
|
|
41
|
-
export declare
|
|
42
|
-
export {};
|
|
30
|
+
export declare const prefabStoreToPrefab: typeof denormalizePrefab;
|
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
-
var t = {};
|
|
3
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
-
t[p] = s[p];
|
|
5
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
12
1
|
import { createContext, createElement, useContext } from "react";
|
|
13
2
|
import { subscribeWithSelector } from "zustand/middleware";
|
|
14
3
|
import { useStore } from "zustand";
|
|
15
4
|
import { createStore } from "zustand/vanilla";
|
|
5
|
+
import { collectAssetRefsForIds, collectSubtreeAssetRefs, collectSubtreeIds, cloneSubtree, createPrefabPatch, denormalizePrefab, insertSubtree, isDescendant, normalizePrefab, updateAssetRefsForNodeChange, } from "./prefab";
|
|
16
6
|
const PrefabStoreContext = createContext(null);
|
|
17
7
|
const EMPTY_CHILD_IDS = [];
|
|
18
8
|
export function PrefabStoreProvider({ store, children, }) {
|
|
@@ -25,6 +15,9 @@ export function usePrefabStoreApi() {
|
|
|
25
15
|
}
|
|
26
16
|
return store;
|
|
27
17
|
}
|
|
18
|
+
export function useOptionalPrefabStoreApi() {
|
|
19
|
+
return useContext(PrefabStoreContext);
|
|
20
|
+
}
|
|
28
21
|
export function usePrefabStore(selector) {
|
|
29
22
|
return useStore(usePrefabStoreApi(), selector);
|
|
30
23
|
}
|
|
@@ -38,8 +31,8 @@ export function usePrefabChildIds(nodeId) {
|
|
|
38
31
|
return usePrefabStore(state => { var _a; return nodeId ? (_a = state.childIdsById[nodeId]) !== null && _a !== void 0 ? _a : EMPTY_CHILD_IDS : EMPTY_CHILD_IDS; });
|
|
39
32
|
}
|
|
40
33
|
export function createPrefabStore(prefab) {
|
|
41
|
-
return createStore()(subscribeWithSelector((set, get) => (Object.assign(Object.assign({},
|
|
42
|
-
set(
|
|
34
|
+
return createStore()(subscribeWithSelector((set, get) => (Object.assign(Object.assign({}, normalizePrefab(prefab)), { replacePrefab: (nextPrefab) => {
|
|
35
|
+
set(normalizePrefab(nextPrefab, get().revision + 1));
|
|
43
36
|
}, updateNode: (id, update) => {
|
|
44
37
|
const state = get();
|
|
45
38
|
const node = state.nodesById[id];
|
|
@@ -49,7 +42,7 @@ export function createPrefabStore(prefab) {
|
|
|
49
42
|
if (nextNode === node)
|
|
50
43
|
return;
|
|
51
44
|
const nextAssetRefCounts = updateAssetRefsForNodeChange(state.assetRefCounts, node, nextNode);
|
|
52
|
-
set(
|
|
45
|
+
set(createPrefabPatch(state, {
|
|
53
46
|
nodesById: Object.assign(Object.assign({}, state.nodesById), { [id]: nextNode }),
|
|
54
47
|
}, nextAssetRefCounts));
|
|
55
48
|
}, updateNodes: (updates) => {
|
|
@@ -71,7 +64,7 @@ export function createPrefabStore(prefab) {
|
|
|
71
64
|
}
|
|
72
65
|
if (!nextNodesById)
|
|
73
66
|
return;
|
|
74
|
-
set(
|
|
67
|
+
set(createPrefabPatch(state, { nodesById: nextNodesById }, nextAssetRefCounts));
|
|
75
68
|
}, addChild: (parentId, node) => {
|
|
76
69
|
var _a;
|
|
77
70
|
const state = get();
|
|
@@ -83,8 +76,11 @@ export function createPrefabStore(prefab) {
|
|
|
83
76
|
const nextAssetRefCounts = Object.assign({}, state.assetRefCounts);
|
|
84
77
|
insertSubtree(node, parentId, nextNodesById, nextChildIdsById, nextParentIdById);
|
|
85
78
|
nextChildIdsById[parentId] = [...((_a = nextChildIdsById[parentId]) !== null && _a !== void 0 ? _a : []), node.id];
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
collectSubtreeAssetRefs(node).forEach(ref => {
|
|
80
|
+
var _a;
|
|
81
|
+
nextAssetRefCounts[ref] = ((_a = nextAssetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
82
|
+
});
|
|
83
|
+
set(createPrefabPatch(state, {
|
|
88
84
|
nodesById: nextNodesById,
|
|
89
85
|
childIdsById: nextChildIdsById,
|
|
90
86
|
parentIdById: nextParentIdById,
|
|
@@ -102,14 +98,22 @@ export function createPrefabStore(prefab) {
|
|
|
102
98
|
const nextChildIdsById = Object.assign({}, state.childIdsById);
|
|
103
99
|
const nextParentIdById = Object.assign({}, state.parentIdById);
|
|
104
100
|
const nextAssetRefCounts = Object.assign({}, state.assetRefCounts);
|
|
105
|
-
|
|
101
|
+
collectAssetRefsForIds(idsToDelete, state.nodesById).forEach(ref => {
|
|
102
|
+
var _a;
|
|
103
|
+
const nextCount = ((_a = nextAssetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) - 1;
|
|
104
|
+
if (nextCount > 0) {
|
|
105
|
+
nextAssetRefCounts[ref] = nextCount;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
delete nextAssetRefCounts[ref];
|
|
109
|
+
});
|
|
106
110
|
idsToDelete.forEach(nodeId => {
|
|
107
111
|
delete nextNodesById[nodeId];
|
|
108
112
|
delete nextChildIdsById[nodeId];
|
|
109
113
|
delete nextParentIdById[nodeId];
|
|
110
114
|
});
|
|
111
115
|
nextChildIdsById[parentId] = ((_a = nextChildIdsById[parentId]) !== null && _a !== void 0 ? _a : []).filter(childId => childId !== id);
|
|
112
|
-
set(
|
|
116
|
+
set(createPrefabPatch(state, {
|
|
113
117
|
nodesById: nextNodesById,
|
|
114
118
|
childIdsById: nextChildIdsById,
|
|
115
119
|
parentIdById: nextParentIdById,
|
|
@@ -125,7 +129,7 @@ export function createPrefabStore(prefab) {
|
|
|
125
129
|
const nextNodesById = Object.assign({}, state.nodesById);
|
|
126
130
|
const nextChildIdsById = Object.assign({}, state.childIdsById);
|
|
127
131
|
const nextParentIdById = Object.assign({}, state.parentIdById);
|
|
128
|
-
const duplicatedRootId =
|
|
132
|
+
const duplicatedRootId = cloneSubtree(id, parentId, state, nextNodesById, nextChildIdsById, nextParentIdById);
|
|
129
133
|
if (!duplicatedRootId)
|
|
130
134
|
return null;
|
|
131
135
|
const siblings = [...((_a = nextChildIdsById[parentId]) !== null && _a !== void 0 ? _a : [])];
|
|
@@ -138,8 +142,11 @@ export function createPrefabStore(prefab) {
|
|
|
138
142
|
}
|
|
139
143
|
nextChildIdsById[parentId] = siblings;
|
|
140
144
|
const nextAssetRefCounts = Object.assign({}, state.assetRefCounts);
|
|
141
|
-
|
|
142
|
-
|
|
145
|
+
collectAssetRefsForIds(collectSubtreeIds(id, state.childIdsById), state.nodesById).forEach(ref => {
|
|
146
|
+
var _a;
|
|
147
|
+
nextAssetRefCounts[ref] = ((_a = nextAssetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
148
|
+
});
|
|
149
|
+
set(createPrefabPatch(state, {
|
|
143
150
|
nodesById: nextNodesById,
|
|
144
151
|
childIdsById: nextChildIdsById,
|
|
145
152
|
parentIdById: nextParentIdById,
|
|
@@ -151,7 +158,7 @@ export function createPrefabStore(prefab) {
|
|
|
151
158
|
if (!node)
|
|
152
159
|
return;
|
|
153
160
|
const nextNode = Object.assign(Object.assign({}, node), { [key]: !node[key] });
|
|
154
|
-
set(
|
|
161
|
+
set(createPrefabPatch(state, {
|
|
155
162
|
nodesById: Object.assign(Object.assign({}, state.nodesById), { [id]: nextNode }),
|
|
156
163
|
}));
|
|
157
164
|
}, moveNode: (draggedId, targetId, position) => {
|
|
@@ -190,158 +197,10 @@ export function createPrefabStore(prefab) {
|
|
|
190
197
|
destinationChildren.splice(targetIndex, 0, draggedId);
|
|
191
198
|
nextChildIdsById[destinationParentId] = destinationChildren;
|
|
192
199
|
}
|
|
193
|
-
set(
|
|
200
|
+
set(createPrefabPatch(state, {
|
|
194
201
|
childIdsById: nextChildIdsById,
|
|
195
202
|
parentIdById: nextParentIdById,
|
|
196
203
|
}));
|
|
197
204
|
} }))));
|
|
198
205
|
}
|
|
199
|
-
export
|
|
200
|
-
return {
|
|
201
|
-
id: state.prefabId,
|
|
202
|
-
name: state.prefabName,
|
|
203
|
-
root: denormalizeNode(state.rootId, state.nodesById, state.childIdsById),
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
function createDocumentState(prefab, revision = 0) {
|
|
207
|
-
const nodesById = {};
|
|
208
|
-
const childIdsById = {};
|
|
209
|
-
const parentIdById = {};
|
|
210
|
-
insertSubtree(prefab.root, null, nodesById, childIdsById, parentIdById);
|
|
211
|
-
const assetRefCounts = createAssetRefCounts(nodesById);
|
|
212
|
-
return {
|
|
213
|
-
prefabId: prefab.id,
|
|
214
|
-
prefabName: prefab.name,
|
|
215
|
-
rootId: prefab.root.id,
|
|
216
|
-
nodesById,
|
|
217
|
-
childIdsById,
|
|
218
|
-
parentIdById,
|
|
219
|
-
revision,
|
|
220
|
-
assetManifestKey: getAssetManifestKey(assetRefCounts),
|
|
221
|
-
assetRefCounts,
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
function createMutationPatch(state, patch, nextAssetRefCounts = state.assetRefCounts) {
|
|
225
|
-
const assetRefsChanged = nextAssetRefCounts !== state.assetRefCounts;
|
|
226
|
-
return Object.assign(Object.assign(Object.assign({}, patch), { revision: state.revision + 1 }), (assetRefsChanged ? {
|
|
227
|
-
assetRefCounts: nextAssetRefCounts,
|
|
228
|
-
assetManifestKey: getAssetManifestKey(nextAssetRefCounts),
|
|
229
|
-
} : null));
|
|
230
|
-
}
|
|
231
|
-
function denormalizeNode(id, nodesById, childIdsById) {
|
|
232
|
-
var _a;
|
|
233
|
-
const node = nodesById[id];
|
|
234
|
-
return Object.assign(Object.assign({}, node), { children: ((_a = childIdsById[id]) !== null && _a !== void 0 ? _a : []).map(childId => denormalizeNode(childId, nodesById, childIdsById)) });
|
|
235
|
-
}
|
|
236
|
-
function collectSubtreeIds(id, childIdsById) {
|
|
237
|
-
var _a;
|
|
238
|
-
const ids = [id];
|
|
239
|
-
for (const childId of (_a = childIdsById[id]) !== null && _a !== void 0 ? _a : []) {
|
|
240
|
-
ids.push(...collectSubtreeIds(childId, childIdsById));
|
|
241
|
-
}
|
|
242
|
-
return ids;
|
|
243
|
-
}
|
|
244
|
-
function insertSubtree(node, parentId, nodesById, childIdsById, parentIdById) {
|
|
245
|
-
var _a;
|
|
246
|
-
const { children } = node, nodeRecord = __rest(node, ["children"]);
|
|
247
|
-
nodesById[node.id] = nodeRecord;
|
|
248
|
-
childIdsById[node.id] = (_a = children === null || children === void 0 ? void 0 : children.map(child => child.id)) !== null && _a !== void 0 ? _a : [];
|
|
249
|
-
parentIdById[node.id] = parentId;
|
|
250
|
-
children === null || children === void 0 ? void 0 : children.forEach(child => insertSubtree(child, node.id, nodesById, childIdsById, parentIdById));
|
|
251
|
-
}
|
|
252
|
-
function cloneSubtreeIntoMaps(id, parentId, source, nodesById, childIdsById, parentIdById) {
|
|
253
|
-
var _a, _b;
|
|
254
|
-
const originalNode = source.nodesById[id];
|
|
255
|
-
if (!originalNode)
|
|
256
|
-
return null;
|
|
257
|
-
const clonedId = crypto.randomUUID();
|
|
258
|
-
const clonedNode = Object.assign(Object.assign({}, originalNode), { id: clonedId, name: `${(_a = originalNode.name) !== null && _a !== void 0 ? _a : originalNode.id} Copy` });
|
|
259
|
-
nodesById[clonedId] = clonedNode;
|
|
260
|
-
parentIdById[clonedId] = parentId;
|
|
261
|
-
const clonedChildIds = ((_b = source.childIdsById[id]) !== null && _b !== void 0 ? _b : [])
|
|
262
|
-
.map(childId => cloneSubtreeIntoMaps(childId, clonedId, source, nodesById, childIdsById, parentIdById))
|
|
263
|
-
.filter((childId) => Boolean(childId));
|
|
264
|
-
childIdsById[clonedId] = clonedChildIds;
|
|
265
|
-
return clonedId;
|
|
266
|
-
}
|
|
267
|
-
function isDescendant(id, potentialAncestorId, parentIdById) {
|
|
268
|
-
let currentId = id;
|
|
269
|
-
while (currentId) {
|
|
270
|
-
if (currentId === potentialAncestorId)
|
|
271
|
-
return true;
|
|
272
|
-
currentId = parentIdById[currentId];
|
|
273
|
-
}
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
function createAssetRefCounts(nodesById) {
|
|
277
|
-
const assetRefCounts = {};
|
|
278
|
-
Object.values(nodesById).forEach(node => addAssetRefs(assetRefCounts, getAssetRefs(node)));
|
|
279
|
-
return assetRefCounts;
|
|
280
|
-
}
|
|
281
|
-
function updateAssetRefsForNodeChange(assetRefCounts, currentNode, nextNode) {
|
|
282
|
-
const currentRefs = getAssetRefs(currentNode);
|
|
283
|
-
const nextRefs = getAssetRefs(nextNode);
|
|
284
|
-
if (sameStringArrays(currentRefs, nextRefs)) {
|
|
285
|
-
return assetRefCounts;
|
|
286
|
-
}
|
|
287
|
-
const nextAssetRefCounts = Object.assign({}, assetRefCounts);
|
|
288
|
-
removeAssetRefs(nextAssetRefCounts, currentRefs);
|
|
289
|
-
addAssetRefs(nextAssetRefCounts, nextRefs);
|
|
290
|
-
return nextAssetRefCounts;
|
|
291
|
-
}
|
|
292
|
-
function collectSubtreeAssetRefs(node) {
|
|
293
|
-
var _a;
|
|
294
|
-
const refs = getAssetRefs(node);
|
|
295
|
-
(_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(child => refs.push(...collectSubtreeAssetRefs(child)));
|
|
296
|
-
return refs;
|
|
297
|
-
}
|
|
298
|
-
function collectAssetRefsForIds(ids, nodesById) {
|
|
299
|
-
return ids.flatMap(id => getAssetRefs(nodesById[id]));
|
|
300
|
-
}
|
|
301
|
-
function getAssetRefs(node) {
|
|
302
|
-
var _a;
|
|
303
|
-
const refs = [];
|
|
304
|
-
Object.values((_a = node === null || node === void 0 ? void 0 : node.components) !== null && _a !== void 0 ? _a : {}).forEach(component => {
|
|
305
|
-
var _a, _b, _c, _d;
|
|
306
|
-
if (!(component === null || component === void 0 ? void 0 : component.type))
|
|
307
|
-
return;
|
|
308
|
-
if (component.type === "Model" && ((_a = component.properties) === null || _a === void 0 ? void 0 : _a.filename)) {
|
|
309
|
-
refs.push(`model:${component.properties.filename}`);
|
|
310
|
-
}
|
|
311
|
-
if (component.type === "Material") {
|
|
312
|
-
if ((_b = component.properties) === null || _b === void 0 ? void 0 : _b.texture)
|
|
313
|
-
refs.push(`texture:${component.properties.texture}`);
|
|
314
|
-
if ((_c = component.properties) === null || _c === void 0 ? void 0 : _c.normalMapTexture)
|
|
315
|
-
refs.push(`texture:${component.properties.normalMapTexture}`);
|
|
316
|
-
}
|
|
317
|
-
if (component.type === "SpotLight" && ((_d = component.properties) === null || _d === void 0 ? void 0 : _d.map)) {
|
|
318
|
-
refs.push(`texture:${component.properties.map}`);
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
return refs.sort();
|
|
322
|
-
}
|
|
323
|
-
function addAssetRefs(assetRefCounts, refs) {
|
|
324
|
-
refs.forEach(ref => {
|
|
325
|
-
var _a;
|
|
326
|
-
assetRefCounts[ref] = ((_a = assetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
function removeAssetRefs(assetRefCounts, refs) {
|
|
330
|
-
refs.forEach(ref => {
|
|
331
|
-
var _a;
|
|
332
|
-
const nextCount = ((_a = assetRefCounts[ref]) !== null && _a !== void 0 ? _a : 0) - 1;
|
|
333
|
-
if (nextCount > 0) {
|
|
334
|
-
assetRefCounts[ref] = nextCount;
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
delete assetRefCounts[ref];
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
function getAssetManifestKey(assetRefCounts) {
|
|
341
|
-
return Object.keys(assetRefCounts).sort().join("|");
|
|
342
|
-
}
|
|
343
|
-
function sameStringArrays(left, right) {
|
|
344
|
-
if (left.length !== right.length)
|
|
345
|
-
return false;
|
|
346
|
-
return left.every((value, index) => value === right[index]);
|
|
347
|
-
}
|
|
206
|
+
export const prefabStoreToPrefab = denormalizePrefab;
|
|
@@ -15,16 +15,27 @@ export interface EntityComponent<TProperties = Record<string, any>> {
|
|
|
15
15
|
}
|
|
16
16
|
export interface Entity {
|
|
17
17
|
readonly id: string;
|
|
18
|
+
readonly name: string | undefined;
|
|
19
|
+
readonly enabled: boolean;
|
|
20
|
+
readonly parent: Entity | null;
|
|
21
|
+
readonly children: Entity[];
|
|
18
22
|
set: (data: EntityData) => void;
|
|
19
23
|
update: (update: (node: EntityData) => EntityData) => void;
|
|
20
24
|
getComponent: <TProperties = Record<string, any>>(name: string) => EntityComponent<TProperties> | null;
|
|
25
|
+
addComponent: (type: string, properties?: Record<string, any>) => EntityComponent | null;
|
|
26
|
+
removeComponent: (name: string) => void;
|
|
27
|
+
destroy: () => void;
|
|
21
28
|
}
|
|
22
29
|
export type EntityUpdate = (node: EntityData) => EntityData;
|
|
23
30
|
export type SceneUpdates = Record<string, EntityUpdate>;
|
|
24
31
|
export interface Scene {
|
|
25
32
|
readonly rootId: string;
|
|
26
|
-
find: (
|
|
33
|
+
find: (nameOrId: string) => Entity | null;
|
|
27
34
|
get: (id: string) => Entity;
|
|
35
|
+
create: (name: string, components?: Record<string, {
|
|
36
|
+
type: string;
|
|
37
|
+
properties?: Record<string, any>;
|
|
38
|
+
}>, options?: SpawnOptions) => Entity;
|
|
28
39
|
update: {
|
|
29
40
|
(id: string, update: EntityUpdate): void;
|
|
30
41
|
(updates: SceneUpdates): void;
|
|
@@ -35,6 +46,9 @@ export interface Scene {
|
|
|
35
46
|
interface SceneAdapter {
|
|
36
47
|
getRootId: () => string;
|
|
37
48
|
getNode: (id: string) => EntityData | null;
|
|
49
|
+
getChildIds: (id: string) => string[];
|
|
50
|
+
getParentId: (id: string) => string | null;
|
|
51
|
+
findByName: (name: string) => string | null;
|
|
38
52
|
updateNode: (id: string, update: (node: EntityData) => EntityData) => void;
|
|
39
53
|
updateNodes: (updates: Record<string, (node: EntityData) => EntityData>) => void;
|
|
40
54
|
addNode: (node: GameObject, options?: SpawnOptions) => string;
|