( registry: PrefabRegistry, prefabId: string, parentMatrix: Mat4, parentTint: Vec4Lit | null, parentTags: ReadonlyArray<string>, out: PrefabLeaf[], errors: string[], visited: Set<string>, pathPrefix: string, )
| 101 | // @param visited Set of ancestor prefab ids, used for cycle detection. |
| 102 | // @param pathPrefix Debug path for error messages, e.g. "world_root". |
| 103 | export function expandPrefab( |
| 104 | registry: PrefabRegistry, |
| 105 | prefabId: string, |
| 106 | parentMatrix: Mat4, |
| 107 | parentTint: Vec4Lit | null, |
| 108 | parentTags: ReadonlyArray<string>, |
| 109 | out: PrefabLeaf[], |
| 110 | errors: string[], |
| 111 | visited: Set<string>, |
| 112 | pathPrefix: string, |
| 113 | ): void { |
| 114 | if (visited.has(prefabId)) { |
| 115 | errors.push( |
| 116 | 'prefab cycle detected: ' + pathPrefix + ' -> ' + prefabId + |
| 117 | ' (already in chain)', |
| 118 | ); |
| 119 | return; |
| 120 | } |
| 121 | |
| 122 | const prefab = registry.getPrefab(prefabId); |
| 123 | if (!prefab) { |
| 124 | errors.push('prefab not found: "' + prefabId + '" (referenced by ' + pathPrefix + ')'); |
| 125 | return; |
| 126 | } |
| 127 | |
| 128 | visited.add(prefabId); |
| 129 | |
| 130 | for (let i = 0; i < prefab.children.length; i++) { |
| 131 | const child = prefab.children[i]; |
| 132 | const childMatrix = mat4Multiply(parentMatrix, trsToMat4(child.transform)); |
| 133 | const childTint = child.tint !== null ? child.tint : parentTint; |
| 134 | const childTags = mergeTags(parentTags, child.tags); |
| 135 | const childPath = pathPrefix + '.' + child.id; |
| 136 | |
| 137 | if (child.modelRef !== null && child.modelRef.length > 0) { |
| 138 | out.push({ |
| 139 | modelRef: child.modelRef, |
| 140 | worldMatrix: childMatrix, |
| 141 | tint: childTint, |
| 142 | tags: childTags, |
| 143 | sourcePath: childPath, |
| 144 | }); |
| 145 | } else if (child.prefabRef !== null && child.prefabRef.length > 0) { |
| 146 | expandPrefab( |
| 147 | registry, |
| 148 | child.prefabRef, |
| 149 | childMatrix, |
| 150 | childTint, |
| 151 | childTags, |
| 152 | out, |
| 153 | errors, |
| 154 | visited, |
| 155 | childPath, |
| 156 | ); |
| 157 | } else { |
| 158 | errors.push('prefab child ' + childPath + ' has neither modelRef nor prefabRef'); |
| 159 | } |
| 160 | } |
no test coverage detected