( entity: EntityData, ctx: InstantiateContext, warnings: string[], )
| 220 | } |
| 221 | |
| 222 | function spawnPrefabEntity( |
| 223 | entity: EntityData, |
| 224 | ctx: InstantiateContext, |
| 225 | warnings: string[], |
| 226 | ): SceneNodeHandle { |
| 227 | if (!ctx.prefabRegistry) { |
| 228 | warnings.push( |
| 229 | 'entity ' + entity.id + ' references prefab "' + entity.prefabRef + '" but no PrefabRegistry was provided — skipped', |
| 230 | ); |
| 231 | return 0; |
| 232 | } |
| 233 | |
| 234 | // Create a root group node at the entity's transform. Expanded leaves are |
| 235 | // parented to this root so the editor gizmo can move the whole prefab as |
| 236 | // one unit. |
| 237 | const root = createSceneNode(); |
| 238 | const rootMatrix = trsToMat4(entity.transform); |
| 239 | setSceneNodeTransform(root, rootMatrix); |
| 240 | setSceneNodeVisible(root, true); |
| 241 | |
| 242 | // Expand the prefab into its leaf glbs and spawn one scene node per leaf. |
| 243 | // `expandPrefab` accumulates leaves into `leaves` and any errors into a |
| 244 | // local list which we fold into the top-level warnings. |
| 245 | const leaves: PrefabLeaf[] = []; |
| 246 | const expandErrors: string[] = []; |
| 247 | const visited = new Set<string>(); |
| 248 | expandPrefab( |
| 249 | ctx.prefabRegistry, |
| 250 | entity.prefabRef as string, |
| 251 | mat4Identity(), |
| 252 | entity.tint, |
| 253 | entity.tags, |
| 254 | leaves, |
| 255 | expandErrors, |
| 256 | visited, |
| 257 | 'world.entities[' + entity.id + ']', |
| 258 | ); |
| 259 | |
| 260 | for (let i = 0; i < expandErrors.length; i++) warnings.push(expandErrors[i]); |
| 261 | |
| 262 | for (let i = 0; i < leaves.length; i++) { |
| 263 | const leaf = leaves[i]; |
| 264 | const modelHandle = ctx.getModelHandle(leaf.modelRef); |
| 265 | if (modelHandle === 0) { |
| 266 | warnings.push( |
| 267 | 'prefab leaf ' + leaf.sourcePath + ' references unknown model "' + leaf.modelRef + '" — skipped', |
| 268 | ); |
| 269 | continue; |
| 270 | } |
| 271 | const leafNode = createSceneNode(); |
| 272 | attachModelToNode(leafNode, modelHandle, 0); |
| 273 | setSceneNodeTransform(leafNode, leaf.worldMatrix); |
| 274 | if (leaf.tint !== null) applyTint(leafNode, leaf.tint); |
| 275 | setSceneNodeParent(leafNode, root); |
| 276 | setSceneNodeVisible(leafNode, true); |
| 277 | } |
| 278 | |
| 279 | return root; |
no test coverage detected