react-three-game 0.0.104 → 0.0.105

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.
@@ -15,7 +15,7 @@ import { Euler, Matrix4 } from "three";
15
15
  import { useStore } from "zustand";
16
16
  import { useClickValid } from "./useClickValid";
17
17
  import { findComponent, getNodeUserData } from "./types";
18
- import { getComponentDef, getComponentAssetRefs, registerComponent } from "./components/ComponentRegistry";
18
+ import { getComponentDef, registerComponent } from "./components/ComponentRegistry";
19
19
  import { builtinComponents } from "./components";
20
20
  import { loadModel, loadSound, loadTexture } from "../dragdrop";
21
21
  import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties } from "./InstanceProvider";
@@ -99,13 +99,12 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
99
99
  }
100
100
  const usesOwnedStore = resolvedStore === ownedStore;
101
101
  const rootId = useStore(resolvedStore, state => state.rootId);
102
- const assetManifestKey = useStore(resolvedStore, state => state.assetManifestKey);
102
+ const assetRefCounts = useStore(resolvedStore, state => state.assetRefCounts);
103
103
  const availableModels = useMemo(() => (Object.assign(Object.assign({}, models), injectedModels)), [models, injectedModels]);
104
- const availableTextures = useMemo(() => (Object.assign(Object.assign({}, textures), injectedTextures)), [textures, injectedTextures]);
105
- const availableSounds = useMemo(() => (Object.assign(Object.assign({}, sounds), injectedSounds)), [sounds, injectedSounds]);
106
104
  const getModel = useCallback((path) => { var _a; return (_a = availableModels[path]) !== null && _a !== void 0 ? _a : null; }, [availableModels]);
107
- const getTexture = useCallback((path) => { var _a; return (_a = availableTextures[path]) !== null && _a !== void 0 ? _a : null; }, [availableTextures]);
108
- const getSound = useCallback((path) => { var _a; return (_a = availableSounds[path]) !== null && _a !== void 0 ? _a : null; }, [availableSounds]);
105
+ const getTexture = useCallback((path) => { var _a, _b; return (_b = (_a = injectedTextures[path]) !== null && _a !== void 0 ? _a : textures[path]) !== null && _b !== void 0 ? _b : null; }, [injectedTextures, textures]);
106
+ const getSound = useCallback((path) => { var _a, _b; return (_b = (_a = injectedSounds[path]) !== null && _a !== void 0 ? _a : sounds[path]) !== null && _b !== void 0 ? _b : null; }, [injectedSounds, sounds]);
107
+ const assetRevision = useMemo(() => `${Object.keys(textures).concat(Object.keys(injectedTextures)).sort().join('|')}::${Object.keys(availableModels).sort().join('|')}`, [availableModels, injectedTextures, textures]);
109
108
  const getObject = useCallback((id) => {
110
109
  var _a;
111
110
  return (_a = objectRefs.current[id]) !== null && _a !== void 0 ? _a : null;
@@ -173,40 +172,23 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
173
172
  }
174
173
  }, [data, resolvedStore, usesOwnedStore]);
175
174
  useEffect(() => {
176
- void assetManifestKey;
177
- const syncAssets = (snapshot = resolvedStore.getState()) => {
178
- const modelsToLoad = new Set();
179
- const texturesToLoad = new Set();
180
- const soundsToLoad = new Set();
181
- Object.values(snapshot.nodesById).forEach(node => {
182
- var _a;
183
- Object.values((_a = node.components) !== null && _a !== void 0 ? _a : {}).forEach(component => {
184
- var _a;
185
- if (!(component === null || component === void 0 ? void 0 : component.type))
186
- return;
187
- for (const ref of getComponentAssetRefs(component.type, (_a = component.properties) !== null && _a !== void 0 ? _a : {})) {
188
- if (ref.type === 'model')
189
- modelsToLoad.add(ref.path);
190
- else if (ref.type === 'texture')
191
- texturesToLoad.add(ref.path);
192
- else if (ref.type === 'sound')
193
- soundsToLoad.add(ref.path);
194
- }
195
- });
175
+ const loadAsset = (file, loaded, injected, failed, loader) => {
176
+ if (loaded[file] || injected[file] || loading.current.has(file) || failed.has(file))
177
+ return;
178
+ loading.current.add(file);
179
+ void loader(resolveAssetPath(basePath, file)).then(result => {
180
+ loading.current.delete(file);
181
+ if (!result.success) {
182
+ console.warn(`Failed to load asset: ${file}`, result.error);
183
+ failed.add(file);
184
+ }
196
185
  });
197
- const loadAsset = (file, loaded, injected, failed, loader) => {
198
- if (loaded[file] || injected[file] || loading.current.has(file) || failed.has(file))
199
- return;
200
- loading.current.add(file);
201
- void loader(resolveAssetPath(basePath, file)).then(result => {
202
- loading.current.delete(file);
203
- if (!result.success) {
204
- console.warn(`Failed to load asset: ${file}`, result.error);
205
- failed.add(file);
206
- }
207
- });
208
- };
209
- modelsToLoad.forEach(file => {
186
+ };
187
+ Object.keys(assetRefCounts).forEach(entry => {
188
+ const separator = entry.indexOf(':');
189
+ const type = entry.slice(0, separator);
190
+ const file = entry.slice(separator + 1);
191
+ if (type === 'model') {
210
192
  loadAsset(file, models, injectedModels, failedModels.current, path => loadModel(path).then(result => {
211
193
  const loadedModel = result.model;
212
194
  if (result.success && loadedModel) {
@@ -214,8 +196,8 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
214
196
  }
215
197
  return result;
216
198
  }));
217
- });
218
- texturesToLoad.forEach(file => {
199
+ }
200
+ else if (type === 'texture') {
219
201
  loadAsset(file, textures, injectedTextures, failedTextures.current, path => loadTexture(path).then(result => {
220
202
  const loadedTexture = result.texture;
221
203
  if (result.success && loadedTexture) {
@@ -223,8 +205,8 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
223
205
  }
224
206
  return result;
225
207
  }));
226
- });
227
- soundsToLoad.forEach(file => {
208
+ }
209
+ else if (type === 'sound') {
228
210
  loadAsset(file, sounds, injectedSounds, failedSounds.current, path => loadSound(path).then(result => {
229
211
  const loadedSound = result.sound;
230
212
  if (result.success && loadedSound) {
@@ -233,10 +215,9 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
233
215
  }
234
216
  return result;
235
217
  }));
236
- });
237
- };
238
- syncAssets();
239
- }, [resolvedStore, assetManifestKey, basePath, injectedModels, injectedSounds, injectedTextures, models, sounds, textures]);
218
+ }
219
+ });
220
+ }, [assetRefCounts, basePath, injectedModels, injectedSounds, injectedTextures, models, sounds, textures]);
240
221
  const assetRuntime = useMemo(() => ({
241
222
  registerHandle,
242
223
  getHandle,
@@ -244,8 +225,8 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
244
225
  getModel,
245
226
  getTexture,
246
227
  getSound,
247
- getAssetRevision: () => `${Object.keys(availableTextures).sort().join('|')}::${Object.keys(availableModels).sort().join('|')}`,
248
- }), [registerHandle, getHandle, getObject, getModel, getTexture, getSound, availableModels, availableTextures]);
228
+ getAssetRevision: () => assetRevision,
229
+ }), [registerHandle, getHandle, getObject, getModel, getTexture, getSound, assetRevision]);
249
230
  const handleNodeClick = useCallback((event, nodeId, fallbackObject) => {
250
231
  const node = resolvedStore.getState().nodesById[nodeId];
251
232
  if (!node)
@@ -66,18 +66,19 @@ function GeometryComponentEditor({ component, onUpdate, }) {
66
66
  // View for Geometry component
67
67
  function GeometryComponentView({ properties, children }) {
68
68
  const { geometryType, args = [] } = properties;
69
+ const geometryKey = `${geometryType !== null && geometryType !== void 0 ? geometryType : 'box'}:${JSON.stringify(args)}`;
69
70
  // Only return the geometry node, do not wrap in mesh or group
70
71
  switch (geometryType) {
71
72
  case "box":
72
- return _jsx("boxGeometry", { args: args });
73
+ return _jsx("boxGeometry", { args: args }, geometryKey);
73
74
  case "sphere":
74
- return _jsx("sphereGeometry", { args: args });
75
+ return _jsx("sphereGeometry", { args: args }, geometryKey);
75
76
  case "plane":
76
- return _jsx("planeGeometry", { args: args });
77
+ return _jsx("planeGeometry", { args: args }, geometryKey);
77
78
  case "cylinder":
78
- return _jsx("cylinderGeometry", { args: args });
79
+ return _jsx("cylinderGeometry", { args: args }, geometryKey);
79
80
  default:
80
- return _jsx("boxGeometry", { args: [1, 1, 1] });
81
+ return _jsx("boxGeometry", { args: [1, 1, 1] }, "box:[1,1,1]");
81
82
  }
82
83
  }
83
84
  const GeometryComponent = {
@@ -185,7 +185,7 @@ export function cloneSubtree(id, parentId, source, nodesById, childIdsById, pare
185
185
  if (!originalNode)
186
186
  return null;
187
187
  const clonedId = crypto.randomUUID();
188
- const clonedNode = Object.assign(Object.assign({}, originalNode), { id: clonedId, name: `${(_a = originalNode.name) !== null && _a !== void 0 ? _a : originalNode.id} Copy` });
188
+ const clonedNode = Object.assign(Object.assign({}, originalNode), { components: clonePrefabValue(originalNode.components), id: clonedId, name: `${(_a = originalNode.name) !== null && _a !== void 0 ? _a : originalNode.id} Copy` });
189
189
  nodesById[clonedId] = clonedNode;
190
190
  parentIdById[clonedId] = parentId;
191
191
  const clonedChildIds = ((_b = source.childIdsById[id]) !== null && _b !== void 0 ? _b : [])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-three-game",
3
- "version": "0.0.104",
3
+ "version": "0.0.105",
4
4
  "description": "high performance 3D game engine built in React",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",