Part of #121. See IDEA.md stage 5.
Goal
scene_ops.inject_object_into_scene today:
# tmpdir, save XML via mj_saveLastXML, ET.parse, find worldbody,
# append child, delete <keyframe>, write, reload from path
Target:
def inject_object_into_scene(world, obj):
spec = world._backend_state['spec']
SpecBuilder._add_object(spec, obj)
world._model, world._data = spec.recompile(world._model, world._data)
return True
Also port eject_body_from_scene, inject_camera_into_scene, eject_robot_from_scene.
Known gotcha
recompile(model, data) preserves qpos only when joint dims are unchanged. Adding a freejoint changes nqpos (new 7 slots). Current code deletes <keyframe> elements. MjSpec has spec.keys - need to either clear or resize.
Acceptance
- All 4
inject_*/eject_* helpers have a spec-path alongside the legacy ET-based path (flag-gated).
- Policy state (qpos) preserved across a mutation when no joint dims change.
- Keyframe-dim mismatch from adding a freejoint handled cleanly (no 'qpos size mismatch' errors).
_patch_xml_paths, _rewrite_mesh_paths, _get_abs_meshdir, _save_and_patch_xml deleted once all callers migrated (or marked for Stage 7).
Part of #121. See IDEA.md stage 5.
Goal
scene_ops.inject_object_into_scenetoday:Target:
Also port
eject_body_from_scene,inject_camera_into_scene,eject_robot_from_scene.Known gotcha
recompile(model, data)preserves qpos only when joint dims are unchanged. Adding a freejoint changes nqpos (new 7 slots). Current code deletes<keyframe>elements. MjSpec hasspec.keys- need to either clear or resize.Acceptance
inject_*/eject_*helpers have a spec-path alongside the legacy ET-based path (flag-gated)._patch_xml_paths,_rewrite_mesh_paths,_get_abs_meshdir,_save_and_patch_xmldeleted once all callers migrated (or marked for Stage 7).