Check that there are no pending keyframes while writing a spec.

This can happen when a body is detached without compiling or recompiling.

Also added error catching when trying to delete a body instead of detaching it.

Fixes #2327

PiperOrigin-RevId: 712526730
Change-Id: I4b48df83120fca12d475c85b3a54893841449653
This commit is contained in:
Alessio Quaglino
2025-01-06 07:49:35 -08:00
committed by Copybara-Service
parent b5df2c10bf
commit f607d9554e
9 changed files with 37 additions and 15 deletions
+10 -3
View File
@@ -254,10 +254,17 @@ int mjs_activatePlugin(mjSpec* s, const char* name) {
// delete object, it will call the appropriate destructor since ~mjCBase is virtual
void mjs_delete(mjsElement* element) {
// delete object, return 0 if success
int mjs_delete(mjsElement* element) {
mjCBase* object = static_cast<mjCBase*>(element);
object->model->DeleteElement(element);
try {
// it will call the appropriate destructor since ~mjCBase is virtual
object->model->DeleteElement(element);
return 0;
} catch (mjCError& e) {
object->model->SetError(e);
return -1;
}
}
+2 -2
View File
@@ -108,8 +108,8 @@ MJAPI mjsLight* mjs_addLight(mjsBody* body, const mjsDefault* def);
// Add frame to body.
MJAPI mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
// Delete object corresponding to the given element.
MJAPI void mjs_delete(mjsElement* element);
// Delete object corresponding to the given element, return 0 on success.
MJAPI int mjs_delete(mjsElement* element);
//---------------------------------- Add non-tree elements -----------------------------------------
-1
View File
@@ -530,7 +530,6 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
ResetTreeLists();
}
PointToLocal();
return *this;
}
+5 -1
View File
@@ -858,7 +858,7 @@ mjXWriter::mjXWriter(void) {
// cast model
void mjXWriter::SetModel(const mjSpec* _spec, const mjModel* m) {
if (_spec) {
model = (mjCModel*)_spec->element;
model = static_cast<mjCModel*>(_spec->element);
}
if (m) {
model->CopyBack(m);
@@ -2207,6 +2207,10 @@ void mjXWriter::Keyframe(XMLElement* root) {
// create section
XMLElement* section = InsertEnd(root, "keyframe");
if (!model->key_pending_.empty()) {
throw mjXError(0, "Model has pending keyframes. It must be (re)compiled before writing XML.");
}
// write all keyframes
for (int i=0; i<model->nkey; i++) {
XMLElement* elem = InsertEnd(section, "key");