@needle-tools/engine 2.64.0-pre → 2.65.0-pre

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.
Files changed (255) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/needle-engine.js +5078 -5055
  3. package/dist/needle-engine.umd.cjs +84 -84
  4. package/lib/engine/api.js.map +1 -1
  5. package/lib/engine/assets/index.js.map +1 -1
  6. package/lib/engine/assets/logo.svg +1 -0
  7. package/lib/engine/codegen/register_types.js +169 -169
  8. package/lib/engine/codegen/register_types.js.map +1 -1
  9. package/lib/engine/debug/debug.js.map +1 -1
  10. package/lib/engine/debug/debug_console.js.map +1 -1
  11. package/lib/engine/debug/debug_overlay.js.map +1 -1
  12. package/lib/engine/debug/index.js.map +1 -1
  13. package/lib/engine/engine.js.map +1 -1
  14. package/lib/engine/engine_addressables.js.map +1 -1
  15. package/lib/engine/engine_application.js.map +1 -1
  16. package/lib/engine/engine_assetdatabase.js.map +1 -1
  17. package/lib/engine/engine_camera.js.map +1 -1
  18. package/lib/engine/engine_components.js.map +1 -1
  19. package/lib/engine/engine_constants.js.map +1 -1
  20. package/lib/engine/engine_context_registry.js.map +1 -1
  21. package/lib/engine/engine_coroutine.js.map +1 -1
  22. package/lib/engine/engine_create_objects.js.map +1 -1
  23. package/lib/engine/engine_default_parameters.js.map +1 -1
  24. package/lib/engine/engine_element.d.ts +6 -4
  25. package/lib/engine/engine_element.js +152 -165
  26. package/lib/engine/engine_element.js.map +1 -1
  27. package/lib/engine/engine_element_loading.js.map +1 -1
  28. package/lib/engine/engine_element_overlay.js.map +1 -1
  29. package/lib/engine/engine_fileloader.js.map +1 -1
  30. package/lib/engine/engine_gameobject.d.ts +4 -2
  31. package/lib/engine/engine_gameobject.js +32 -13
  32. package/lib/engine/engine_gameobject.js.map +1 -1
  33. package/lib/engine/engine_generic_utils.js.map +1 -1
  34. package/lib/engine/engine_gizmos.js.map +1 -1
  35. package/lib/engine/engine_gltf.d.ts +1 -1
  36. package/lib/engine/engine_gltf.js.map +1 -1
  37. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  38. package/lib/engine/engine_hot_reload.js.map +1 -1
  39. package/lib/engine/engine_input.js.map +1 -1
  40. package/lib/engine/engine_input_utils.js.map +1 -1
  41. package/lib/engine/engine_instancing.js.map +1 -1
  42. package/lib/engine/engine_license.js.map +1 -1
  43. package/lib/engine/engine_lightdata.js.map +1 -1
  44. package/lib/engine/engine_loaders.js.map +1 -1
  45. package/lib/engine/engine_mainloop_utils.js +36 -6
  46. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  47. package/lib/engine/engine_math.js.map +1 -1
  48. package/lib/engine/engine_networking.js.map +1 -1
  49. package/lib/engine/engine_networking_auto.js.map +1 -1
  50. package/lib/engine/engine_networking_files.js.map +1 -1
  51. package/lib/engine/engine_networking_files_default_components.js.map +1 -1
  52. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  53. package/lib/engine/engine_networking_peer.js.map +1 -1
  54. package/lib/engine/engine_networking_types.js.map +1 -1
  55. package/lib/engine/engine_networking_utils.js.map +1 -1
  56. package/lib/engine/engine_networking_websocket.js.map +1 -1
  57. package/lib/engine/engine_physics.js.map +1 -1
  58. package/lib/engine/engine_physics.types.js.map +1 -1
  59. package/lib/engine/engine_playerview.js.map +1 -1
  60. package/lib/engine/engine_rendererdata.js.map +1 -1
  61. package/lib/engine/engine_scenetools.js.map +1 -1
  62. package/lib/engine/engine_serialization.js.map +1 -1
  63. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  64. package/lib/engine/engine_serialization_core.js.map +1 -1
  65. package/lib/engine/engine_serialization_decorator.js.map +1 -1
  66. package/lib/engine/engine_setup.d.ts +5 -2
  67. package/lib/engine/engine_setup.js +14 -5
  68. package/lib/engine/engine_setup.js.map +1 -1
  69. package/lib/engine/engine_shaders.js.map +1 -1
  70. package/lib/engine/engine_texture.js.map +1 -1
  71. package/lib/engine/engine_three_utils.js.map +1 -1
  72. package/lib/engine/engine_time.js.map +1 -1
  73. package/lib/engine/engine_types.js.map +1 -1
  74. package/lib/engine/engine_typestore.js.map +1 -1
  75. package/lib/engine/engine_util_decorator.js.map +1 -1
  76. package/lib/engine/engine_utils.js.map +1 -1
  77. package/lib/engine/engine_utils_screenshot.js.map +1 -1
  78. package/lib/engine/engine_web_api.js.map +1 -1
  79. package/lib/engine/extensions/EXT_texture_exr.js.map +1 -1
  80. package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
  81. package/lib/engine/extensions/NEEDLE_components.js.map +1 -1
  82. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  83. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  84. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  85. package/lib/engine/extensions/NEEDLE_persistent_assets.js.map +1 -1
  86. package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -1
  87. package/lib/engine/extensions/NEEDLE_render_objects.js.map +1 -1
  88. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  89. package/lib/engine/extensions/extension_resolver.js.map +1 -1
  90. package/lib/engine/extensions/extension_utils.js.map +1 -1
  91. package/lib/engine/extensions/extensions.js.map +1 -1
  92. package/lib/engine/js-extensions/Camera.js.map +1 -1
  93. package/lib/engine/js-extensions/Layers.js.map +1 -1
  94. package/lib/engine/js-extensions/index.js.map +1 -1
  95. package/lib/engine/shaders/shaderData.js.map +1 -1
  96. package/lib/engine/tests/test_utils.js.map +1 -1
  97. package/lib/engine-components/AlignmentConstraint.js.map +1 -1
  98. package/lib/engine-components/Animation.js.map +1 -1
  99. package/lib/engine-components/AnimationCurve.js.map +1 -1
  100. package/lib/engine-components/Animator.js.map +1 -1
  101. package/lib/engine-components/AnimatorController.js.map +1 -1
  102. package/lib/engine-components/AudioListener.js.map +1 -1
  103. package/lib/engine-components/AudioSource.js.map +1 -1
  104. package/lib/engine-components/AvatarLoader.js.map +1 -1
  105. package/lib/engine-components/AxesHelper.js.map +1 -1
  106. package/lib/engine-components/BasicIKConstraint.js.map +1 -1
  107. package/lib/engine-components/BoxCollider.js.map +1 -1
  108. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  109. package/lib/engine-components/Camera.d.ts +3 -1
  110. package/lib/engine-components/Camera.js +11 -10
  111. package/lib/engine-components/Camera.js.map +1 -1
  112. package/lib/engine-components/CameraUtils.js.map +1 -1
  113. package/lib/engine-components/CharacterController.js.map +1 -1
  114. package/lib/engine-components/Collider.js.map +1 -1
  115. package/lib/engine-components/Component.d.ts +1 -1
  116. package/lib/engine-components/Component.js +2 -2
  117. package/lib/engine-components/Component.js.map +1 -1
  118. package/lib/engine-components/DeleteBox.js.map +1 -1
  119. package/lib/engine-components/DeviceFlag.js.map +1 -1
  120. package/lib/engine-components/DragControls.js.map +1 -1
  121. package/lib/engine-components/DropListener.js.map +1 -1
  122. package/lib/engine-components/Duplicatable.js.map +1 -1
  123. package/lib/engine-components/EventList.js.map +1 -1
  124. package/lib/engine-components/EventTrigger.js.map +1 -1
  125. package/lib/engine-components/EventType.js.map +1 -1
  126. package/lib/engine-components/FlyControls.js.map +1 -1
  127. package/lib/engine-components/Fog.js.map +1 -1
  128. package/lib/engine-components/Gizmos.js.map +1 -1
  129. package/lib/engine-components/GridHelper.js.map +1 -1
  130. package/lib/engine-components/GroundProjection.js.map +1 -1
  131. package/lib/engine-components/Interactable.js.map +1 -1
  132. package/lib/engine-components/Joints.js.map +1 -1
  133. package/lib/engine-components/LODGroup.js.map +1 -1
  134. package/lib/engine-components/Light.d.ts +0 -2
  135. package/lib/engine-components/Light.js +22 -14
  136. package/lib/engine-components/Light.js.map +1 -1
  137. package/lib/engine-components/LookAtConstraint.js.map +1 -1
  138. package/lib/engine-components/NestedGltf.js.map +1 -1
  139. package/lib/engine-components/Networking.js.map +1 -1
  140. package/lib/engine-components/OffsetConstraint.js.map +1 -1
  141. package/lib/engine-components/OrbitControls.js.map +1 -1
  142. package/lib/engine-components/ParticleSystem.js.map +1 -1
  143. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  144. package/lib/engine-components/ParticleSystemSubEmitter.js.map +1 -1
  145. package/lib/engine-components/PlayerColor.js.map +1 -1
  146. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  147. package/lib/engine-components/Renderer.js.map +1 -1
  148. package/lib/engine-components/RendererLightmap.js.map +1 -1
  149. package/lib/engine-components/RigidBody.js.map +1 -1
  150. package/lib/engine-components/ScreenCapture.js.map +1 -1
  151. package/lib/engine-components/ShadowCatcher.js.map +1 -1
  152. package/lib/engine-components/Skybox.d.ts +2 -0
  153. package/lib/engine-components/Skybox.js +43 -21
  154. package/lib/engine-components/Skybox.js.map +1 -1
  155. package/lib/engine-components/SmoothFollow.js.map +1 -1
  156. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  157. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  158. package/lib/engine-components/SphereCollider.js.map +1 -1
  159. package/lib/engine-components/SpriteRenderer.js.map +1 -1
  160. package/lib/engine-components/SyncedCamera.js.map +1 -1
  161. package/lib/engine-components/SyncedRoom.js.map +1 -1
  162. package/lib/engine-components/SyncedTransform.js.map +1 -1
  163. package/lib/engine-components/TestRunner.js.map +1 -1
  164. package/lib/engine-components/TransformGizmo.js.map +1 -1
  165. package/lib/engine-components/VideoPlayer.js.map +1 -1
  166. package/lib/engine-components/Voip.js.map +1 -1
  167. package/lib/engine-components/Volume.js +2 -0
  168. package/lib/engine-components/Volume.js.map +1 -1
  169. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  170. package/lib/engine-components/WebXR.js.map +1 -1
  171. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  172. package/lib/engine-components/WebXRController.js.map +1 -1
  173. package/lib/engine-components/WebXRGrabRendering.js.map +1 -1
  174. package/lib/engine-components/WebXRRig.js.map +1 -1
  175. package/lib/engine-components/WebXRSync.js.map +1 -1
  176. package/lib/engine-components/XRFlag.js.map +1 -1
  177. package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +1 -1
  178. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +1 -1
  179. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +1 -1
  180. package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +1 -1
  181. package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +1 -1
  182. package/lib/engine-components/codegen/components.js.map +1 -1
  183. package/lib/engine-components/debug/LogStats.js.map +1 -1
  184. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  185. package/lib/engine-components/export/usdz/Extension.js.map +1 -1
  186. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  187. package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -1
  188. package/lib/engine-components/export/usdz/types.js.map +1 -1
  189. package/lib/engine-components/export/usdz/utils/animationutils.js.map +1 -1
  190. package/lib/engine-components/export/usdz/utils/quicklook.js.map +1 -1
  191. package/lib/engine-components/export/usdz/utils/timeutils.js.map +1 -1
  192. package/lib/engine-components/js-extensions/ExtensionUtils.js.map +1 -1
  193. package/lib/engine-components/js-extensions/Object3D.js +1 -1
  194. package/lib/engine-components/js-extensions/Object3D.js.map +1 -1
  195. package/lib/engine-components/js-extensions/RGBAColor.js.map +1 -1
  196. package/lib/engine-components/js-extensions/Vector.js.map +1 -1
  197. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  198. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  199. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  200. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  201. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  202. package/lib/engine-components/ui/Button.js.map +1 -1
  203. package/lib/engine-components/ui/Canvas.js +2 -2
  204. package/lib/engine-components/ui/Canvas.js.map +1 -1
  205. package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
  206. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  207. package/lib/engine-components/ui/Graphic.js.map +1 -1
  208. package/lib/engine-components/ui/Image.js.map +1 -1
  209. package/lib/engine-components/ui/InputField.js.map +1 -1
  210. package/lib/engine-components/ui/Interfaces.js.map +1 -1
  211. package/lib/engine-components/ui/Keyboard.js.map +1 -1
  212. package/lib/engine-components/ui/Layout.js.map +1 -1
  213. package/lib/engine-components/ui/PointerEvents.js.map +1 -1
  214. package/lib/engine-components/ui/RaycastUtils.js.map +1 -1
  215. package/lib/engine-components/ui/Raycaster.js.map +1 -1
  216. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  217. package/lib/engine-components/ui/SpatialHtml.js.map +1 -1
  218. package/lib/engine-components/ui/Text.js.map +1 -1
  219. package/lib/engine-components/ui/Utils.js.map +1 -1
  220. package/lib/engine-components-experimental/Presentation.js.map +1 -1
  221. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  222. package/lib/engine-schemes/schemes.js.map +1 -1
  223. package/lib/engine-schemes/synced-camera-model.js.map +1 -1
  224. package/lib/engine-schemes/synced-transform-model.js.map +1 -1
  225. package/lib/engine-schemes/transform.js.map +1 -1
  226. package/lib/engine-schemes/vec2.js.map +1 -1
  227. package/lib/engine-schemes/vec3.js.map +1 -1
  228. package/lib/engine-schemes/vec4.js.map +1 -1
  229. package/lib/engine-schemes/vr-user-state-buffer.js.map +1 -1
  230. package/lib/include/three/ARButton.js.map +1 -1
  231. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js.map +1 -1
  232. package/lib/include/three/VRButton.js.map +1 -1
  233. package/lib/needle-engine.js.map +1 -1
  234. package/package.json +16 -3
  235. package/plugins/generate-font.js +65 -0
  236. package/plugins/vite/poster-client.js +3 -5
  237. package/plugins/vite/reload.js +2 -2
  238. package/src/engine/codegen/register_types.js +171 -171
  239. package/src/engine/engine_element.ts +162 -178
  240. package/src/engine/engine_gameobject.ts +583 -558
  241. package/src/engine/engine_gltf.ts +1 -1
  242. package/src/engine/engine_mainloop_utils.ts +36 -7
  243. package/src/engine/engine_setup.ts +20 -7
  244. package/src/engine-components/Camera.ts +14 -12
  245. package/src/engine-components/Component.ts +2 -2
  246. package/src/engine-components/Light.ts +20 -13
  247. package/src/engine-components/Skybox.ts +49 -22
  248. package/src/engine-components/Volume.ts +1 -0
  249. package/src/engine-components/js-extensions/Object3D.ts +1 -1
  250. package/src/engine-components/ui/Canvas.ts +2 -2
  251. package/lib/tsconfig.tsbuildinfo +0 -1
  252. package/lib/vite.config.d.ts +0 -2
  253. package/lib/vite.config.js +0 -26
  254. package/lib/vite.config.js.map +0 -1
  255. package/src/tsconfig.json +0 -33
@@ -1,559 +1,584 @@
1
- import { Object3D } from "three";
2
- import { processNewScripts } from "./engine_mainloop_utils";
3
- import { InstantiateIdProvider } from "./engine_networking_instantiate";
4
- import { Context, registerComponent } from "./engine_setup";
5
- import { logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_three_utils";
6
- import { GuidsMap, IComponent as Component, IComponent, IGameObject as GameObject, UIDProvider } from "./engine_types";
7
- import { getParam, tryFindObject } from "./engine_utils";
8
- import { apply } from "../engine-components/js-extensions/Object3D";
9
- import { $isUsingInstancing, InstancingUtil } from "./engine_instancing";
10
- import { activeInHierarchyFieldName } from "./engine_constants";
11
- import { assign } from "./engine_serialization_core";
12
-
13
- const debug = getParam("debuggetcomponent");
14
-
15
-
16
- export enum HideFlags {
17
- None = 0,
18
- HideInHierarchy = 1,
19
- HideInInspector = 2,
20
- DontSaveInEditor = 4,
21
- NotEditable = 8,
22
- DontSaveInBuild = 16, // 0x00000010
23
- DontUnloadUnusedAsset = 32, // 0x00000020
24
- DontSave = DontUnloadUnusedAsset | DontSaveInBuild | DontSaveInEditor, // 0x00000034
25
- HideAndDontSave = DontSave | NotEditable | HideInHierarchy, // 0x0000003D
26
- }
27
-
28
-
29
- export class InstantiateOptions {
30
- idProvider?: UIDProvider | undefined;
31
-
32
- //** parent guid */
33
- parent?: string | undefined | Object3D;
34
- /** for duplicatable parenting */
35
- keepWorldPosition?: boolean
36
- position?: THREE.Vector3 | undefined;
37
- rotation?: THREE.Quaternion | undefined;
38
- scale?: THREE.Vector3 | undefined;
39
-
40
- visible?: boolean | undefined;
41
-
42
- context?: Context | undefined;
43
- }
44
-
45
-
46
- // export function setActive(go: Object3D, active: boolean, processStart: boolean = true) {
47
- // if (!go) return;
48
- // go.visible = active;
49
- // main.updateActiveInHierarchyWithoutEventCall(go);
50
- // if (active && processStart)
51
- // main.processStart(Context.Current, go);
52
- // }
53
-
54
-
55
- const $isActive = Symbol("isActive");
56
- export function isActiveSelf(go: Object3D): boolean {
57
- const visible = go.visible || isUsingInstancing(go);
58
- if (go[$isActive] === undefined) {
59
- // initialize object to active so if someone's object start invisible and is set to visible = true
60
- // it should activate the components
61
- go[$isActive] = true;
62
- }
63
- return go[$isActive] && visible;
64
- }
65
-
66
- export function setActive(go: Object3D, active: boolean | number, setVisible = true): boolean {
67
- if (typeof active === "number") active = active > .5;
68
- go[$isActive] = active;
69
- if (setVisible) go.visible = active;
70
- return go[$isActive];
71
- }
72
-
73
- export function isActiveInHierarchy(go: Object3D): boolean {
74
- return go[activeInHierarchyFieldName] || isUsingInstancing(go);
75
- }
76
-
77
- export function markAsInstancedRendered(go: THREE.Object3D, instanced: boolean) {
78
- go[$isUsingInstancing] = instanced;
79
- }
80
-
81
- export function isUsingInstancing(instance: THREE.Object3D): boolean { return InstancingUtil.isUsingInstancing(instance); }
82
-
83
-
84
- export function findByGuid(guid: string, hierarchy: THREE.Object3D): GameObject | IComponent | null | undefined {
85
- return tryFindObject(guid, hierarchy, true, true);
86
- }
87
-
88
-
89
- const $isDestroyed = Symbol("isDestroyed");
90
- export function isDestroyed(go: Object3D): boolean {
91
- return go[$isDestroyed];
92
- }
93
- export function setDestroyed(go: Object3D, value: boolean) {
94
- go[$isDestroyed] = value;
95
- }
96
-
97
- export function destroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false) {
98
- internalDestroy(instance, recursive, dispose, true);
99
- }
100
-
101
- function internalDestroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false, isRoot: boolean = true) {
102
- const comp = instance as Component;
103
- if (comp.isComponent) {
104
- comp.__internalDisable();
105
- comp.__internalDestroy();
106
- return;
107
- }
108
-
109
-
110
- const obj = instance as GameObject;
111
- if (dispose) disposeObject(obj);
112
- setDestroyed(obj, true);
113
-
114
-
115
- if (debug) console.log(obj);
116
-
117
- if (recursive && obj.children) {
118
- for (const ch of obj.children) {
119
- internalDestroy(ch, recursive, false, false);
120
- }
121
- }
122
-
123
- const components = obj.userData.components;
124
- if (components) {
125
- let lastLength = components.length;
126
- for (let i = 0; i < components.length; i++) {
127
- const comp: Component = components[i];
128
- comp.__internalDisable();
129
- comp.__internalDestroy();
130
- // if (comp.destroy) {
131
- // if (debug) console.log("destroying", comp);
132
- // comp.destroy();
133
- // }
134
- // components will be removed from componentlist in destroy
135
- if (components.length < lastLength) {
136
- lastLength = components.length;
137
- i--;
138
- }
139
- }
140
- }
141
- if (isRoot)
142
- obj.removeFromParent();
143
- }
144
-
145
- function disposeObject(obj: Object3D) {
146
- if (!obj) return;
147
- const mesh = obj as THREE.Mesh;
148
- if (mesh.geometry) {
149
- mesh.geometry.dispose();
150
- }
151
- if (mesh.material) {
152
- if (Array.isArray(mesh.material)) {
153
- mesh.material.forEach(m => m.dispose());
154
- } else {
155
- mesh.material.dispose();
156
- }
157
- }
158
- }
159
-
160
- export function foreachComponent(instance: THREE.Object3D, cb: (comp: Component) => any, recursive: boolean = true): any {
161
- if (!instance) return;
162
- if (!instance.isObject3D) {
163
- new Error("Expected Object3D but got " + instance);
164
- }
165
- if (instance.userData?.components) {
166
- for (let i = 0; i < instance.userData.components.length; i++) {
167
- const comp = instance.userData.components[i];
168
- if (comp?.isComponent === true) {
169
- const res = cb(comp);
170
- if (res !== undefined) return res;
171
- }
172
- }
173
- }
174
-
175
- if (recursive && instance.children) {
176
- for (let i = 0; i < instance.children.length; i++) {
177
- const child = instance.children[i];
178
- if (!child) continue;
179
- const res = foreachComponent(child, cb, recursive);
180
- if (res !== undefined) return res;
181
- }
182
- }
183
- }
184
-
185
-
186
- declare class NewGameObjectReferenceInfo {
187
- original: THREE.Object3D;
188
- clone: THREE.Object3D;
189
- }
190
-
191
- export function instantiate(instance: GameObject | Object3D | null, opts: InstantiateOptions | null = null): GameObject | null {
192
- if (instance === null) return null;
193
-
194
- let options: InstantiateOptions | null = null;
195
- if (opts !== null) {
196
- // if x is defined assume this is a vec3 - this is just to not break everything at once and stay a little bit backwards compatible
197
- if (opts["x"] !== undefined) {
198
- options = new InstantiateOptions();
199
- options.position = opts as unknown as THREE.Vector3;
200
- }
201
- else {
202
- // if (opts instanceof InstantiateOptions)
203
- options = opts as InstantiateOptions;
204
- // else {
205
- // options = new InstantiateOptions();
206
- // Object.assign(options, opts);
207
- // }
208
- }
209
- }
210
-
211
- let context = Context.Current;
212
- if (options?.context) context = options.context;
213
- if (debug && context.alias)
214
- console.log("context", context.alias);
215
-
216
- // we need to create the id provider before calling internal instantiate because cloned gameobjects also create new guids
217
- if (options && !options.idProvider) {
218
- options.idProvider = new InstantiateIdProvider(Date.now());
219
- }
220
-
221
- const components: Array<Component> = [];
222
- const goMapping: { [key: string]: NewGameObjectReferenceInfo } = {}; // used to resolve references on components to components on other gameobjects to their new counterpart
223
- const skinnedMeshes: { [key: string]: NewGameObjectReferenceInfo } = {};
224
- const clone = internalInstantiate(context, instance, options, components, goMapping, skinnedMeshes);
225
-
226
- if (clone) {
227
- resolveReferences(goMapping);
228
- resolveAndBindSkinnedMeshBones(skinnedMeshes, goMapping);
229
- }
230
-
231
- if (debug) {
232
- logHierarchy(instance, true);
233
- logHierarchy(clone, true);
234
- }
235
-
236
- const guidsMap: GuidsMap = {};
237
- for (const i in components) {
238
- const copy = components[i];
239
- const oldGuid = copy.guid;
240
- if (options && options.idProvider) {
241
- copy.guid = options.idProvider.generateUUID();
242
- guidsMap[oldGuid] = copy.guid;
243
- if (debug)
244
- console.log(copy.name, copy.guid)
245
- }
246
- registerComponent(copy, context);
247
- if (copy.__internalNewInstanceCreated)
248
- copy.__internalNewInstanceCreated();
249
- }
250
- for (const i in components) {
251
- const copy = components[i];
252
- if (copy.resolveGuids)
253
- copy.resolveGuids(guidsMap);
254
- if (copy.enabled === false) continue;
255
- else copy.enabled = true;
256
- }
257
-
258
- processNewScripts(context);
259
-
260
- return clone as GameObject;
261
- }
262
-
263
-
264
- function internalInstantiate(
265
- context: Context, instance: GameObject | THREE.Object3D, opts: InstantiateOptions | null,
266
- componentsList: Array<Component>,
267
- newGameObjectsMap: { [key: string]: NewGameObjectReferenceInfo },
268
- skinnedMeshesMap: { [key: string]: NewGameObjectReferenceInfo }
269
- )
270
- : GameObject | THREE.Object3D | null {
271
- if (!instance) return null;
272
- // prepare, remove things that dont work out of the box
273
- // e.g. user data we want to manually clone
274
- // also children throw errors (e.g. recursive toJson with nested meshes)
275
- const userData = instance.userData;
276
- instance.userData = {};
277
- const children = instance.children;
278
- instance.children = [];
279
- let clone: THREE.Object3D | GameObject;
280
- clone = instance.clone(false);
281
- apply(clone);
282
- instance.userData = userData;
283
- instance.children = children;
284
-
285
- // make reference from old id to new object
286
- newGameObjectsMap[instance.uuid] = { original: instance, clone: clone };
287
-
288
- if (instance.type === "SkinnedMesh") {
289
- skinnedMeshesMap[instance.uuid] = { original: instance, clone: clone };
290
- }
291
-
292
- // DO NOT EVER RENAME BECAUSE IT BREAKS / MIGHT BREAK ANIMATIONS
293
- // clone.name += " (Clone)";
294
-
295
- if (opts?.visible !== undefined)
296
- clone.visible = opts.visible;
297
-
298
- if (opts?.idProvider) {
299
- clone.uuid = opts.idProvider.generateUUID();
300
- const cloneGo: GameObject = clone as GameObject;
301
- if (cloneGo) cloneGo.guid = clone.uuid;
302
- }
303
-
304
- if (instance.animations && instance.animations.length > 0) {
305
- clone.animations = [...instance.animations];
306
- }
307
-
308
- const parent = instance.parent;
309
- if (parent) {
310
- parent.add(clone);
311
- }
312
-
313
- // apply transform
314
- if (opts?.position) {
315
- setWorldPosition(clone, opts.position);
316
- }
317
- else clone.position.copy(instance.position);
318
- if (opts?.rotation) {
319
- setWorldQuaternion(clone, opts.rotation);
320
- // clone.quaternion.copy(opts.rotation);
321
- }
322
- else clone.quaternion.copy(instance.quaternion);
323
- if (opts?.scale) {
324
- // TODO: make set world scale work
325
- clone.scale.copy(opts.scale);
326
- }
327
- else clone.scale.copy(instance.scale);
328
-
329
- if (opts?.parent && opts.parent !== "scene") {
330
- let requestedParent: Object3D | null = null;
331
- if (typeof opts.parent === "string") {
332
- requestedParent = tryFindObject(opts.parent, context.scene, true);
333
- }
334
- else {
335
- requestedParent = opts.parent;
336
- }
337
- if (requestedParent) {
338
- const func = opts.keepWorldPosition === true ? requestedParent.attach : requestedParent.add;
339
- if (!func) console.error("Invalid parent object", requestedParent, "received when instantiating:", instance);
340
- else func.call(requestedParent, clone);
341
- }
342
- else console.warn("could not find parent:", opts.parent);
343
- }
344
-
345
- for (const [key, value] of Object.entries(instance.userData)) {
346
- if (key === "components") continue;
347
- clone.userData[key] = value;
348
- }
349
-
350
- if (instance.userData?.components) {
351
- const components = instance.userData.components;
352
- const newComponents: Component[] = [];
353
- clone.userData.components = newComponents;
354
- for (let i = 0; i < components.length; i++) {
355
- const comp = components[i];
356
- const copy = Object.create(comp);
357
- assign(copy, comp);
358
- newComponents.push(copy);
359
- copy.gameObject = clone;
360
- // copy.transform = clone;
361
- componentsList.push(copy);
362
- }
363
- }
364
-
365
- // children should just clone the original transform
366
- if (opts) {
367
- opts.position = undefined;
368
- opts.rotation = undefined;
369
- opts.scale = undefined;
370
- opts.parent = undefined;
371
- }
372
-
373
- for (const ch in instance.children) {
374
- const child = instance.children[ch];
375
- const newChild = internalInstantiate(context, child as GameObject, opts, componentsList, newGameObjectsMap, skinnedMeshesMap);
376
- if (newChild)
377
- clone.add(newChild);
378
- }
379
-
380
- return clone;
381
-
382
- }
383
-
384
- function resolveAndBindSkinnedMeshBones(
385
- skinnedMeshes: { [key: string]: NewGameObjectReferenceInfo },
386
- newObjectsMap: { [key: string]: NewGameObjectReferenceInfo }
387
- ) {
388
- for (const key in skinnedMeshes) {
389
- const val = skinnedMeshes[key];
390
- const original = val.original as THREE.SkinnedMesh;
391
- const originalSkeleton = original.skeleton;
392
- const clone = val.clone as THREE.SkinnedMesh;
393
- // clone.updateWorldMatrix(true, true);
394
- if (!originalSkeleton) {
395
- console.warn("Skinned mesh has no skeleton?", val);
396
- continue;
397
- }
398
- const originalBones = originalSkeleton.bones;
399
- const clonedSkeleton = clone.skeleton.clone();
400
-
401
- clone.skeleton = clonedSkeleton;
402
- clone.bindMatrix.clone().copy(original.bindMatrix);
403
- // console.log(clone.bindMatrix)
404
- clone.bindMatrixInverse.copy(original.bindMatrixInverse);
405
- // clone.bindMatrix.multiplyScalar(.025);
406
- // console.assert(originalSkeleton.uuid !== clonedSkeleton.uuid);
407
- // console.assert(originalBones.length === clonedSkeleton.bones.length);
408
- const bones: Array<THREE.Bone> = [];
409
- clonedSkeleton.bones = bones;
410
- for (let i = 0; i < originalBones.length; i++) {
411
- const bone = originalBones[i];
412
- const newBoneInfo = newObjectsMap[bone.uuid];
413
- const clonedBone = newBoneInfo.clone as THREE.Bone;
414
- // console.log("NEW BONE: ", clonedBone, "BEFORE", newBoneInfo.original);
415
- bones.push(clonedBone);
416
- }
417
- // clone.skeleton = new THREE.Skeleton(bones);
418
- // clone.skeleton.update();
419
- // clone.pose();
420
- // clone.scale.set(1,1,1);
421
- // clone.position.y += .1;
422
- // console.log("ORIG", original, "CLONE", clone);
423
- }
424
- for (const key in skinnedMeshes) {
425
- const clone = skinnedMeshes[key].clone as THREE.SkinnedMesh;
426
- clone.skeleton.update();
427
- // clone.skeleton.calculateInverses();
428
- clone.bind(clone.skeleton, clone.bindMatrix);
429
- clone.updateMatrixWorld(true);
430
- // clone.pose();
431
- }
432
- }
433
-
434
- // private static bindNewSkinnedMeshBones(source, clone) {
435
- // const sourceLookup = new Map();
436
- // const cloneLookup = new Map();
437
- // // const clone = source.clone(false);
438
-
439
- // function parallelTraverse(a, b, callback) {
440
- // callback(a, b);
441
- // for (let i = 0; i < a.children.length; i++) {
442
- // parallelTraverse(a.children[i], b.children[i], callback);
443
- // }
444
- // }
445
- // parallelTraverse(source, clone, function (sourceNode, clonedNode) {
446
- // sourceLookup.set(clonedNode, sourceNode);
447
- // cloneLookup.set(sourceNode, clonedNode);
448
- // });
449
-
450
- // clone.traverse(function (node) {
451
- // if (!node.isSkinnedMesh) return;
452
- // const clonedMesh = node;
453
- // const sourceMesh = sourceLookup.get(node);
454
- // const sourceBones = sourceMesh.skeleton.bones;
455
-
456
- // clonedMesh.skeleton = sourceMesh.skeleton.clone();
457
- // clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix);
458
-
459
- // clonedMesh.skeleton.bones = sourceBones.map(function (bone) {
460
- // return cloneLookup.get(bone);
461
- // });
462
- // clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix);
463
- // });
464
- // return clone;
465
-
466
- // }
467
-
468
- function resolveReferences(newObjectsMap: { [key: string]: NewGameObjectReferenceInfo }) {
469
- // for every object that is newly created we want to update references to their newly created counterparts
470
- // e.g. a collider instance referencing a rigidbody instance should be updated so that
471
- // the cloned collider does not reference the cloned rigidbody (instead of the original rigidbody)
472
- for (const key in newObjectsMap) {
473
- const val = newObjectsMap[key];
474
- const clone = val.clone;
475
- // resolve references
476
- if (clone.userData?.components) {
477
- for (let i = 0; i < clone.userData.components.length; i++) {
478
- const copy = clone.userData.components[i];
479
- // find referenced within a cloned gameobject
480
- const entries = Object.entries(copy);
481
- // console.log(copy, entries);
482
- for (const [key, value] of entries) {
483
- if (Array.isArray(value)) {
484
- const clonedArray: Array<any> = [];
485
- copy[key] = clonedArray;
486
- // console.log(copy, key, value, copy[key]);
487
- for (let i = 0; i < value.length; i++) {
488
- const entry = value[i];
489
- // push value types into new array
490
- if (typeof entry !== "object") {
491
- clonedArray.push(entry);
492
- continue;
493
- }
494
- const res: any = postProcessNewInstance(copy, key, entry, newObjectsMap);
495
- if (res !== undefined)
496
- clonedArray.push(res);
497
- else clonedArray.push(entry);
498
- }
499
- // console.log(copy[key])
500
- }
501
- else if (typeof value === "object") {
502
- const res = postProcessNewInstance(copy, key, value as IComponent | Object3D, newObjectsMap);
503
- if (res !== undefined) {
504
- copy[key] = res;
505
- }
506
- }
507
- }
508
- }
509
- }
510
- }
511
-
512
- }
513
-
514
- function postProcessNewInstance(copy: THREE.Object3D, key: string, value: IComponent | Object3D | any, newObjectsMap: { [key: string]: NewGameObjectReferenceInfo }) {
515
- if (value === null || value === undefined) return;
516
- if ((value as IComponent).isComponent === true) {
517
- const originalGameObjectReference = value["gameObject"];
518
- // console.log(key, value, originalGameObjectReference);
519
- if (originalGameObjectReference) {
520
- const id = originalGameObjectReference.uuid;
521
- const newGameObject = newObjectsMap[id]?.clone;
522
- if (!newGameObject) {
523
- // reference has not changed!
524
- if (debug)
525
- console.log("reference did not change", key, copy, value);
526
- return;
527
- }
528
- const index = originalGameObjectReference.userData.components.indexOf(value);
529
- if (index >= 0) {
530
- if (debug)
531
- console.log(key, id);
532
- const found = newGameObject.userData.components[index];
533
- return found;
534
- }
535
- else {
536
- console.warn("could not find component", key, value);
537
- }
538
- }
539
- } else if ((value as Object3D).isObject3D === true) {
540
- // console.log(value);
541
- if (key === "gameObject") return;
542
- const originalGameObjectReference = value as Object3D;
543
- if (originalGameObjectReference) {
544
- const id = originalGameObjectReference.uuid;
545
- const newGameObject = newObjectsMap[id]?.clone;
546
- if (newGameObject) {
547
- if (debug)
548
- console.log(key, "old", value, "new", newGameObject);
549
- return newGameObject;
550
- }
551
- }
552
- }
553
- else {
554
- // create new instances for some types that we know should usually not be shared and can safely be cloned
555
- if (value.isVector4 || value.isVector3 || value.isVector2 || value.isQuaternion || value.isEuler) {
556
- return value.clone();
557
- }
558
- }
1
+ import { Object3D } from "three";
2
+ import { processNewScripts } from "./engine_mainloop_utils";
3
+ import { InstantiateIdProvider } from "./engine_networking_instantiate";
4
+ import { Context, registerComponent } from "./engine_setup";
5
+ import { logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_three_utils";
6
+ import { GuidsMap, IComponent as Component, IComponent, IGameObject as GameObject, UIDProvider } from "./engine_types";
7
+ import { getParam, tryFindObject } from "./engine_utils";
8
+ import { apply } from "../engine-components/js-extensions/Object3D";
9
+ import { $isUsingInstancing, InstancingUtil } from "./engine_instancing";
10
+ import { activeInHierarchyFieldName } from "./engine_constants";
11
+ import { assign } from "./engine_serialization_core";
12
+
13
+ const debug = getParam("debuggetcomponent");
14
+
15
+
16
+ export enum HideFlags {
17
+ None = 0,
18
+ HideInHierarchy = 1,
19
+ HideInInspector = 2,
20
+ DontSaveInEditor = 4,
21
+ NotEditable = 8,
22
+ DontSaveInBuild = 16, // 0x00000010
23
+ DontUnloadUnusedAsset = 32, // 0x00000020
24
+ DontSave = DontUnloadUnusedAsset | DontSaveInBuild | DontSaveInEditor, // 0x00000034
25
+ HideAndDontSave = DontSave | NotEditable | HideInHierarchy, // 0x0000003D
26
+ }
27
+
28
+
29
+ export class InstantiateOptions {
30
+ idProvider?: UIDProvider | undefined;
31
+
32
+ //** parent guid */
33
+ parent?: string | undefined | Object3D;
34
+ /** for duplicatable parenting */
35
+ keepWorldPosition?: boolean
36
+ position?: THREE.Vector3 | undefined;
37
+ rotation?: THREE.Quaternion | undefined;
38
+ scale?: THREE.Vector3 | undefined;
39
+
40
+ visible?: boolean | undefined;
41
+
42
+ context?: Context | undefined;
43
+ }
44
+
45
+
46
+ // export function setActive(go: Object3D, active: boolean, processStart: boolean = true) {
47
+ // if (!go) return;
48
+ // go.visible = active;
49
+ // main.updateActiveInHierarchyWithoutEventCall(go);
50
+ // if (active && processStart)
51
+ // main.processStart(Context.Current, go);
52
+ // }
53
+
54
+
55
+ // Object.defineProperty(Object3D.prototype, "visible", {
56
+ // get: function () {
57
+ // return this._visible;
58
+ // },
59
+ // set: function (val) {
60
+ // // const changed = val !== this._visible;
61
+ // this._visible = val;
62
+ // // if (changed) {
63
+ // // setActive(this, val);
64
+ // // }
65
+ // }
66
+ // });
67
+
68
+
69
+ const $isActive = Symbol("isActive");
70
+ export function isActiveSelf(go: Object3D): boolean {
71
+ // if (go[$isActive] === undefined) {
72
+ // go[$isActive] = true;
73
+ // }
74
+ return go.visible;
75
+ }
76
+
77
+ export function setActive(go: Object3D, active: boolean | number): boolean {
78
+ if (typeof active === "number") active = active > .5;
79
+ // go[$isActive] = active;
80
+ go.visible = active;
81
+ return go.visible;// go[$isActive];
82
+ }
83
+
84
+ export function isActiveInHierarchy(go: Object3D): boolean {
85
+ return go[activeInHierarchyFieldName] || isUsingInstancing(go);
86
+ }
87
+
88
+ export function markAsInstancedRendered(go: THREE.Object3D, instanced: boolean) {
89
+ go[$isUsingInstancing] = instanced;
90
+ }
91
+
92
+ export function isUsingInstancing(instance: THREE.Object3D): boolean { return InstancingUtil.isUsingInstancing(instance); }
93
+
94
+
95
+ export function findByGuid(guid: string, hierarchy: THREE.Object3D): GameObject | IComponent | null | undefined {
96
+ return tryFindObject(guid, hierarchy, true, true);
97
+ }
98
+
99
+
100
+ const $isDestroyed = Symbol("isDestroyed");
101
+ export function isDestroyed(go: Object3D): boolean {
102
+ return go[$isDestroyed];
103
+ }
104
+ export function setDestroyed(go: Object3D, value: boolean) {
105
+ go[$isDestroyed] = value;
106
+ }
107
+
108
+ export function destroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false) {
109
+ internalDestroy(instance, recursive, dispose, true);
110
+ }
111
+
112
+ function internalDestroy(instance: Object3D | Component, recursive: boolean = true, dispose: boolean = false, isRoot: boolean = true) {
113
+ const comp = instance as Component;
114
+ if (comp.isComponent) {
115
+ comp.__internalDisable();
116
+ comp.__internalDestroy();
117
+ return;
118
+ }
119
+
120
+
121
+ const obj = instance as GameObject;
122
+ if (dispose) disposeObject(obj);
123
+ setDestroyed(obj, true);
124
+
125
+
126
+ if (debug) console.log(obj);
127
+
128
+ if (recursive && obj.children) {
129
+ for (const ch of obj.children) {
130
+ internalDestroy(ch, recursive, false, false);
131
+ }
132
+ }
133
+
134
+ const components = obj.userData.components;
135
+ if (components) {
136
+ let lastLength = components.length;
137
+ for (let i = 0; i < components.length; i++) {
138
+ const comp: Component = components[i];
139
+ comp.__internalDisable();
140
+ comp.__internalDestroy();
141
+ // if (comp.destroy) {
142
+ // if (debug) console.log("destroying", comp);
143
+ // comp.destroy();
144
+ // }
145
+ // components will be removed from componentlist in destroy
146
+ if (components.length < lastLength) {
147
+ lastLength = components.length;
148
+ i--;
149
+ }
150
+ }
151
+ }
152
+ if (isRoot)
153
+ obj.removeFromParent();
154
+ }
155
+
156
+ function disposeObject(obj: Object3D) {
157
+ if (!obj) return;
158
+ const mesh = obj as THREE.Mesh;
159
+ if (mesh.geometry) {
160
+ mesh.geometry.dispose();
161
+ }
162
+ if (mesh.material) {
163
+ if (Array.isArray(mesh.material)) {
164
+ mesh.material.forEach(m => m.dispose());
165
+ } else {
166
+ mesh.material.dispose();
167
+ }
168
+ }
169
+ }
170
+
171
+ declare type ForEachComponentCallback = (comp: Component) => any;
172
+
173
+ export function foreachComponent(instance: THREE.Object3D, cb: ForEachComponentCallback, recursive: boolean = true): any {
174
+ return internalForEachComponent(instance, cb, recursive);
175
+ }
176
+
177
+ function internalForEachComponent(instance: Object3D, cb: ForEachComponentCallback, recursive: boolean, level: number = 0): any {
178
+ if (!instance) return;
179
+ if (!instance.isObject3D) {
180
+ new Error("Expected Object3D but got " + instance);
181
+ }
182
+ if (level > 1000) {
183
+ console.warn("Failed to iterate components: too many levels");
184
+ return;
185
+ }
186
+ if (instance.userData?.components) {
187
+ for (let i = 0; i < instance.userData.components.length; i++) {
188
+ const comp = instance.userData.components[i];
189
+ if (comp?.isComponent === true) {
190
+ const res = cb(comp);
191
+ if (res !== undefined) return res;
192
+ }
193
+ }
194
+ }
195
+
196
+ if (recursive && instance.children) {
197
+ // childArrayBuffer.length = 0;
198
+ // childArrayBuffer.push(...instance.children);
199
+ const nextLevel = level + 1;
200
+ for (let i = 0; i < instance.children.length; i++) {
201
+ const child = instance.children[i];
202
+ if (!child) continue;
203
+ const res = internalForEachComponent(child, cb, recursive, nextLevel);
204
+ if (res !== undefined) return res;
205
+ }
206
+ // childArrayBuffer.length = 0;
207
+ }
208
+
209
+ }
210
+
211
+ declare class NewGameObjectReferenceInfo {
212
+ original: THREE.Object3D;
213
+ clone: THREE.Object3D;
214
+ }
215
+
216
+ export function instantiate(instance: GameObject | Object3D | null, opts: InstantiateOptions | null = null): GameObject | null {
217
+ if (instance === null) return null;
218
+
219
+ let options: InstantiateOptions | null = null;
220
+ if (opts !== null) {
221
+ // if x is defined assume this is a vec3 - this is just to not break everything at once and stay a little bit backwards compatible
222
+ if (opts["x"] !== undefined) {
223
+ options = new InstantiateOptions();
224
+ options.position = opts as unknown as THREE.Vector3;
225
+ }
226
+ else {
227
+ // if (opts instanceof InstantiateOptions)
228
+ options = opts as InstantiateOptions;
229
+ // else {
230
+ // options = new InstantiateOptions();
231
+ // Object.assign(options, opts);
232
+ // }
233
+ }
234
+ }
235
+
236
+ let context = Context.Current;
237
+ if (options?.context) context = options.context;
238
+ if (debug && context.alias)
239
+ console.log("context", context.alias);
240
+
241
+ // we need to create the id provider before calling internal instantiate because cloned gameobjects also create new guids
242
+ if (options && !options.idProvider) {
243
+ options.idProvider = new InstantiateIdProvider(Date.now());
244
+ }
245
+
246
+ const components: Array<Component> = [];
247
+ const goMapping: { [key: string]: NewGameObjectReferenceInfo } = {}; // used to resolve references on components to components on other gameobjects to their new counterpart
248
+ const skinnedMeshes: { [key: string]: NewGameObjectReferenceInfo } = {};
249
+ const clone = internalInstantiate(context, instance, options, components, goMapping, skinnedMeshes);
250
+
251
+ if (clone) {
252
+ resolveReferences(goMapping);
253
+ resolveAndBindSkinnedMeshBones(skinnedMeshes, goMapping);
254
+ }
255
+
256
+ if (debug) {
257
+ logHierarchy(instance, true);
258
+ logHierarchy(clone, true);
259
+ }
260
+
261
+ const guidsMap: GuidsMap = {};
262
+ for (const i in components) {
263
+ const copy = components[i];
264
+ const oldGuid = copy.guid;
265
+ if (options && options.idProvider) {
266
+ copy.guid = options.idProvider.generateUUID();
267
+ guidsMap[oldGuid] = copy.guid;
268
+ if (debug)
269
+ console.log(copy.name, copy.guid)
270
+ }
271
+ registerComponent(copy, context);
272
+ if (copy.__internalNewInstanceCreated)
273
+ copy.__internalNewInstanceCreated();
274
+ }
275
+ for (const i in components) {
276
+ const copy = components[i];
277
+ if (copy.resolveGuids)
278
+ copy.resolveGuids(guidsMap);
279
+ if (copy.enabled === false) continue;
280
+ else copy.enabled = true;
281
+ }
282
+
283
+ processNewScripts(context);
284
+
285
+ return clone as GameObject;
286
+ }
287
+
288
+
289
+ function internalInstantiate(
290
+ context: Context, instance: GameObject | THREE.Object3D, opts: InstantiateOptions | null,
291
+ componentsList: Array<Component>,
292
+ newGameObjectsMap: { [key: string]: NewGameObjectReferenceInfo },
293
+ skinnedMeshesMap: { [key: string]: NewGameObjectReferenceInfo }
294
+ )
295
+ : GameObject | THREE.Object3D | null {
296
+ if (!instance) return null;
297
+ // prepare, remove things that dont work out of the box
298
+ // e.g. user data we want to manually clone
299
+ // also children throw errors (e.g. recursive toJson with nested meshes)
300
+ const userData = instance.userData;
301
+ instance.userData = {};
302
+ const children = instance.children;
303
+ instance.children = [];
304
+ let clone: THREE.Object3D | GameObject;
305
+ clone = instance.clone(false);
306
+ apply(clone);
307
+ instance.userData = userData;
308
+ instance.children = children;
309
+
310
+ // make reference from old id to new object
311
+ newGameObjectsMap[instance.uuid] = { original: instance, clone: clone };
312
+
313
+ if (instance.type === "SkinnedMesh") {
314
+ skinnedMeshesMap[instance.uuid] = { original: instance, clone: clone };
315
+ }
316
+
317
+ // DO NOT EVER RENAME BECAUSE IT BREAKS / MIGHT BREAK ANIMATIONS
318
+ // clone.name += " (Clone)";
319
+
320
+ if (opts?.visible !== undefined)
321
+ clone.visible = opts.visible;
322
+
323
+ if (opts?.idProvider) {
324
+ clone.uuid = opts.idProvider.generateUUID();
325
+ const cloneGo: GameObject = clone as GameObject;
326
+ if (cloneGo) cloneGo.guid = clone.uuid;
327
+ }
328
+
329
+ if (instance.animations && instance.animations.length > 0) {
330
+ clone.animations = [...instance.animations];
331
+ }
332
+
333
+ const parent = instance.parent;
334
+ if (parent) {
335
+ parent.add(clone);
336
+ }
337
+
338
+ // apply transform
339
+ if (opts?.position) {
340
+ setWorldPosition(clone, opts.position);
341
+ }
342
+ else clone.position.copy(instance.position);
343
+ if (opts?.rotation) {
344
+ setWorldQuaternion(clone, opts.rotation);
345
+ // clone.quaternion.copy(opts.rotation);
346
+ }
347
+ else clone.quaternion.copy(instance.quaternion);
348
+ if (opts?.scale) {
349
+ // TODO: make set world scale work
350
+ clone.scale.copy(opts.scale);
351
+ }
352
+ else clone.scale.copy(instance.scale);
353
+
354
+ if (opts?.parent && opts.parent !== "scene") {
355
+ let requestedParent: Object3D | null = null;
356
+ if (typeof opts.parent === "string") {
357
+ requestedParent = tryFindObject(opts.parent, context.scene, true);
358
+ }
359
+ else {
360
+ requestedParent = opts.parent;
361
+ }
362
+ if (requestedParent) {
363
+ const func = opts.keepWorldPosition === true ? requestedParent.attach : requestedParent.add;
364
+ if (!func) console.error("Invalid parent object", requestedParent, "received when instantiating:", instance);
365
+ else func.call(requestedParent, clone);
366
+ }
367
+ else console.warn("could not find parent:", opts.parent);
368
+ }
369
+
370
+ for (const [key, value] of Object.entries(instance.userData)) {
371
+ if (key === "components") continue;
372
+ clone.userData[key] = value;
373
+ }
374
+
375
+ if (instance.userData?.components) {
376
+ const components = instance.userData.components;
377
+ const newComponents: Component[] = [];
378
+ clone.userData.components = newComponents;
379
+ for (let i = 0; i < components.length; i++) {
380
+ const comp = components[i];
381
+ const copy = Object.create(comp);
382
+ assign(copy, comp);
383
+ newComponents.push(copy);
384
+ copy.gameObject = clone;
385
+ // copy.transform = clone;
386
+ componentsList.push(copy);
387
+ }
388
+ }
389
+
390
+ // children should just clone the original transform
391
+ if (opts) {
392
+ opts.position = undefined;
393
+ opts.rotation = undefined;
394
+ opts.scale = undefined;
395
+ opts.parent = undefined;
396
+ }
397
+
398
+ for (const ch in instance.children) {
399
+ const child = instance.children[ch];
400
+ const newChild = internalInstantiate(context, child as GameObject, opts, componentsList, newGameObjectsMap, skinnedMeshesMap);
401
+ if (newChild)
402
+ clone.add(newChild);
403
+ }
404
+
405
+ return clone;
406
+
407
+ }
408
+
409
+ function resolveAndBindSkinnedMeshBones(
410
+ skinnedMeshes: { [key: string]: NewGameObjectReferenceInfo },
411
+ newObjectsMap: { [key: string]: NewGameObjectReferenceInfo }
412
+ ) {
413
+ for (const key in skinnedMeshes) {
414
+ const val = skinnedMeshes[key];
415
+ const original = val.original as THREE.SkinnedMesh;
416
+ const originalSkeleton = original.skeleton;
417
+ const clone = val.clone as THREE.SkinnedMesh;
418
+ // clone.updateWorldMatrix(true, true);
419
+ if (!originalSkeleton) {
420
+ console.warn("Skinned mesh has no skeleton?", val);
421
+ continue;
422
+ }
423
+ const originalBones = originalSkeleton.bones;
424
+ const clonedSkeleton = clone.skeleton.clone();
425
+
426
+ clone.skeleton = clonedSkeleton;
427
+ clone.bindMatrix.clone().copy(original.bindMatrix);
428
+ // console.log(clone.bindMatrix)
429
+ clone.bindMatrixInverse.copy(original.bindMatrixInverse);
430
+ // clone.bindMatrix.multiplyScalar(.025);
431
+ // console.assert(originalSkeleton.uuid !== clonedSkeleton.uuid);
432
+ // console.assert(originalBones.length === clonedSkeleton.bones.length);
433
+ const bones: Array<THREE.Bone> = [];
434
+ clonedSkeleton.bones = bones;
435
+ for (let i = 0; i < originalBones.length; i++) {
436
+ const bone = originalBones[i];
437
+ const newBoneInfo = newObjectsMap[bone.uuid];
438
+ const clonedBone = newBoneInfo.clone as THREE.Bone;
439
+ // console.log("NEW BONE: ", clonedBone, "BEFORE", newBoneInfo.original);
440
+ bones.push(clonedBone);
441
+ }
442
+ // clone.skeleton = new THREE.Skeleton(bones);
443
+ // clone.skeleton.update();
444
+ // clone.pose();
445
+ // clone.scale.set(1,1,1);
446
+ // clone.position.y += .1;
447
+ // console.log("ORIG", original, "CLONE", clone);
448
+ }
449
+ for (const key in skinnedMeshes) {
450
+ const clone = skinnedMeshes[key].clone as THREE.SkinnedMesh;
451
+ clone.skeleton.update();
452
+ // clone.skeleton.calculateInverses();
453
+ clone.bind(clone.skeleton, clone.bindMatrix);
454
+ clone.updateMatrixWorld(true);
455
+ // clone.pose();
456
+ }
457
+ }
458
+
459
+ // private static bindNewSkinnedMeshBones(source, clone) {
460
+ // const sourceLookup = new Map();
461
+ // const cloneLookup = new Map();
462
+ // // const clone = source.clone(false);
463
+
464
+ // function parallelTraverse(a, b, callback) {
465
+ // callback(a, b);
466
+ // for (let i = 0; i < a.children.length; i++) {
467
+ // parallelTraverse(a.children[i], b.children[i], callback);
468
+ // }
469
+ // }
470
+ // parallelTraverse(source, clone, function (sourceNode, clonedNode) {
471
+ // sourceLookup.set(clonedNode, sourceNode);
472
+ // cloneLookup.set(sourceNode, clonedNode);
473
+ // });
474
+
475
+ // clone.traverse(function (node) {
476
+ // if (!node.isSkinnedMesh) return;
477
+ // const clonedMesh = node;
478
+ // const sourceMesh = sourceLookup.get(node);
479
+ // const sourceBones = sourceMesh.skeleton.bones;
480
+
481
+ // clonedMesh.skeleton = sourceMesh.skeleton.clone();
482
+ // clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix);
483
+
484
+ // clonedMesh.skeleton.bones = sourceBones.map(function (bone) {
485
+ // return cloneLookup.get(bone);
486
+ // });
487
+ // clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix);
488
+ // });
489
+ // return clone;
490
+
491
+ // }
492
+
493
+ function resolveReferences(newObjectsMap: { [key: string]: NewGameObjectReferenceInfo }) {
494
+ // for every object that is newly created we want to update references to their newly created counterparts
495
+ // e.g. a collider instance referencing a rigidbody instance should be updated so that
496
+ // the cloned collider does not reference the cloned rigidbody (instead of the original rigidbody)
497
+ for (const key in newObjectsMap) {
498
+ const val = newObjectsMap[key];
499
+ const clone = val.clone;
500
+ // resolve references
501
+ if (clone.userData?.components) {
502
+ for (let i = 0; i < clone.userData.components.length; i++) {
503
+ const copy = clone.userData.components[i];
504
+ // find referenced within a cloned gameobject
505
+ const entries = Object.entries(copy);
506
+ // console.log(copy, entries);
507
+ for (const [key, value] of entries) {
508
+ if (Array.isArray(value)) {
509
+ const clonedArray: Array<any> = [];
510
+ copy[key] = clonedArray;
511
+ // console.log(copy, key, value, copy[key]);
512
+ for (let i = 0; i < value.length; i++) {
513
+ const entry = value[i];
514
+ // push value types into new array
515
+ if (typeof entry !== "object") {
516
+ clonedArray.push(entry);
517
+ continue;
518
+ }
519
+ const res: any = postProcessNewInstance(copy, key, entry, newObjectsMap);
520
+ if (res !== undefined)
521
+ clonedArray.push(res);
522
+ else clonedArray.push(entry);
523
+ }
524
+ // console.log(copy[key])
525
+ }
526
+ else if (typeof value === "object") {
527
+ const res = postProcessNewInstance(copy, key, value as IComponent | Object3D, newObjectsMap);
528
+ if (res !== undefined) {
529
+ copy[key] = res;
530
+ }
531
+ }
532
+ }
533
+ }
534
+ }
535
+ }
536
+
537
+ }
538
+
539
+ function postProcessNewInstance(copy: THREE.Object3D, key: string, value: IComponent | Object3D | any, newObjectsMap: { [key: string]: NewGameObjectReferenceInfo }) {
540
+ if (value === null || value === undefined) return;
541
+ if ((value as IComponent).isComponent === true) {
542
+ const originalGameObjectReference = value["gameObject"];
543
+ // console.log(key, value, originalGameObjectReference);
544
+ if (originalGameObjectReference) {
545
+ const id = originalGameObjectReference.uuid;
546
+ const newGameObject = newObjectsMap[id]?.clone;
547
+ if (!newGameObject) {
548
+ // reference has not changed!
549
+ if (debug)
550
+ console.log("reference did not change", key, copy, value);
551
+ return;
552
+ }
553
+ const index = originalGameObjectReference.userData.components.indexOf(value);
554
+ if (index >= 0) {
555
+ if (debug)
556
+ console.log(key, id);
557
+ const found = newGameObject.userData.components[index];
558
+ return found;
559
+ }
560
+ else {
561
+ console.warn("could not find component", key, value);
562
+ }
563
+ }
564
+ } else if ((value as Object3D).isObject3D === true) {
565
+ // console.log(value);
566
+ if (key === "gameObject") return;
567
+ const originalGameObjectReference = value as Object3D;
568
+ if (originalGameObjectReference) {
569
+ const id = originalGameObjectReference.uuid;
570
+ const newGameObject = newObjectsMap[id]?.clone;
571
+ if (newGameObject) {
572
+ if (debug)
573
+ console.log(key, "old", value, "new", newGameObject);
574
+ return newGameObject;
575
+ }
576
+ }
577
+ }
578
+ else {
579
+ // create new instances for some types that we know should usually not be shared and can safely be cloned
580
+ if (value.isVector4 || value.isVector3 || value.isVector2 || value.isQuaternion || value.isEuler) {
581
+ return value.clone();
582
+ }
583
+ }
559
584
  }