@zylem/behaviors 0.2.0

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 (175) hide show
  1. package/README.md +26 -0
  2. package/dist/behavior-system-DYbx-x_-.d.ts +307 -0
  3. package/dist/chunk-2C3Z5GE7.js +176 -0
  4. package/dist/chunk-2C3Z5GE7.js.map +1 -0
  5. package/dist/chunk-2CLT36VB.js +241 -0
  6. package/dist/chunk-2CLT36VB.js.map +1 -0
  7. package/dist/chunk-3PYGRHAL.js +35 -0
  8. package/dist/chunk-3PYGRHAL.js.map +1 -0
  9. package/dist/chunk-4I6E6DGV.js +212 -0
  10. package/dist/chunk-4I6E6DGV.js.map +1 -0
  11. package/dist/chunk-4URF65BR.js +44 -0
  12. package/dist/chunk-4URF65BR.js.map +1 -0
  13. package/dist/chunk-6C6NXNEW.js +38 -0
  14. package/dist/chunk-6C6NXNEW.js.map +1 -0
  15. package/dist/chunk-ARJWUNRE.js +431 -0
  16. package/dist/chunk-ARJWUNRE.js.map +1 -0
  17. package/dist/chunk-BXP4K7RF.js +1205 -0
  18. package/dist/chunk-BXP4K7RF.js.map +1 -0
  19. package/dist/chunk-DYLH6K7B.js +44 -0
  20. package/dist/chunk-DYLH6K7B.js.map +1 -0
  21. package/dist/chunk-EIWQM6U3.js +27 -0
  22. package/dist/chunk-EIWQM6U3.js.map +1 -0
  23. package/dist/chunk-EZNCCO4L.js +14 -0
  24. package/dist/chunk-EZNCCO4L.js.map +1 -0
  25. package/dist/chunk-F3KRX2V4.js +457 -0
  26. package/dist/chunk-F3KRX2V4.js.map +1 -0
  27. package/dist/chunk-FPTWVCPN.js +53 -0
  28. package/dist/chunk-FPTWVCPN.js.map +1 -0
  29. package/dist/chunk-GCNRXAKH.js +37 -0
  30. package/dist/chunk-GCNRXAKH.js.map +1 -0
  31. package/dist/chunk-GYURWCIQ.js +1985 -0
  32. package/dist/chunk-GYURWCIQ.js.map +1 -0
  33. package/dist/chunk-HZMY3TT4.js +244 -0
  34. package/dist/chunk-HZMY3TT4.js.map +1 -0
  35. package/dist/chunk-ID5QJYF5.js +50 -0
  36. package/dist/chunk-ID5QJYF5.js.map +1 -0
  37. package/dist/chunk-JAN34G6S.js +552 -0
  38. package/dist/chunk-JAN34G6S.js.map +1 -0
  39. package/dist/chunk-K3UNLQ7W.js +118 -0
  40. package/dist/chunk-K3UNLQ7W.js.map +1 -0
  41. package/dist/chunk-KDY5N6J4.js +82 -0
  42. package/dist/chunk-KDY5N6J4.js.map +1 -0
  43. package/dist/chunk-KOZUNIIE.js +413 -0
  44. package/dist/chunk-KOZUNIIE.js.map +1 -0
  45. package/dist/chunk-KS72RZHX.js +30 -0
  46. package/dist/chunk-KS72RZHX.js.map +1 -0
  47. package/dist/chunk-LD5SMIB3.js +32 -0
  48. package/dist/chunk-LD5SMIB3.js.map +1 -0
  49. package/dist/chunk-OHCPV2NT.js +86 -0
  50. package/dist/chunk-OHCPV2NT.js.map +1 -0
  51. package/dist/chunk-OYWFPIHF.js +115 -0
  52. package/dist/chunk-OYWFPIHF.js.map +1 -0
  53. package/dist/chunk-POZER3MQ.js +407 -0
  54. package/dist/chunk-POZER3MQ.js.map +1 -0
  55. package/dist/chunk-RTRVBEIB.js +56 -0
  56. package/dist/chunk-RTRVBEIB.js.map +1 -0
  57. package/dist/chunk-RTVRUNYR.js +29 -0
  58. package/dist/chunk-RTVRUNYR.js.map +1 -0
  59. package/dist/chunk-SS7ELMJ7.js +406 -0
  60. package/dist/chunk-SS7ELMJ7.js.map +1 -0
  61. package/dist/chunk-STCCNLPC.js +160 -0
  62. package/dist/chunk-STCCNLPC.js.map +1 -0
  63. package/dist/chunk-SVLNF434.js +261 -0
  64. package/dist/chunk-SVLNF434.js.map +1 -0
  65. package/dist/chunk-UYFOLI2X.js +24 -0
  66. package/dist/chunk-UYFOLI2X.js.map +1 -0
  67. package/dist/chunk-VAN4WW3F.js +67 -0
  68. package/dist/chunk-VAN4WW3F.js.map +1 -0
  69. package/dist/chunk-WOMHL23C.js +369 -0
  70. package/dist/chunk-WOMHL23C.js.map +1 -0
  71. package/dist/chunk-WWVD5DR5.js +120 -0
  72. package/dist/chunk-WWVD5DR5.js.map +1 -0
  73. package/dist/chunk-XG2YMCJW.js +201 -0
  74. package/dist/chunk-XG2YMCJW.js.map +1 -0
  75. package/dist/chunk-XIJNE67Y.js +210 -0
  76. package/dist/chunk-XIJNE67Y.js.map +1 -0
  77. package/dist/chunk-Y6UJOUE5.js +44 -0
  78. package/dist/chunk-Y6UJOUE5.js.map +1 -0
  79. package/dist/chunk-YUO6SKJD.js +348 -0
  80. package/dist/chunk-YUO6SKJD.js.map +1 -0
  81. package/dist/components--hjBMTnz.d.ts +120 -0
  82. package/dist/components-B29WHGQN.d.ts +39 -0
  83. package/dist/components-BWG1GkZA.d.ts +20 -0
  84. package/dist/components-XCpL6IYt.d.ts +18 -0
  85. package/dist/components-qWwOsvwh.d.ts +43 -0
  86. package/dist/cooldown.d.ts +116 -0
  87. package/dist/cooldown.js +20 -0
  88. package/dist/cooldown.js.map +1 -0
  89. package/dist/coordinators/boundary-ricochet-3d.d.ts +19 -0
  90. package/dist/coordinators/boundary-ricochet-3d.js +8 -0
  91. package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
  92. package/dist/coordinators/boundary-ricochet.d.ts +34 -0
  93. package/dist/coordinators/boundary-ricochet.js +8 -0
  94. package/dist/coordinators/boundary-ricochet.js.map +1 -0
  95. package/dist/coordinators/first-person-shooter.d.ts +35 -0
  96. package/dist/coordinators/first-person-shooter.js +9 -0
  97. package/dist/coordinators/first-person-shooter.js.map +1 -0
  98. package/dist/coordinators/multidirectional-space-shooter.d.ts +27 -0
  99. package/dist/coordinators/multidirectional-space-shooter.js +10 -0
  100. package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
  101. package/dist/coordinators/top-down-shooter.d.ts +27 -0
  102. package/dist/coordinators/top-down-shooter.js +10 -0
  103. package/dist/coordinators/top-down-shooter.js.map +1 -0
  104. package/dist/core.d.ts +25 -0
  105. package/dist/core.js +327 -0
  106. package/dist/core.js.map +1 -0
  107. package/dist/destructible-3d.d.ts +42 -0
  108. package/dist/destructible-3d.js +13 -0
  109. package/dist/destructible-3d.js.map +1 -0
  110. package/dist/destructible-prebake.d.ts +28 -0
  111. package/dist/destructible-prebake.js +23 -0
  112. package/dist/destructible-prebake.js.map +1 -0
  113. package/dist/entity-types-CmtQ-IBp.d.ts +15 -0
  114. package/dist/first-person-perspective-C9Mptl0-.d.ts +23 -0
  115. package/dist/first-person.d.ts +204 -0
  116. package/dist/first-person.js +27 -0
  117. package/dist/first-person.js.map +1 -0
  118. package/dist/index.d.ts +40 -0
  119. package/dist/index.js +263 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/jumper-2d.d.ts +113 -0
  122. package/dist/jumper-2d.js +27 -0
  123. package/dist/jumper-2d.js.map +1 -0
  124. package/dist/jumper-3d.d.ts +164 -0
  125. package/dist/jumper-3d.js +29 -0
  126. package/dist/jumper-3d.js.map +1 -0
  127. package/dist/moveable-BCRpjAQb.d.ts +176 -0
  128. package/dist/particle-emitter/presets.d.ts +46 -0
  129. package/dist/particle-emitter/presets.js +15 -0
  130. package/dist/particle-emitter/presets.js.map +1 -0
  131. package/dist/particle-emitter.d.ts +78 -0
  132. package/dist/particle-emitter.js +15 -0
  133. package/dist/particle-emitter.js.map +1 -0
  134. package/dist/payload-BQzu-oY_.d.ts +89 -0
  135. package/dist/platformer-3d.d.ts +347 -0
  136. package/dist/platformer-3d.js +23 -0
  137. package/dist/platformer-3d.js.map +1 -0
  138. package/dist/ricochet-2d.d.ts +274 -0
  139. package/dist/ricochet-2d.js +16 -0
  140. package/dist/ricochet-2d.js.map +1 -0
  141. package/dist/ricochet-3d.d.ts +116 -0
  142. package/dist/ricochet-3d.js +16 -0
  143. package/dist/ricochet-3d.js.map +1 -0
  144. package/dist/runtime-2d.d.ts +2 -0
  145. package/dist/runtime-2d.js +32 -0
  146. package/dist/runtime-2d.js.map +1 -0
  147. package/dist/runtime-pong.d.ts +92 -0
  148. package/dist/runtime-pong.js +38 -0
  149. package/dist/runtime-pong.js.map +1 -0
  150. package/dist/screen-visibility.d.ts +74 -0
  151. package/dist/screen-visibility.js +10 -0
  152. package/dist/screen-visibility.js.map +1 -0
  153. package/dist/screen-wrap.d.ts +86 -0
  154. package/dist/screen-wrap.js +16 -0
  155. package/dist/screen-wrap.js.map +1 -0
  156. package/dist/shooter-2d.d.ts +77 -0
  157. package/dist/shooter-2d.js +12 -0
  158. package/dist/shooter-2d.js.map +1 -0
  159. package/dist/spark-DDlIg1nM.d.ts +148 -0
  160. package/dist/sync-state-machine-CZyspBpj.d.ts +16 -0
  161. package/dist/thruster.d.ts +132 -0
  162. package/dist/thruster.js +26 -0
  163. package/dist/thruster.js.map +1 -0
  164. package/dist/top-down-movement.d.ts +40 -0
  165. package/dist/top-down-movement.js +20 -0
  166. package/dist/top-down-movement.js.map +1 -0
  167. package/dist/use-behavior-D_82jAL3.d.ts +13 -0
  168. package/dist/vector-Bm65-FOG.d.ts +45 -0
  169. package/dist/world-boundary-2d.d.ts +141 -0
  170. package/dist/world-boundary-2d.js +21 -0
  171. package/dist/world-boundary-2d.js.map +1 -0
  172. package/dist/world-boundary-3d.d.ts +75 -0
  173. package/dist/world-boundary-3d.js +21 -0
  174. package/dist/world-boundary-3d.js.map +1 -0
  175. package/package.json +161 -0
@@ -0,0 +1,1205 @@
1
+ import {
2
+ bufferGeometryToPlain,
3
+ buildFractureGeometryCacheKey,
4
+ buildNormalizedFractureSourceGeometry,
5
+ pinataFractureOptionsToPlain,
6
+ plainWorkerResultToTemplateParts
7
+ } from "./chunk-HZMY3TT4.js";
8
+ import {
9
+ defineBehavior
10
+ } from "./chunk-EZNCCO4L.js";
11
+
12
+ // src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts
13
+ import {
14
+ ActiveCollisionTypes,
15
+ ColliderDesc,
16
+ RigidBodyDesc
17
+ } from "@dimforge/rapier3d-compat";
18
+ import {
19
+ DestructibleMesh,
20
+ FractureOptions as PinataFractureOptions
21
+ } from "@dgreenheck/three-pinata";
22
+ import {
23
+ Box3,
24
+ BufferAttribute,
25
+ Group,
26
+ Matrix4,
27
+ Quaternion as Quaternion2,
28
+ Vector2,
29
+ Vector3
30
+ } from "three";
31
+ import * as Comlink from "comlink";
32
+
33
+ // src/lib/physics/physics-pose.ts
34
+ import { Quaternion } from "three";
35
+ var directBodyPoseHistory = /* @__PURE__ */ new WeakMap();
36
+ var _previousQuaternion = new Quaternion();
37
+ var _currentQuaternion = new Quaternion();
38
+ var _renderQuaternion = new Quaternion();
39
+ function clonePhysicsVector3(vector) {
40
+ return { x: vector.x, y: vector.y, z: vector.z };
41
+ }
42
+ function clonePhysicsQuaternion(rotation) {
43
+ return { x: rotation.x, y: rotation.y, z: rotation.z, w: rotation.w };
44
+ }
45
+ function clonePhysicsPose(pose) {
46
+ return {
47
+ position: clonePhysicsVector3(pose.position),
48
+ rotation: clonePhysicsQuaternion(pose.rotation)
49
+ };
50
+ }
51
+ function clampInterpolationAlpha(alpha) {
52
+ if (!Number.isFinite(alpha)) return 0;
53
+ return Math.max(0, Math.min(1, alpha));
54
+ }
55
+ function capturePhysicsPose(body) {
56
+ return {
57
+ position: clonePhysicsVector3(body.translation()),
58
+ rotation: clonePhysicsQuaternion(body.rotation())
59
+ };
60
+ }
61
+ function createCollapsedPhysicsPoseHistory(pose) {
62
+ const current = clonePhysicsPose(pose);
63
+ return {
64
+ previous: clonePhysicsPose(current),
65
+ current
66
+ };
67
+ }
68
+ function collapseDirectBodyPoseHistory(body) {
69
+ const pose = capturePhysicsPose(body);
70
+ const history = directBodyPoseHistory.get(body) ?? createCollapsedPhysicsPoseHistory(pose);
71
+ history.previous = clonePhysicsPose(pose);
72
+ history.current = clonePhysicsPose(pose);
73
+ directBodyPoseHistory.set(body, history);
74
+ return history;
75
+ }
76
+ function interpolatePhysicsPose(previous, current, alpha) {
77
+ const t = clampInterpolationAlpha(alpha);
78
+ _previousQuaternion.set(
79
+ previous.rotation.x,
80
+ previous.rotation.y,
81
+ previous.rotation.z,
82
+ previous.rotation.w
83
+ );
84
+ _currentQuaternion.set(
85
+ current.rotation.x,
86
+ current.rotation.y,
87
+ current.rotation.z,
88
+ current.rotation.w
89
+ );
90
+ _renderQuaternion.slerpQuaternions(
91
+ _previousQuaternion,
92
+ _currentQuaternion,
93
+ t
94
+ );
95
+ return {
96
+ position: {
97
+ x: previous.position.x + (current.position.x - previous.position.x) * t,
98
+ y: previous.position.y + (current.position.y - previous.position.y) * t,
99
+ z: previous.position.z + (current.position.z - previous.position.z) * t
100
+ },
101
+ rotation: {
102
+ x: _renderQuaternion.x,
103
+ y: _renderQuaternion.y,
104
+ z: _renderQuaternion.z,
105
+ w: _renderQuaternion.w
106
+ }
107
+ };
108
+ }
109
+ function getBodyRenderPose(body, alpha) {
110
+ if (isRenderPoseProvider(body)) {
111
+ return body.getRenderPose(alpha);
112
+ }
113
+ const history = directBodyPoseHistory.get(body);
114
+ if (!history) {
115
+ return capturePhysicsPose(body);
116
+ }
117
+ const latestPose = capturePhysicsPose(body);
118
+ if (!posesEqual(latestPose, history.current)) {
119
+ const collapsed = collapseDirectBodyPoseHistory(body);
120
+ return clonePhysicsPose(collapsed.current);
121
+ }
122
+ return interpolatePhysicsPose(history.previous, history.current, alpha);
123
+ }
124
+ function isRenderPoseProvider(value) {
125
+ return value != null && typeof value === "object" && typeof value.getPoseHistory === "function" && typeof value.getRenderPose === "function";
126
+ }
127
+ function posesEqual(a, b) {
128
+ return a.position.x === b.position.x && a.position.y === b.position.y && a.position.z === b.position.z && a.rotation.x === b.rotation.x && a.rotation.y === b.rotation.y && a.rotation.z === b.rotation.z && a.rotation.w === b.rotation.w;
129
+ }
130
+
131
+ // src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts
132
+ var DESTRUCTIBLE_3D_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for(
133
+ "zylem:behavior:destructible-3d"
134
+ );
135
+ var DEFAULT_FRACTURE_OPTIONS = {
136
+ fractureMethod: "voronoi",
137
+ fragmentCount: 12,
138
+ voronoiOptions: {
139
+ mode: "3D"
140
+ },
141
+ fracturePlanes: {
142
+ x: true,
143
+ y: true,
144
+ z: true
145
+ },
146
+ textureScale: new Vector2(1, 1),
147
+ textureOffset: new Vector2(0, 0)
148
+ };
149
+ var DEFAULT_FRAGMENT_PHYSICS = {
150
+ mode: "compound",
151
+ inheritSourceVelocity: true,
152
+ outwardVelocity: 3,
153
+ angularVelocity: 1.5
154
+ };
155
+ var defaultOptions = {
156
+ fractureOptions: DEFAULT_FRACTURE_OPTIONS,
157
+ innerMaterial: null,
158
+ collider: {
159
+ shape: "convexHull",
160
+ sensor: false,
161
+ activeCollisionTypes: ActiveCollisionTypes.DEFAULT
162
+ },
163
+ fragmentPhysics: DEFAULT_FRAGMENT_PHYSICS
164
+ };
165
+ var runtimeStates = /* @__PURE__ */ new WeakMap();
166
+ function getRuntimeState(ref) {
167
+ const existing = runtimeStates.get(ref);
168
+ if (existing) {
169
+ return existing;
170
+ }
171
+ const state = {
172
+ fragmentContainer: null,
173
+ fragmentEntities: [],
174
+ fragments: [],
175
+ prebakedFragments: [],
176
+ prebakedFractureKey: null,
177
+ createdRootGroup: false,
178
+ fractureMode: null,
179
+ isFractured: false,
180
+ originalMeshParent: null,
181
+ originalColliderDesc: void 0,
182
+ originalColliderDescs: [],
183
+ originalMeshVisible: true,
184
+ originalGroupVisible: true,
185
+ sourceBodySnapshot: null,
186
+ sourcePhysicsAttached: false
187
+ };
188
+ runtimeStates.set(ref, state);
189
+ return state;
190
+ }
191
+ var prebakeWorkerApis = /* @__PURE__ */ new Map();
192
+ var prebakeAsyncInFlight = /* @__PURE__ */ new WeakMap();
193
+ function resolvePrebakeWorkerHref(url) {
194
+ return typeof url === "string" ? url : url.href;
195
+ }
196
+ function getPrebakeWorkerApi(url) {
197
+ if (typeof Worker === "undefined") {
198
+ throw new Error(
199
+ "Destructible3D prebakeAsync requires a Web Worker-capable environment."
200
+ );
201
+ }
202
+ const key = resolvePrebakeWorkerHref(url);
203
+ let api = prebakeWorkerApis.get(key);
204
+ if (api) {
205
+ return api;
206
+ }
207
+ const worker = new Worker(key, { type: "module" });
208
+ api = Comlink.wrap(worker);
209
+ prebakeWorkerApis.set(key, api);
210
+ return api;
211
+ }
212
+ function requireEntity(ref) {
213
+ const entity = ref.__entity;
214
+ if (!entity) {
215
+ throw new Error(
216
+ "Destructible3DBehavior requires the entity to be registered on a stage before calling fracture() or repair()."
217
+ );
218
+ }
219
+ return entity;
220
+ }
221
+ function getBehaviorWorld(ref) {
222
+ return ref.__world ?? null;
223
+ }
224
+ function getBehaviorScene(ref) {
225
+ return ref.__scene ?? null;
226
+ }
227
+ function getBehaviorCreateEntity(ref) {
228
+ return ref.__createEntity ?? null;
229
+ }
230
+ function getBehaviorGlobals(ref) {
231
+ return ref.__getGlobals ?? null;
232
+ }
233
+ function cloneFractureOptionsInput(value) {
234
+ if (!value) {
235
+ return {};
236
+ }
237
+ if (value instanceof PinataFractureOptions) {
238
+ return {
239
+ fractureMethod: value.fractureMethod,
240
+ fragmentCount: value.fragmentCount,
241
+ voronoiOptions: value.voronoiOptions ? {
242
+ mode: value.voronoiOptions.mode,
243
+ seedPoints: value.voronoiOptions.seedPoints?.map((point) => point.clone()),
244
+ impactPoint: value.voronoiOptions.impactPoint?.clone(),
245
+ impactRadius: value.voronoiOptions.impactRadius,
246
+ projectionAxis: value.voronoiOptions.projectionAxis,
247
+ projectionNormal: value.voronoiOptions.projectionNormal?.clone(),
248
+ useApproximation: value.voronoiOptions.useApproximation,
249
+ approximationNeighborCount: value.voronoiOptions.approximationNeighborCount
250
+ } : void 0,
251
+ fracturePlanes: value.fracturePlanes ? { ...value.fracturePlanes } : void 0,
252
+ textureScale: value.textureScale?.clone(),
253
+ textureOffset: value.textureOffset?.clone(),
254
+ seed: value.seed
255
+ };
256
+ }
257
+ return {
258
+ ...value,
259
+ voronoiOptions: value.voronoiOptions ? {
260
+ ...value.voronoiOptions,
261
+ seedPoints: value.voronoiOptions.seedPoints?.map((point) => point.clone()),
262
+ impactPoint: value.voronoiOptions.impactPoint?.clone(),
263
+ projectionNormal: value.voronoiOptions.projectionNormal?.clone()
264
+ } : void 0,
265
+ fracturePlanes: value.fracturePlanes ? { ...value.fracturePlanes } : void 0,
266
+ textureScale: value.textureScale?.clone(),
267
+ textureOffset: value.textureOffset?.clone()
268
+ };
269
+ }
270
+ function resolveFractureOptions(baseValue, overrideValue) {
271
+ const base = cloneFractureOptionsInput(baseValue);
272
+ const override = cloneFractureOptionsInput(overrideValue);
273
+ const fractureMethod = override.fractureMethod ?? base.fractureMethod ?? DEFAULT_FRACTURE_OPTIONS.fractureMethod ?? "voronoi";
274
+ const voronoiOptions = fractureMethod === "voronoi" ? {
275
+ mode: override.voronoiOptions?.mode ?? base.voronoiOptions?.mode ?? DEFAULT_FRACTURE_OPTIONS.voronoiOptions?.mode ?? "3D",
276
+ seedPoints: override.voronoiOptions?.seedPoints ?? base.voronoiOptions?.seedPoints,
277
+ impactPoint: override.voronoiOptions?.impactPoint ?? base.voronoiOptions?.impactPoint,
278
+ impactRadius: override.voronoiOptions?.impactRadius ?? base.voronoiOptions?.impactRadius,
279
+ projectionAxis: override.voronoiOptions?.projectionAxis ?? base.voronoiOptions?.projectionAxis,
280
+ projectionNormal: override.voronoiOptions?.projectionNormal ?? base.voronoiOptions?.projectionNormal,
281
+ useApproximation: override.voronoiOptions?.useApproximation ?? base.voronoiOptions?.useApproximation,
282
+ approximationNeighborCount: override.voronoiOptions?.approximationNeighborCount ?? base.voronoiOptions?.approximationNeighborCount
283
+ } : void 0;
284
+ return new PinataFractureOptions({
285
+ fractureMethod,
286
+ fragmentCount: override.fragmentCount ?? base.fragmentCount ?? DEFAULT_FRACTURE_OPTIONS.fragmentCount ?? 12,
287
+ voronoiOptions,
288
+ fracturePlanes: {
289
+ x: override.fracturePlanes?.x ?? base.fracturePlanes?.x ?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.x ?? true,
290
+ y: override.fracturePlanes?.y ?? base.fracturePlanes?.y ?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.y ?? true,
291
+ z: override.fracturePlanes?.z ?? base.fracturePlanes?.z ?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.z ?? true
292
+ },
293
+ textureScale: override.textureScale?.clone() ?? base.textureScale?.clone() ?? DEFAULT_FRACTURE_OPTIONS.textureScale?.clone() ?? new Vector2(1, 1),
294
+ textureOffset: override.textureOffset?.clone() ?? base.textureOffset?.clone() ?? DEFAULT_FRACTURE_OPTIONS.textureOffset?.clone() ?? new Vector2(0, 0),
295
+ seed: override.seed ?? base.seed
296
+ });
297
+ }
298
+ function resolveColliderOptions(input) {
299
+ return {
300
+ shape: input?.shape ?? defaultOptions.collider?.shape ?? "convexHull",
301
+ sensor: input?.sensor ?? defaultOptions.collider?.sensor ?? false,
302
+ collisionGroups: input?.collisionGroups,
303
+ activeCollisionTypes: input?.activeCollisionTypes ?? defaultOptions.collider?.activeCollisionTypes ?? ActiveCollisionTypes.DEFAULT
304
+ };
305
+ }
306
+ function resolveFragmentPhysicsOptions(input) {
307
+ return {
308
+ mode: input?.mode ?? DEFAULT_FRAGMENT_PHYSICS.mode,
309
+ inheritSourceVelocity: input?.inheritSourceVelocity ?? DEFAULT_FRAGMENT_PHYSICS.inheritSourceVelocity,
310
+ outwardVelocity: input?.outwardVelocity ?? DEFAULT_FRAGMENT_PHYSICS.outwardVelocity,
311
+ angularVelocity: input?.angularVelocity ?? DEFAULT_FRAGMENT_PHYSICS.angularVelocity
312
+ };
313
+ }
314
+ function findFirstMesh(root) {
315
+ let resolved = null;
316
+ root?.traverse((child) => {
317
+ if (resolved) {
318
+ return;
319
+ }
320
+ if (child.isMesh) {
321
+ resolved = child;
322
+ }
323
+ });
324
+ return resolved;
325
+ }
326
+ function requireEntityMesh(entity) {
327
+ if (entity.mesh?.geometry) {
328
+ return entity.mesh;
329
+ }
330
+ const mesh = findFirstMesh(entity.group);
331
+ if (!mesh?.geometry) {
332
+ throw new Error(
333
+ "Destructible3DBehavior requires the entity to have a primary mesh geometry."
334
+ );
335
+ }
336
+ entity.mesh = mesh;
337
+ if (!entity.materials?.length) {
338
+ if (Array.isArray(mesh.material)) {
339
+ entity.materials = [...mesh.material];
340
+ } else if (mesh.material) {
341
+ entity.materials = [mesh.material];
342
+ }
343
+ }
344
+ return mesh;
345
+ }
346
+ function getPrimaryMaterial(mesh) {
347
+ if (Array.isArray(mesh.material)) {
348
+ const material = mesh.material[0];
349
+ if (material) {
350
+ return material;
351
+ }
352
+ } else if (mesh.material) {
353
+ return mesh.material;
354
+ }
355
+ throw new Error(
356
+ "Destructible3DBehavior requires the entity mesh to have a material."
357
+ );
358
+ }
359
+ function ensureRootGroup(entity, state) {
360
+ if (entity.group) {
361
+ state.createdRootGroup = false;
362
+ return entity.group;
363
+ }
364
+ const originalMesh = requireEntityMesh(entity);
365
+ const parent = originalMesh.parent;
366
+ const root = new Group();
367
+ root.name = `${entity.name ?? entity.uuid}-destructible-root`;
368
+ root.position.copy(originalMesh.position);
369
+ root.quaternion.copy(originalMesh.quaternion);
370
+ root.scale.copy(originalMesh.scale);
371
+ originalMesh.position.set(0, 0, 0);
372
+ originalMesh.quaternion.identity();
373
+ originalMesh.scale.set(1, 1, 1);
374
+ if (parent) {
375
+ parent.remove(originalMesh);
376
+ parent.add(root);
377
+ }
378
+ root.add(originalMesh);
379
+ entity.group = root;
380
+ state.createdRootGroup = true;
381
+ return root;
382
+ }
383
+ function createFractureSourceMesh(mesh, root, innerMaterial) {
384
+ const geometry = buildNormalizedFractureSourceGeometry(mesh, root);
385
+ const outerMaterial = getPrimaryMaterial(mesh);
386
+ return new DestructibleMesh(
387
+ geometry,
388
+ outerMaterial,
389
+ innerMaterial ?? outerMaterial
390
+ );
391
+ }
392
+ function createPrebakedFragmentTemplates(fragments) {
393
+ return fragments.map((fragment) => {
394
+ const geometry = fragment.geometry.clone();
395
+ geometry.computeBoundingBox();
396
+ geometry.computeBoundingSphere();
397
+ return {
398
+ geometry,
399
+ position: fragment.position.clone(),
400
+ quaternion: fragment.quaternion.clone(),
401
+ scale: fragment.scale.clone()
402
+ };
403
+ });
404
+ }
405
+ function disposePrebakedFragmentTemplates(templates) {
406
+ for (const template of templates) {
407
+ template.geometry.dispose();
408
+ }
409
+ }
410
+ function cachePrebakedFragments(state, cacheKey, fragments) {
411
+ if (state.prebakedFractureKey === cacheKey && state.prebakedFragments.length > 0) {
412
+ return;
413
+ }
414
+ disposePrebakedFragmentTemplates(state.prebakedFragments);
415
+ state.prebakedFragments = createPrebakedFragmentTemplates(fragments);
416
+ state.prebakedFractureKey = cacheKey;
417
+ }
418
+ function installPrebakedTemplateParts(state, cacheKey, parts) {
419
+ if (state.prebakedFractureKey === cacheKey && state.prebakedFragments.length > 0) {
420
+ for (const part of parts) {
421
+ part.geometry.dispose();
422
+ }
423
+ return;
424
+ }
425
+ disposePrebakedFragmentTemplates(state.prebakedFragments);
426
+ state.prebakedFragments = parts.map((part) => ({
427
+ geometry: part.geometry,
428
+ position: part.position.clone(),
429
+ quaternion: part.quaternion.clone(),
430
+ scale: part.scale.clone()
431
+ }));
432
+ state.prebakedFractureKey = cacheKey;
433
+ }
434
+ function instantiatePrebakedFragments(mesh, innerMaterial, templates) {
435
+ const outerMaterial = getPrimaryMaterial(mesh);
436
+ return templates.map((template) => {
437
+ const fragment = new DestructibleMesh(
438
+ template.geometry.clone(),
439
+ outerMaterial,
440
+ innerMaterial ?? outerMaterial
441
+ );
442
+ fragment.position.copy(template.position);
443
+ fragment.quaternion.copy(template.quaternion);
444
+ fragment.scale.copy(template.scale);
445
+ return fragment;
446
+ });
447
+ }
448
+ function tagConvexHullCollider(colliderDesc, vertices) {
449
+ colliderDesc.__zylemShapeData = {
450
+ shape: "convexHull",
451
+ vertices: Array.from(vertices)
452
+ };
453
+ return colliderDesc;
454
+ }
455
+ function tagTrimeshCollider(colliderDesc, vertices, indices) {
456
+ colliderDesc.__zylemShapeData = {
457
+ shape: "trimesh",
458
+ vertices: Array.from(vertices),
459
+ indices: Array.from(indices)
460
+ };
461
+ return colliderDesc;
462
+ }
463
+ function getFragmentVertices(fragment) {
464
+ const position = fragment.geometry.getAttribute("position");
465
+ if (!(position instanceof BufferAttribute)) {
466
+ throw new Error("Fragment geometry is missing a position attribute.");
467
+ }
468
+ return new Float32Array(position.array);
469
+ }
470
+ function getFragmentIndices(fragment) {
471
+ const geometryIndex = fragment.geometry.getIndex();
472
+ if (geometryIndex) {
473
+ return new Uint32Array(geometryIndex.array);
474
+ }
475
+ const position = fragment.geometry.getAttribute("position");
476
+ if (!(position instanceof BufferAttribute)) {
477
+ return new Uint32Array();
478
+ }
479
+ return Uint32Array.from({ length: position.count }, (_value, index) => index);
480
+ }
481
+ function createCuboidCollider(fragment) {
482
+ const bounds = fragment.geometry.boundingBox ?? new Box3();
483
+ if (!fragment.geometry.boundingBox) {
484
+ fragment.geometry.computeBoundingBox();
485
+ }
486
+ bounds.copy(fragment.geometry.boundingBox ?? bounds);
487
+ const size = bounds.getSize(new Vector3());
488
+ return ColliderDesc.cuboid(
489
+ Math.max(size.x / 2, 1e-3),
490
+ Math.max(size.y / 2, 1e-3),
491
+ Math.max(size.z / 2, 1e-3)
492
+ );
493
+ }
494
+ function createFragmentColliderDesc(fragment, options, translation) {
495
+ const resolved = resolveColliderOptions(options);
496
+ const vertices = getFragmentVertices(fragment);
497
+ let colliderDesc = null;
498
+ if (resolved.shape === "convexHull") {
499
+ colliderDesc = ColliderDesc.convexHull(vertices);
500
+ if (colliderDesc) {
501
+ colliderDesc = tagConvexHullCollider(colliderDesc, vertices);
502
+ }
503
+ }
504
+ if (!colliderDesc && resolved.shape === "trimesh") {
505
+ const indices = getFragmentIndices(fragment);
506
+ colliderDesc = tagTrimeshCollider(
507
+ ColliderDesc.trimesh(vertices, indices),
508
+ vertices,
509
+ indices
510
+ );
511
+ }
512
+ if (!colliderDesc) {
513
+ colliderDesc = createCuboidCollider(fragment);
514
+ }
515
+ if (translation) {
516
+ colliderDesc.setTranslation(
517
+ translation.x,
518
+ translation.y,
519
+ translation.z
520
+ );
521
+ }
522
+ colliderDesc.setSensor(resolved.sensor);
523
+ if (resolved.collisionGroups !== void 0) {
524
+ colliderDesc.setCollisionGroups(resolved.collisionGroups);
525
+ }
526
+ colliderDesc.activeCollisionTypes = resolved.activeCollisionTypes;
527
+ return colliderDesc;
528
+ }
529
+ function snapshotBody(entity) {
530
+ if (!entity.body) {
531
+ return null;
532
+ }
533
+ const translation = entity.body.translation();
534
+ const rotation = entity.body.rotation();
535
+ const linearVelocity = entity.body.linvel();
536
+ const angularVelocity = entity.body.angvel();
537
+ return {
538
+ translation: { ...translation },
539
+ rotation: { ...rotation },
540
+ linearVelocity: { ...linearVelocity },
541
+ angularVelocity: { ...angularVelocity }
542
+ };
543
+ }
544
+ function restoreBodySnapshot(entity, snapshot) {
545
+ if (!snapshot || !entity.body) {
546
+ return;
547
+ }
548
+ entity.body.setTranslation(snapshot.translation, true);
549
+ entity.body.setRotation(snapshot.rotation, true);
550
+ entity.body.setLinvel(snapshot.linearVelocity, true);
551
+ entity.body.setAngvel(snapshot.angularVelocity, true);
552
+ }
553
+ function attachEntityPhysics(ref, entity, snapshot) {
554
+ const world = getBehaviorWorld(ref);
555
+ if (!world || !entity.colliderDesc) {
556
+ return;
557
+ }
558
+ if (entity.physicsAttached) {
559
+ world.destroyEntity(entity);
560
+ }
561
+ world.addEntity(entity);
562
+ restoreBodySnapshot(entity, snapshot);
563
+ }
564
+ function detachEntityPhysics(ref, entity) {
565
+ const world = getBehaviorWorld(ref);
566
+ if (!world || !entity.physicsAttached) {
567
+ return;
568
+ }
569
+ world.destroyEntity(entity);
570
+ }
571
+ function disposeFragments(fragments) {
572
+ for (const fragment of fragments) {
573
+ fragment.removeFromParent();
574
+ fragment.geometry.dispose();
575
+ }
576
+ }
577
+ function syncRuntimeFragmentEntityTransform(entity, interpolationAlpha) {
578
+ const target = entity.group ?? entity.mesh;
579
+ if (!target) {
580
+ return;
581
+ }
582
+ const wasmPose = entity.getPose?.();
583
+ if (wasmPose && entity.runtimeHandle >= 0) {
584
+ target.position.set(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z);
585
+ target.quaternion.set(wasmPose.rotation.x, wasmPose.rotation.y, wasmPose.rotation.z, wasmPose.rotation.w);
586
+ return;
587
+ }
588
+ if (!entity.body) {
589
+ return;
590
+ }
591
+ const pose = getBodyRenderPose(entity.body, interpolationAlpha);
592
+ target.position.set(pose.position.x, pose.position.y, pose.position.z);
593
+ target.quaternion.set(pose.rotation.x, pose.rotation.y, pose.rotation.z, pose.rotation.w);
594
+ }
595
+ function bakeScaleIntoFragmentGeometry(fragment, scale) {
596
+ if (Math.abs(scale.x - 1) < 1e-6 && Math.abs(scale.y - 1) < 1e-6 && Math.abs(scale.z - 1) < 1e-6) {
597
+ return;
598
+ }
599
+ fragment.geometry.applyMatrix4(
600
+ new Matrix4().makeScale(scale.x, scale.y, scale.z)
601
+ );
602
+ fragment.geometry.computeBoundingBox();
603
+ fragment.geometry.computeBoundingSphere();
604
+ }
605
+ function getRootWorldPosition(root) {
606
+ root.updateMatrixWorld(true);
607
+ return root.getWorldPosition(new Vector3());
608
+ }
609
+ function getImpactPointWorld(root, fractureOptions) {
610
+ const localImpactPoint = fractureOptions.voronoiOptions?.impactPoint;
611
+ if (!localImpactPoint) {
612
+ return null;
613
+ }
614
+ root.updateMatrixWorld(true);
615
+ return localImpactPoint.clone().applyMatrix4(root.matrixWorld);
616
+ }
617
+ function computeFragmentWorldPose(root, fragment) {
618
+ root.updateMatrixWorld(true);
619
+ fragment.updateMatrix();
620
+ const worldMatrix = new Matrix4().copy(root.matrixWorld).multiply(fragment.matrix);
621
+ const position = new Vector3();
622
+ const rotation = new Quaternion2();
623
+ const scale = new Vector3();
624
+ worldMatrix.decompose(position, rotation, scale);
625
+ return {
626
+ position,
627
+ rotation,
628
+ scale
629
+ };
630
+ }
631
+ function pseudoRandomSigned(index, salt) {
632
+ const value = Math.sin((index + 1) * 12.9898 + salt * 78.233) * 43758.5453;
633
+ return (value - Math.floor(value)) * 2 - 1;
634
+ }
635
+ function computeFragmentAngularVelocity(index, magnitude) {
636
+ if (magnitude <= 0) {
637
+ return { x: 0, y: 0, z: 0 };
638
+ }
639
+ const axis = new Vector3(
640
+ pseudoRandomSigned(index, 0.13),
641
+ pseudoRandomSigned(index, 0.47),
642
+ pseudoRandomSigned(index, 0.91)
643
+ );
644
+ if (axis.lengthSq() <= 1e-6) {
645
+ axis.set(0.35, 1, 0.2);
646
+ }
647
+ axis.normalize().multiplyScalar(magnitude);
648
+ return {
649
+ x: axis.x,
650
+ y: axis.y,
651
+ z: axis.z
652
+ };
653
+ }
654
+ function computeFragmentLinearVelocity(fragmentWorldPosition, rootWorldPosition, impactPointWorld, physicsOptions, sourceVelocity) {
655
+ const velocity = new Vector3();
656
+ if (physicsOptions.inheritSourceVelocity && sourceVelocity) {
657
+ velocity.set(
658
+ sourceVelocity.x,
659
+ sourceVelocity.y,
660
+ sourceVelocity.z
661
+ );
662
+ }
663
+ if (physicsOptions.outwardVelocity <= 0) {
664
+ return {
665
+ x: velocity.x,
666
+ y: velocity.y,
667
+ z: velocity.z
668
+ };
669
+ }
670
+ const direction = fragmentWorldPosition.clone().sub(
671
+ impactPointWorld ?? rootWorldPosition
672
+ );
673
+ if (direction.lengthSq() <= 1e-6) {
674
+ direction.copy(fragmentWorldPosition).sub(rootWorldPosition);
675
+ }
676
+ if (direction.lengthSq() <= 1e-6) {
677
+ direction.set(0, 1, 0);
678
+ }
679
+ direction.normalize().multiplyScalar(physicsOptions.outwardVelocity);
680
+ velocity.add(direction);
681
+ return {
682
+ x: velocity.x,
683
+ y: velocity.y,
684
+ z: velocity.z
685
+ };
686
+ }
687
+ function createRuntimeFragmentEntity(createEntity, parentEntity, fragment, index, colliderOptions, position, rotation) {
688
+ const entity = createEntity({
689
+ name: `${parentEntity.name ?? parentEntity.uuid}-fragment-${index}`
690
+ });
691
+ entity.onCleanup(() => {
692
+ fragment.removeFromParent();
693
+ fragment.geometry.dispose();
694
+ });
695
+ entity.create();
696
+ entity.mesh = fragment;
697
+ if (Array.isArray(fragment.material)) {
698
+ entity.materials = [...fragment.material];
699
+ } else if (fragment.material) {
700
+ entity.materials = [fragment.material];
701
+ }
702
+ entity.colliderDesc = createFragmentColliderDesc(fragment, colliderOptions);
703
+ entity.colliderDescs = [entity.colliderDesc];
704
+ entity.bodyDesc = RigidBodyDesc.dynamic().setTranslation(position.x, position.y, position.z).setCanSleep(false).setCcdEnabled(true);
705
+ fragment.position.set(0, 0, 0);
706
+ fragment.quaternion.identity();
707
+ fragment.scale.set(1, 1, 1);
708
+ entity.bodyDesc.setRotation({
709
+ x: rotation.x,
710
+ y: rotation.y,
711
+ z: rotation.z,
712
+ w: rotation.w
713
+ });
714
+ return entity;
715
+ }
716
+ function unlockIndependentFragmentPhysicsBody(entity) {
717
+ const body = entity.body;
718
+ if (!body?.lockTranslations || !body.lockRotations) {
719
+ return;
720
+ }
721
+ body.lockTranslations(false, true);
722
+ body.lockRotations(false, true);
723
+ }
724
+ function destroyRuntimeFragmentEntities(ref, state) {
725
+ const world = getBehaviorWorld(ref);
726
+ const scene = getBehaviorScene(ref);
727
+ const handledFragments = /* @__PURE__ */ new Set();
728
+ for (const fragmentEntity of state.fragmentEntities) {
729
+ const fragmentMesh = fragmentEntity.mesh;
730
+ if (fragmentMesh) {
731
+ handledFragments.add(fragmentMesh);
732
+ }
733
+ try {
734
+ fragmentEntity.nodeDestroy({
735
+ me: fragmentEntity,
736
+ globals: getBehaviorGlobals(ref)?.() ?? {}
737
+ });
738
+ } catch {
739
+ }
740
+ if (world && fragmentEntity.physicsAttached) {
741
+ world.destroyEntity(fragmentEntity);
742
+ }
743
+ const target = fragmentEntity.group ?? fragmentEntity.mesh;
744
+ if (target) {
745
+ target.removeFromParent();
746
+ scene?.scene.remove(target);
747
+ }
748
+ }
749
+ for (const fragment of state.fragments) {
750
+ if (handledFragments.has(fragment)) {
751
+ continue;
752
+ }
753
+ fragment.removeFromParent();
754
+ fragment.geometry.dispose();
755
+ }
756
+ state.fragmentEntities = [];
757
+ }
758
+ function restoreOriginalMesh(entity, state) {
759
+ if (!entity.mesh) {
760
+ return;
761
+ }
762
+ if (state.createdRootGroup && entity.group) {
763
+ const root = entity.group;
764
+ const parent2 = root.parent;
765
+ entity.mesh.position.copy(root.position);
766
+ entity.mesh.quaternion.copy(root.quaternion);
767
+ entity.mesh.scale.copy(root.scale);
768
+ entity.mesh.removeFromParent();
769
+ if (parent2) {
770
+ parent2.remove(root);
771
+ parent2.add(entity.mesh);
772
+ }
773
+ entity.group = void 0;
774
+ return;
775
+ }
776
+ const parent = state.originalMeshParent ?? entity.group;
777
+ if (parent && entity.mesh.parent !== parent) {
778
+ parent.add(entity.mesh);
779
+ }
780
+ }
781
+ function restoreRuntimeState(ref, refreshPhysics) {
782
+ const state = getRuntimeState(ref);
783
+ if (!state.isFractured) {
784
+ return;
785
+ }
786
+ const entity = requireEntity(ref);
787
+ if (state.fractureMode === "independent") {
788
+ destroyRuntimeFragmentEntities(ref, state);
789
+ } else {
790
+ state.fragmentContainer?.removeFromParent();
791
+ state.fragmentContainer?.clear();
792
+ disposeFragments(state.fragments);
793
+ }
794
+ state.fragmentContainer = null;
795
+ state.fragments = [];
796
+ restoreOriginalMesh(entity, state);
797
+ if (entity.mesh) {
798
+ entity.mesh.visible = state.originalMeshVisible;
799
+ }
800
+ if (entity.group) {
801
+ entity.group.visible = state.originalGroupVisible;
802
+ }
803
+ entity.colliderDesc = state.originalColliderDesc;
804
+ entity.colliderDescs = [...state.originalColliderDescs];
805
+ if (!entity.colliderDesc && entity.colliderDescs.length > 0) {
806
+ entity.colliderDesc = entity.colliderDescs[0];
807
+ }
808
+ if (refreshPhysics && state.sourcePhysicsAttached) {
809
+ attachEntityPhysics(ref, entity, state.sourceBodySnapshot);
810
+ }
811
+ state.createdRootGroup = false;
812
+ state.fractureMode = null;
813
+ state.originalMeshParent = null;
814
+ state.originalColliderDesc = void 0;
815
+ state.originalColliderDescs = [];
816
+ state.originalMeshVisible = true;
817
+ state.originalGroupVisible = true;
818
+ state.sourceBodySnapshot = null;
819
+ state.sourcePhysicsAttached = false;
820
+ state.isFractured = false;
821
+ }
822
+ function disposeRuntimeState(state) {
823
+ disposePrebakedFragmentTemplates(state.prebakedFragments);
824
+ state.prebakedFragments = [];
825
+ state.prebakedFractureKey = null;
826
+ }
827
+ function fractureCompoundEntity(ref, entity, root, fragments, state) {
828
+ const fragmentContainer = new Group();
829
+ fragmentContainer.name = `${entity.name ?? entity.uuid}-fracture-fragments`;
830
+ for (const fragment of fragments) {
831
+ fragmentContainer.add(fragment);
832
+ }
833
+ entity.mesh?.removeFromParent();
834
+ root.add(fragmentContainer);
835
+ state.fragmentContainer = fragmentContainer;
836
+ state.fractureMode = "compound";
837
+ const colliderDescs = fragments.map((fragment) => createFragmentColliderDesc(
838
+ fragment,
839
+ ref.options.collider,
840
+ fragment.position
841
+ ));
842
+ if (colliderDescs.length > 0) {
843
+ entity.colliderDescs = colliderDescs;
844
+ entity.colliderDesc = colliderDescs[0];
845
+ if (state.sourcePhysicsAttached) {
846
+ attachEntityPhysics(ref, entity, state.sourceBodySnapshot);
847
+ }
848
+ }
849
+ }
850
+ function fractureIndependentEntity(ref, entity, root, fractureOptions, fragments, state) {
851
+ const world = getBehaviorWorld(ref);
852
+ const scene = getBehaviorScene(ref);
853
+ if (!world || !scene) {
854
+ throw new Error(
855
+ "Destructible3DBehavior independent fragments require an active scene and physics world."
856
+ );
857
+ }
858
+ const createEntity = getBehaviorCreateEntity(ref);
859
+ if (!createEntity) {
860
+ throw new Error(
861
+ "Destructible3DBehavior independent fragments require a host entity factory (BehaviorSystemContext.createEntity)."
862
+ );
863
+ }
864
+ const physicsOptions = resolveFragmentPhysicsOptions(ref.options.fragmentPhysics);
865
+ const rootWorldPosition = getRootWorldPosition(root);
866
+ const impactPointWorld = getImpactPointWorld(root, fractureOptions);
867
+ const sourceVelocity = state.sourceBodySnapshot?.linearVelocity ?? null;
868
+ if (entity.mesh) {
869
+ entity.mesh.visible = false;
870
+ }
871
+ if (state.sourcePhysicsAttached) {
872
+ detachEntityPhysics(ref, entity);
873
+ }
874
+ const fragmentEntities = [];
875
+ for (const [index, fragment] of fragments.entries()) {
876
+ const fragmentWorldPose = computeFragmentWorldPose(root, fragment);
877
+ bakeScaleIntoFragmentGeometry(fragment, fragmentWorldPose.scale);
878
+ const fragmentEntity = createRuntimeFragmentEntity(
879
+ createEntity,
880
+ entity,
881
+ fragment,
882
+ index,
883
+ ref.options.collider,
884
+ fragmentWorldPose.position,
885
+ fragmentWorldPose.rotation
886
+ );
887
+ world.addEntity(fragmentEntity);
888
+ unlockIndependentFragmentPhysicsBody(fragmentEntity);
889
+ const linearVelocity = computeFragmentLinearVelocity(
890
+ fragmentWorldPose.position,
891
+ rootWorldPosition,
892
+ impactPointWorld,
893
+ physicsOptions,
894
+ sourceVelocity
895
+ );
896
+ fragmentEntity.body?.setLinvel(linearVelocity, true);
897
+ fragmentEntity.body?.setAngvel(
898
+ computeFragmentAngularVelocity(
899
+ index,
900
+ physicsOptions.angularVelocity
901
+ ),
902
+ true
903
+ );
904
+ syncRuntimeFragmentEntityTransform(
905
+ fragmentEntity,
906
+ world.interpolationAlpha ?? 0
907
+ );
908
+ const target = fragmentEntity.group ?? fragmentEntity.mesh;
909
+ if (target) {
910
+ target.removeFromParent();
911
+ scene.scene.add(target);
912
+ }
913
+ fragmentEntities.push(fragmentEntity);
914
+ }
915
+ state.fragmentEntities = fragmentEntities;
916
+ state.fractureMode = "independent";
917
+ }
918
+ function fractureEntity(ref, overrideOptions) {
919
+ const entity = requireEntity(ref);
920
+ if (entity.isInstanced) {
921
+ throw new Error(
922
+ "Destructible3DBehavior does not support entities using instanced rendering."
923
+ );
924
+ }
925
+ const state = getRuntimeState(ref);
926
+ if (state.isFractured) {
927
+ restoreRuntimeState(ref, true);
928
+ }
929
+ const sourceMesh = requireEntityMesh(entity);
930
+ const fractureOptions = resolveFractureOptions(
931
+ ref.options.fractureOptions,
932
+ overrideOptions
933
+ );
934
+ const cacheKey = buildFractureGeometryCacheKey(fractureOptions);
935
+ const root = ensureRootGroup(entity, state);
936
+ state.originalMeshParent = sourceMesh.parent;
937
+ state.originalColliderDesc = entity.colliderDesc;
938
+ state.originalColliderDescs = entity.colliderDescs.length > 0 ? [...entity.colliderDescs] : entity.colliderDesc ? [entity.colliderDesc] : [];
939
+ state.originalMeshVisible = sourceMesh.visible;
940
+ state.originalGroupVisible = entity.group?.visible ?? true;
941
+ state.sourceBodySnapshot = snapshotBody(entity);
942
+ state.sourcePhysicsAttached = entity.physicsAttached;
943
+ const usePrebakedFragments = state.prebakedFractureKey === cacheKey && state.prebakedFragments.length > 0;
944
+ const source = usePrebakedFragments ? null : createFractureSourceMesh(
945
+ sourceMesh,
946
+ root,
947
+ ref.options.innerMaterial
948
+ );
949
+ try {
950
+ const fragmentPhysics = resolveFragmentPhysicsOptions(
951
+ ref.options.fragmentPhysics
952
+ );
953
+ const fragments = usePrebakedFragments ? instantiatePrebakedFragments(
954
+ sourceMesh,
955
+ ref.options.innerMaterial,
956
+ state.prebakedFragments
957
+ ) : source.fracture(fractureOptions);
958
+ cachePrebakedFragments(state, cacheKey, fragments);
959
+ state.fragments = [...fragments];
960
+ state.isFractured = true;
961
+ if (fragmentPhysics.mode === "independent") {
962
+ fractureIndependentEntity(
963
+ ref,
964
+ entity,
965
+ root,
966
+ fractureOptions,
967
+ fragments,
968
+ state
969
+ );
970
+ } else {
971
+ fractureCompoundEntity(
972
+ ref,
973
+ entity,
974
+ root,
975
+ fragments,
976
+ state
977
+ );
978
+ }
979
+ return fragments;
980
+ } catch (error) {
981
+ restoreRuntimeState(ref, true);
982
+ throw error;
983
+ } finally {
984
+ source?.geometry.dispose();
985
+ }
986
+ }
987
+ function prebakeEntityGeometryOnly(ref, overrideOptions) {
988
+ const entity = requireEntity(ref);
989
+ if (entity.isInstanced) {
990
+ throw new Error(
991
+ "Destructible3DBehavior does not support entities using instanced rendering."
992
+ );
993
+ }
994
+ const state = getRuntimeState(ref);
995
+ if (state.isFractured) {
996
+ return;
997
+ }
998
+ const fractureOptions = resolveFractureOptions(
999
+ ref.options.fractureOptions,
1000
+ overrideOptions
1001
+ );
1002
+ const cacheKey = buildFractureGeometryCacheKey(fractureOptions);
1003
+ if (state.prebakedFractureKey === cacheKey && state.prebakedFragments.length > 0) {
1004
+ return;
1005
+ }
1006
+ const sourceMesh = requireEntityMesh(entity);
1007
+ const root = ensureRootGroup(entity, state);
1008
+ const createdRootGroup = state.createdRootGroup;
1009
+ const source = createFractureSourceMesh(
1010
+ sourceMesh,
1011
+ root,
1012
+ ref.options.innerMaterial
1013
+ );
1014
+ try {
1015
+ const fragments = source.fracture(fractureOptions);
1016
+ cachePrebakedFragments(state, cacheKey, fragments);
1017
+ for (const fragment of fragments) {
1018
+ fragment.geometry.dispose();
1019
+ }
1020
+ } finally {
1021
+ source.geometry.dispose();
1022
+ }
1023
+ if (createdRootGroup) {
1024
+ restoreOriginalMesh(entity, state);
1025
+ state.createdRootGroup = false;
1026
+ }
1027
+ }
1028
+ async function prebakeEntityAsync(ref, overrideOptions) {
1029
+ const workerUrl = ref.options.prebakeWorkerUrl;
1030
+ if (!workerUrl) {
1031
+ prebakeEntityGeometryOnly(ref, overrideOptions);
1032
+ return;
1033
+ }
1034
+ const existing = prebakeAsyncInFlight.get(ref);
1035
+ if (existing) {
1036
+ await existing;
1037
+ return;
1038
+ }
1039
+ const job = (async () => {
1040
+ const entity = requireEntity(ref);
1041
+ if (entity.isInstanced) {
1042
+ throw new Error(
1043
+ "Destructible3DBehavior does not support entities using instanced rendering."
1044
+ );
1045
+ }
1046
+ const state = getRuntimeState(ref);
1047
+ if (state.isFractured) {
1048
+ return;
1049
+ }
1050
+ const fractureOptions = resolveFractureOptions(
1051
+ ref.options.fractureOptions,
1052
+ overrideOptions
1053
+ );
1054
+ const cacheKey = buildFractureGeometryCacheKey(fractureOptions);
1055
+ if (state.prebakedFractureKey === cacheKey && state.prebakedFragments.length > 0) {
1056
+ return;
1057
+ }
1058
+ const sourceMesh = requireEntityMesh(entity);
1059
+ const root = ensureRootGroup(entity, state);
1060
+ const createdRootGroup = state.createdRootGroup;
1061
+ const normalizedGeometry = buildNormalizedFractureSourceGeometry(
1062
+ sourceMesh,
1063
+ root
1064
+ );
1065
+ if (createdRootGroup) {
1066
+ restoreOriginalMesh(entity, state);
1067
+ state.createdRootGroup = false;
1068
+ }
1069
+ const { payload, transferables } = bufferGeometryToPlain(normalizedGeometry);
1070
+ normalizedGeometry.dispose();
1071
+ const plainOptions = pinataFractureOptionsToPlain(fractureOptions);
1072
+ const api = getPrebakeWorkerApi(workerUrl);
1073
+ const request = Comlink.transfer(
1074
+ { geometry: payload, options: plainOptions },
1075
+ transferables
1076
+ );
1077
+ const response = await api.prebake(request);
1078
+ const parts = plainWorkerResultToTemplateParts(response);
1079
+ installPrebakedTemplateParts(state, cacheKey, parts);
1080
+ })();
1081
+ prebakeAsyncInFlight.set(ref, job);
1082
+ try {
1083
+ await job;
1084
+ } finally {
1085
+ if (prebakeAsyncInFlight.get(ref) === job) {
1086
+ prebakeAsyncInFlight.delete(ref);
1087
+ }
1088
+ }
1089
+ }
1090
+ function prebakeEntity(ref, overrideOptions) {
1091
+ prebakeEntityGeometryOnly(ref, overrideOptions);
1092
+ }
1093
+ function createDestructible3DHandle(ref) {
1094
+ return {
1095
+ fracture: (overrideOptions) => fractureEntity(ref, overrideOptions),
1096
+ prebake: (overrideOptions) => {
1097
+ prebakeEntity(ref, overrideOptions);
1098
+ },
1099
+ prebakeAsync: (overrideOptions) => prebakeEntityAsync(ref, overrideOptions),
1100
+ repair: () => restoreRuntimeState(ref, true),
1101
+ isFractured: () => getRuntimeState(ref).isFractured,
1102
+ getFragments: () => getRuntimeState(ref).fragments
1103
+ };
1104
+ }
1105
+ var Destructible3DSystem = class {
1106
+ constructor(world, scene, getBehaviorLinks, createEntity, getGlobals) {
1107
+ this.world = world;
1108
+ this.scene = scene;
1109
+ this.getBehaviorLinks = getBehaviorLinks;
1110
+ this.createEntity = createEntity;
1111
+ this.getGlobals = getGlobals;
1112
+ this.primeLinks();
1113
+ }
1114
+ world;
1115
+ scene;
1116
+ getBehaviorLinks;
1117
+ createEntity;
1118
+ getGlobals;
1119
+ attach(link) {
1120
+ if (link.ref?.descriptor?.key !== DESTRUCTIBLE_3D_BEHAVIOR_KEY) {
1121
+ return;
1122
+ }
1123
+ this.primeLink(link);
1124
+ }
1125
+ update(_ecs, _delta) {
1126
+ this.primeLinks();
1127
+ const links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);
1128
+ if (!links) {
1129
+ return;
1130
+ }
1131
+ const interpolationAlpha = this.world?.interpolationAlpha ?? 0;
1132
+ for (const link of links) {
1133
+ const state = getRuntimeState(
1134
+ link.ref
1135
+ );
1136
+ for (const fragmentEntity of state.fragmentEntities) {
1137
+ syncRuntimeFragmentEntityTransform(
1138
+ fragmentEntity,
1139
+ interpolationAlpha
1140
+ );
1141
+ }
1142
+ }
1143
+ }
1144
+ destroy(_ecs) {
1145
+ const links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);
1146
+ if (!links) {
1147
+ return;
1148
+ }
1149
+ for (const link of links) {
1150
+ const ref = link.ref;
1151
+ restoreRuntimeState(ref, false);
1152
+ disposeRuntimeState(getRuntimeState(ref));
1153
+ }
1154
+ }
1155
+ primeLinks() {
1156
+ const links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);
1157
+ if (!links) {
1158
+ return;
1159
+ }
1160
+ for (const link of links) {
1161
+ this.primeLink(link);
1162
+ }
1163
+ }
1164
+ primeLink(link) {
1165
+ const ref = link.ref;
1166
+ const entity = link.entity;
1167
+ ref.__entity = entity;
1168
+ ref.__world = this.world;
1169
+ ref.__scene = this.scene;
1170
+ ref.__createEntity = this.createEntity;
1171
+ ref.__getGlobals = this.getGlobals;
1172
+ if (!ref.__cleanupRegistered) {
1173
+ entity.onCleanup(() => {
1174
+ restoreRuntimeState(ref, false);
1175
+ disposeRuntimeState(getRuntimeState(ref));
1176
+ });
1177
+ ref.__cleanupRegistered = true;
1178
+ }
1179
+ }
1180
+ };
1181
+ var Destructible3DBehavior = defineBehavior({
1182
+ name: "destructible-3d",
1183
+ defaultOptions,
1184
+ systemFactory: (ctx) => new Destructible3DSystem(
1185
+ ctx.world,
1186
+ ctx.scene,
1187
+ ctx.getBehaviorLinks,
1188
+ ctx.createEntity,
1189
+ ctx.getGlobals
1190
+ ),
1191
+ createHandle: createDestructible3DHandle
1192
+ });
1193
+
1194
+ // src/lib/behaviors/destructible-3d/index.ts
1195
+ import {
1196
+ DestructibleMesh as DestructibleMesh2,
1197
+ FractureOptions
1198
+ } from "@dgreenheck/three-pinata";
1199
+
1200
+ export {
1201
+ Destructible3DBehavior,
1202
+ DestructibleMesh2 as DestructibleMesh,
1203
+ FractureOptions
1204
+ };
1205
+ //# sourceMappingURL=chunk-BXP4K7RF.js.map