Copy ``elem`` into ``out_parent``, recursively expanding any descendants in place. Handles both and include roots and rewrites asset file= paths to stay valid from root_dir.
(out_parent, elem, src_dir: Path, root_dir: Path,
meshdir: str, texturedir: str, assetdir: str, visited: set)
| 159 | |
| 160 | def _rewrite_asset_path(elem, src_dir: Path, root_dir: Path, |
| 161 | meshdir: str, texturedir: str, assetdir: str): |
| 162 | """Rewrite an asset element's ``file=`` so it resolves from ``root_dir`` (the |
| 163 | output _ue.xml location) after the declaring file has been spliced in. |
| 164 | |
| 165 | Paths are resolved relative to the *declaring* file's directory plus its |
| 166 | meshdir/texturedir/assetdir, matching how the C++ importer resolves includes, |
| 167 | then re-expressed relative to root_dir. The companion <compiler> dir |
| 168 | attributes are cleared by the caller so nothing double-prefixes them. |
| 169 | """ |
| 170 | file_attr = elem.get("file") |
| 171 | if not file_attr: |
| 172 | return |
| 173 | if elem.tag == "texture": |
| 174 | subdir = texturedir or assetdir |
| 175 | else: # mesh, hfield, skin |
| 176 | subdir = meshdir or assetdir |
| 177 | base = src_dir / subdir if subdir else src_dir |
| 178 | abs_path = (base / file_attr).resolve() |
| 179 | try: |
| 180 | rel = os.path.relpath(abs_path, root_dir) |
| 181 | except ValueError: |
| 182 | rel = str(abs_path) # different drive on Windows — keep absolute |
| 183 | elem.set("file", rel.replace("\\", "/")) |
| 184 | |
| 185 | |
| 186 | def _append_expanded(out_parent, elem, src_dir: Path, root_dir: Path, |
| 187 | meshdir: str, texturedir: str, assetdir: str, visited: set): |
| 188 | """Copy ``elem`` into ``out_parent``, recursively expanding any <include> |
| 189 | descendants in place. Handles both <mujoco> and <mujocoinclude> include roots |
| 190 | and rewrites asset file= paths to stay valid from root_dir.""" |
| 191 | if elem.tag == "include": |
| 192 | inc_file = elem.get("file") |
| 193 | if not inc_file: |
| 194 | return |
| 195 | inc_path = (src_dir / inc_file).resolve() |
| 196 | if inc_path in visited: |
| 197 | print(f" [include] cycle/duplicate skipped: {inc_path}") |
| 198 | return |
| 199 | if not inc_path.exists(): |
| 200 | print(f" x [include] file not found, leaving unresolved: {inc_path}") |
| 201 | return |
| 202 | visited.add(inc_path) |
| 203 | inc_root = ET.parse(str(inc_path)).getroot() |
no test coverage detected