From 0ba11b96233df07275a25cf328aeb4f950b0bad9 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Mon, 23 Sep 2024 06:12:42 -0700 Subject: [PATCH] Add `plugins` list to mjSpec Python API. Fixes #2061. PiperOrigin-RevId: 677762985 Change-Id: I8e407373e7b505d9b0f1c023e97c5ea92169bbf6 --- doc/APIreference/functions.rst | 9 +++++++++ doc/includes/references.h | 3 ++- include/mujoco/mjspec.h | 2 +- include/mujoco/mujoco.h | 3 +++ introspect/functions.py | 16 ++++++++++++++++ introspect/structs.py | 2 +- python/mujoco/specs.cc | 18 +++++++++++++++--- python/mujoco/specs_test.py | 27 +++++++++++++++++++++++++++ src/user/user_api.cc | 14 ++++++++++++-- src/user/user_api.h | 3 +++ src/user/user_composite.cc | 4 ++-- src/user/user_flexcomp.cc | 6 +++--- src/user/user_mesh.cc | 12 ++++++------ src/user/user_model.cc | 10 ++++++---- src/user/user_objects.cc | 32 ++++++++++++++++---------------- src/xml/xml_native_reader.cc | 2 +- src/xml/xml_native_writer.cc | 4 ++-- test/user/user_api_test.cc | 4 ++-- 18 files changed, 127 insertions(+), 44 deletions(-) diff --git a/doc/APIreference/functions.rst b/doc/APIreference/functions.rst index 60fa14a1..81a3841a 100644 --- a/doc/APIreference/functions.rst +++ b/doc/APIreference/functions.rst @@ -4432,6 +4432,15 @@ mjs_asMaterial Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial. +.. _mjs_asPlugin: + +mjs_asPlugin +~~~~~~~~~~~~ + +.. mujoco-include:: mjs_asPlugin + +Safely cast an element as mjsPlugin, or return NULL if the element is not an mjsPlugin. + .. _AttributeSetters: Attribute setters diff --git a/doc/includes/references.h b/doc/includes/references.h index c7669ec8..d1e11e55 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -1738,7 +1738,7 @@ typedef struct mjsOrientation_ { // alternative orientation specifiers double euler[3]; // Euler angles } mjsOrientation; typedef struct mjsPlugin_ { // plugin specification - mjsElement* instance; // element type + mjsElement* element; // element type mjString* name; // name mjString* instance_name; // instance name int plugin_slot; // global registered slot number of the plugin @@ -3622,6 +3622,7 @@ mjsHField* mjs_asHField(mjsElement* element); mjsSkin* mjs_asSkin(mjsElement* element); mjsTexture* mjs_asTexture(mjsElement* element); mjsMaterial* mjs_asMaterial(mjsElement* element); +mjsPlugin* mjs_asPlugin(mjsElement* element); void mjs_setBuffer(mjByteVec* dest, const void* array, int size); void mjs_setString(mjString* dest, const char* text); void mjs_setStringVec(mjStringVec* dest, const char* text); diff --git a/include/mujoco/mjspec.h b/include/mujoco/mjspec.h index 90bc6c9a..807ef71c 100644 --- a/include/mujoco/mjspec.h +++ b/include/mujoco/mjspec.h @@ -181,7 +181,7 @@ typedef struct mjsOrientation_ { // alternative orientation specifiers typedef struct mjsPlugin_ { // plugin specification - mjsElement* instance; // element type + mjsElement* element; // element type mjString* name; // name mjString* instance_name; // instance name int plugin_slot; // global registered slot number of the plugin diff --git a/include/mujoco/mujoco.h b/include/mujoco/mujoco.h index fbf9b151..cdc63388 100644 --- a/include/mujoco/mujoco.h +++ b/include/mujoco/mujoco.h @@ -1628,6 +1628,9 @@ MJAPI mjsTexture* mjs_asTexture(mjsElement* element); // Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial. MJAPI mjsMaterial* mjs_asMaterial(mjsElement* element); +// Safely cast an element as mjsPlugin, or return NULL if the element is not an mjsPlugin. +MJAPI mjsPlugin* mjs_asPlugin(mjsElement* element); + //---------------------------------- Attribute setters --------------------------------------------- diff --git a/introspect/functions.py b/introspect/functions.py index 838c1cff..f5f6cb08 100644 --- a/introspect/functions.py +++ b/introspect/functions.py @@ -10270,6 +10270,22 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([ ), doc='Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial.', # pylint: disable=line-too-long )), + ('mjs_asPlugin', + FunctionDecl( + name='mjs_asPlugin', + return_type=PointerType( + inner_type=ValueType(name='mjsPlugin'), + ), + parameters=( + FunctionParameterDecl( + name='element', + type=PointerType( + inner_type=ValueType(name='mjsElement'), + ), + ), + ), + doc='Safely cast an element as mjsPlugin, or return NULL if the element is not an mjsPlugin.', # pylint: disable=line-too-long + )), ('mjs_setBuffer', FunctionDecl( name='mjs_setBuffer', diff --git a/introspect/structs.py b/introspect/structs.py index 149ebef0..cfaa5809 100644 --- a/introspect/structs.py +++ b/introspect/structs.py @@ -8565,7 +8565,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([ declname='struct mjsPlugin_', fields=( StructFieldDecl( - name='instance', + name='element', type=PointerType( inner_type=ValueType(name='mjsElement'), ), diff --git a/python/mujoco/specs.cc b/python/mujoco/specs.cc index 5dd4621e..04200af6 100644 --- a/python/mujoco/specs.cc +++ b/python/mujoco/specs.cc @@ -274,6 +274,18 @@ PYBIND11_MODULE(_specs, m) { mjSpec.def("detach_body", [](MjSpec& self, raw::MjsBody& body) { mjs_detachBody(self.ptr, &body); }); + mjSpec.def_property_readonly( + "plugins", + [](MjSpec& self) -> py::list { + py::list list; + raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_PLUGIN); + while (el) { + list.append(mjs_asPlugin(el)); + el = mjs_nextElement(self.ptr, el); + } + return list; + }, + py::return_value_policy::reference_internal); mjSpec.def_property_readonly( "actuators", [](MjSpec& self) -> py::list { @@ -900,12 +912,12 @@ PYBIND11_MODULE(_specs, m) { // ============================= MJSPLUGIN =================================== mjsPlugin.def_property( "id", - [](raw::MjsPlugin& self) -> int { return mjs_getId(self.instance); }, + [](raw::MjsPlugin& self) -> int { return mjs_getId(self.element); }, [](raw::MjsPlugin& self, raw::MjsPlugin* other) { - self.instance = other->instance; + self.element = other->element; }); mjsPlugin.def("delete", - [](raw::MjsPlugin& self) { mjs_delete(self.instance); }); + [](raw::MjsPlugin& self) { mjs_delete(self.element); }); #include "specs.cc.inc" } // PYBIND11_MODULE // NOLINT diff --git a/python/mujoco/specs_test.py b/python/mujoco/specs_test.py index fb3a1321..8ddaf8c1 100644 --- a/python/mujoco/specs_test.py +++ b/python/mujoco/specs_test.py @@ -690,5 +690,32 @@ class SpecsTest(absltest.TestCase): ): spec.recompile(model, data) + def test_delete_unused_plugin(self): + spec = mujoco.MjSpec() + spec.from_string(textwrap.dedent(""" + + + + + + + + + + + + + + + + """)) + plugin = spec.plugins[0] + self.assertIsNotNone(plugin) + plugin.delete() + + model = spec.compile() + self.assertIsNotNone(model) + self.assertEqual(model.nplugin, 0) + if __name__ == '__main__': absltest.main() diff --git a/src/user/user_api.cc b/src/user/user_api.cc index 4253f2ed..fe686dcb 100644 --- a/src/user/user_api.cc +++ b/src/user/user_api.cc @@ -471,7 +471,7 @@ mjsKey* mjs_addKey(mjSpec* s) { mjsPlugin* mjs_addPlugin(mjSpec* s) { mjCModel* modelC = static_cast(s->element); mjCPlugin* plugin = modelC->AddPlugin(); - plugin->spec.instance = static_cast(plugin); + plugin->spec.element = static_cast(plugin); return &plugin->spec; } @@ -887,6 +887,16 @@ mjsMaterial* mjs_asMaterial(mjsElement* element) { +// return plugin given mjsElement +mjsPlugin* mjs_asPlugin(mjsElement* element) { + if (element && element->elemtype == mjOBJ_PLUGIN) { + return &(static_cast(element)->spec); + } + return nullptr; +} + + + // copy buffer to destination buffer void mjs_setBuffer(mjByteVec* dest, const void* array, int size) { const std::byte* buffer = static_cast(array); @@ -995,7 +1005,7 @@ const double* mjs_getDouble(const mjDoubleVec* source, int* size) { // set plugin attributes void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes) { - mjCPlugin* pluginC = static_cast(plugin->instance); + mjCPlugin* pluginC = static_cast(plugin->element); std::map>* config_attribs = reinterpret_cast>*>(attributes); pluginC->config_attribs = std::move(*config_attribs); diff --git a/src/user/user_api.h b/src/user/user_api.h index 35799bad..a1b80dd2 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -296,6 +296,9 @@ MJAPI mjsTexture* mjs_asTexture(mjsElement* element); // Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial. MJAPI mjsMaterial* mjs_asMaterial(mjsElement* element); +// Safely cast an element as mjsPlugin, or return NULL if the element is not an mjsPlugin. +MJAPI mjsPlugin* mjs_asPlugin(mjsElement* element); + //---------------------------------- Attribute setters --------------------------------------------- diff --git a/src/user/user_composite.cc b/src/user/user_composite.cc index 26c3a3db..d18ba94b 100644 --- a/src/user/user_composite.cc +++ b/src/user/user_composite.cc @@ -315,7 +315,7 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) // overwrite plugin name if (plugin_instance_name.empty() && plugin.active) { plugin_instance_name = "composite" + prefix; - (static_cast(plugin.instance))->name = plugin_instance_name; + (static_cast(plugin.element))->name = plugin_instance_name; } // dispatch @@ -714,7 +714,7 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix, if (plugin.active) { mjsPlugin* pplugin = &body->plugin; pplugin->active = true; - pplugin->instance = plugin.instance; + pplugin->element = plugin.element; mjs_setString(pplugin->name, mjs_getString(plugin.name)); mjs_setString(pplugin->instance_name, plugin_instance_name.c_str()); } diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 2243c1f5..4f5b4354 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -422,7 +422,7 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) { // overwrite plugin name if (plugin.active && plugin_instance_name.empty()) { plugin_instance_name = "flexcomp_" + name; - static_cast(plugin.instance)->name = plugin_instance_name; + static_cast(plugin.element)->name = plugin_instance_name; } // create bodies, construct flex vert and vertbody @@ -440,7 +440,7 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) { if (plugin.active) { mjsPlugin* pplugin = &body->plugin; pplugin->active = true; - pplugin->instance = static_cast(plugin.instance); + pplugin->element = static_cast(plugin.element); mjs_setString(pplugin->name, mjs_getString(plugin.name)); mjs_setString(pplugin->instance_name, plugin_instance_name.c_str()); } @@ -504,7 +504,7 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) { if (plugin.active) { mjsPlugin* pplugin = &pb->plugin; pplugin->active = true; - pplugin->instance = static_cast(plugin.instance); + pplugin->element = static_cast(plugin.element); mjs_setString(pplugin->name, mjs_getString(plugin.name)); mjs_setString(pplugin->instance_name, plugin_instance_name.c_str()); } diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index 2a398c6f..d06905b3 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -246,7 +246,7 @@ void mjCMesh::CopyFromSpec() { facetexcoord_ = spec_facetexcoord_; maxhullvert_ = spec.maxhullvert; plugin.active = spec.plugin.active; - plugin.instance = spec.plugin.instance; + plugin.element = spec.plugin.element; plugin.name = spec.plugin.name; plugin.instance_name = spec.plugin.instance_name; @@ -270,7 +270,7 @@ mjCMesh::~mjCMesh() { if (center_) mju_free(center_); if (graph_) mju_free(graph_); if (spec.plugin.active && spec.plugin.instance_name->empty()) { - model->DeleteElement(spec.plugin.instance); + model->DeleteElement(spec.plugin.element); } } @@ -289,9 +289,9 @@ void mjCMesh::LoadSDF() { name.c_str(), id); } - mjCPlugin* plugin_instance = static_cast(plugin.instance); + mjCPlugin* plugin_instance = static_cast(plugin.element); model->ResolvePlugin(this, plugin_name, plugin_instance_name, &plugin_instance); - plugin.instance = plugin_instance; + plugin.element = plugin_instance; const mjpPlugin* pplugin = mjp_getPluginAtSlot(plugin_instance->spec.plugin_slot); if (!(pplugin->capabilityflags & mjPLUGIN_SDF)) { throw mjCError(this, "plugin '%s' does not support signed distance fields", pplugin->name); @@ -2919,9 +2919,9 @@ void mjCFlex::Compile(const mjVFS* vfs) { useredge = VectorToString(edgeidx_); for (const auto& vbodyid : vertbodyid) { - if (model->Bodies()[vbodyid]->plugin.instance) { + if (model->Bodies()[vbodyid]->plugin.element) { mjCPlugin* plugin_instance = - static_cast(model->Bodies()[vbodyid]->plugin.instance); + static_cast(model->Bodies()[vbodyid]->plugin.element); if (damping > 0) { plugin_instance->config_attribs["damping"] = std::to_string(damping); } diff --git a/src/user/user_model.cc b/src/user/user_model.cc index 1bfa3c70..b189677b 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -938,6 +938,8 @@ mjsElement* mjCModel::NextObject(mjsElement* object, mjtObj type) { return GetNext(textures_, object); case mjOBJ_MATERIAL: return GetNext(materials_, object); + case mjOBJ_PLUGIN: + return GetNext(plugins_, object); default: return nullptr; } @@ -3932,7 +3934,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { std::vector> plugin_to_actuators(nplugin); for (int i = 0; i < nu; ++i) { if (actuators_[i]->plugin.active) { - int actuator_plugin = static_cast(actuators_[i]->plugin.instance)->id; + int actuator_plugin = static_cast(actuators_[i]->plugin.element)->id; m->actuator_plugin[i] = actuator_plugin; plugin_to_actuators[actuator_plugin].push_back(i); } else { @@ -3942,7 +3944,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { for (int i = 0; i < nbody; ++i) { if (bodies_[i]->plugin.active) { - m->body_plugin[i] = static_cast(bodies_[i]->plugin.instance)->id; + m->body_plugin[i] = static_cast(bodies_[i]->plugin.element)->id; } else { m->body_plugin[i] = -1; } @@ -3950,7 +3952,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { for (int i = 0; i < ngeom; ++i) { if (geoms_[i]->plugin.active) { - m->geom_plugin[i] = static_cast(geoms_[i]->plugin.instance)->id; + m->geom_plugin[i] = static_cast(geoms_[i]->plugin.element)->id; } else { m->geom_plugin[i] = -1; } @@ -3959,7 +3961,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { std::vector> plugin_to_sensors(nplugin); for (int i = 0; i < nsensor; ++i) { if (sensors_[i]->type == mjSENS_PLUGIN) { - int sensor_plugin = static_cast(sensors_[i]->plugin.instance)->id; + int sensor_plugin = static_cast(sensors_[i]->plugin.element)->id; m->sensor_plugin[i] = sensor_plugin; plugin_to_sensors[sensor_plugin].push_back(i); } else { diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 22d00ae2..7d369998 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -959,7 +959,7 @@ void mjCBody::CopyFromSpec() { *static_cast(this) = spec; userdata_ = spec_userdata_; plugin.active = spec.plugin.active; - plugin.instance = spec.plugin.instance; + plugin.element = spec.plugin.element; plugin.name = spec.plugin.name; plugin.instance_name = spec.plugin.instance_name; } @@ -986,7 +986,7 @@ mjCBody::~mjCBody() { lights.clear(); if (spec.plugin.active && spec.plugin.instance_name->empty()) { - model->DeleteElement(spec.plugin.instance); + model->DeleteElement(spec.plugin.element); } } @@ -1669,9 +1669,9 @@ void mjCBody::Compile(void) { name.c_str(), id); } - mjCPlugin* plugin_instance = static_cast(plugin.instance); + mjCPlugin* plugin_instance = static_cast(plugin.element); model->ResolvePlugin(this, plugin_name, plugin_instance_name, &plugin_instance); - plugin.instance = plugin_instance; + plugin.element = plugin_instance; const mjpPlugin* pplugin = mjp_getPluginAtSlot(plugin_instance->spec.plugin_slot); if (!(pplugin->capabilityflags & mjPLUGIN_PASSIVE)) { throw mjCError(this, "plugin '%s' does not support passive forces", pplugin->name); @@ -2132,7 +2132,7 @@ mjCGeom::mjCGeom(const mjCGeom& other) { mjCGeom::~mjCGeom() { if (spec.plugin.active && spec.plugin.instance_name->empty()) { - model->DeleteElement(spec.plugin.instance); + model->DeleteElement(spec.plugin.element); } } @@ -2176,7 +2176,7 @@ void mjCGeom::CopyFromSpec() { meshname_ = spec_meshname_; material_ = spec_material_; plugin.active = spec.plugin.active; - plugin.instance = spec.plugin.instance; + plugin.element = spec.plugin.element; plugin.name = spec.plugin.name; plugin.instance_name = spec.plugin.instance_name; } @@ -2913,9 +2913,9 @@ void mjCGeom::Compile(void) { this, "neither 'plugin' nor 'instance' is specified for geom"); } - mjCPlugin* plugin_instance = static_cast(plugin.instance); + mjCPlugin* plugin_instance = static_cast(plugin.element); model->ResolvePlugin(this, plugin_name, plugin_instance_name, &plugin_instance); - plugin.instance = plugin_instance; + plugin.element = plugin_instance; const mjpPlugin* pplugin = mjp_getPluginAtSlot(plugin_instance->spec.plugin_slot); if (!(pplugin->capabilityflags & mjPLUGIN_SDF)) { throw mjCError(this, "plugin '%s' does not support sign distance fields", pplugin->name); @@ -5554,7 +5554,7 @@ mjCActuator::mjCActuator(const mjCActuator& other) { mjCActuator::~mjCActuator() { if (spec.plugin.active && spec.plugin.instance_name->empty()) { - model->DeleteElement(spec.plugin.instance); + model->DeleteElement(spec.plugin.element); } } @@ -5640,7 +5640,7 @@ void mjCActuator::CopyFromSpec() { refsite_ = spec_refsite_; slidersite_ = spec_slidersite_; plugin.active = spec.plugin.active; - plugin.instance = spec.plugin.instance; + plugin.element = spec.plugin.element; plugin.name = spec.plugin.name; plugin.instance_name = spec.plugin.instance_name; } @@ -5869,9 +5869,9 @@ void mjCActuator::Compile(void) { name.c_str(), id); } - mjCPlugin* plugin_instance = static_cast(plugin.instance); + mjCPlugin* plugin_instance = static_cast(plugin.element); model->ResolvePlugin(this, plugin_name, plugin_instance_name, &plugin_instance); - plugin.instance = plugin_instance; + plugin.element = plugin_instance; const mjpPlugin* pplugin = mjp_getPluginAtSlot(plugin_instance->spec.plugin_slot); if (!(pplugin->capabilityflags & mjPLUGIN_ACTUATOR)) { throw mjCError(this, "plugin '%s' does not support actuators", pplugin->name); @@ -5916,7 +5916,7 @@ mjCSensor::mjCSensor(const mjCSensor& other) { mjCSensor::~mjCSensor() { if (spec.plugin.active && spec.plugin.instance_name->empty()) { - model->DeleteElement(spec.plugin.instance); + model->DeleteElement(spec.plugin.element); } } @@ -5968,7 +5968,7 @@ void mjCSensor::CopyFromSpec() { objname_ = spec_objname_; refname_ = spec_refname_; plugin.active = spec.plugin.active; - plugin.instance = spec.plugin.instance; + plugin.element = spec.plugin.element; plugin.name = spec.plugin.name; plugin.instance_name = spec.plugin.instance_name; } @@ -6373,9 +6373,9 @@ void mjCSensor::Compile(void) { // resolve plugin instance, or create one if using the "plugin" attribute shortcut { - mjCPlugin* plugin_instance = static_cast(plugin.instance); + mjCPlugin* plugin_instance = static_cast(plugin.element); model->ResolvePlugin(this, plugin_name, plugin_instance_name, &plugin_instance); - plugin.instance = plugin_instance; + plugin.element = plugin_instance; const mjpPlugin* pplugin = mjp_getPluginAtSlot(plugin_instance->spec.plugin_slot); if (!(pplugin->capabilityflags & mjPLUGIN_SENSOR)) { throw mjCError(this, "plugin '%s' does not support sensors", pplugin->name); diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index ed6e4339..d5813799 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -2767,7 +2767,7 @@ void mjXReader::OnePlugin(XMLElement* elem, mjsPlugin* plugin) { mjs_setString(plugin->name, name.c_str()); mjs_setString(plugin->instance_name, instance_name.c_str()); if (instance_name.empty()) { - plugin->instance = mjs_addPlugin(spec)->instance; + plugin->element = mjs_addPlugin(spec)->element; ReadPluginConfigs(elem, plugin); } else { spec->hasImplicitPluginElem = true; diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index 92ddd08c..0643e4e9 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -827,8 +827,8 @@ void mjXWriter::OnePlugin(XMLElement* elem, const mjsPlugin* plugin) { } else { WriteAttrTxt(elem, "plugin", plugin_name); const mjpPlugin* pplugin = mjp_getPluginAtSlot( - static_cast(plugin->instance)->spec.plugin_slot); - const char* c = &(static_cast(plugin->instance)->flattened_attributes[0]); + static_cast(plugin->element)->spec.plugin_slot); + const char* c = &(static_cast(plugin->element)->flattened_attributes[0]); for (int i = 0; i < pplugin->nattribute; ++i) { string value(c); if (!value.empty()) { diff --git a/test/user/user_api_test.cc b/test/user/user_api_test.cc index b27f26e2..39811a30 100644 --- a/test/user/user_api_test.cc +++ b/test/user/user_api_test.cc @@ -147,7 +147,7 @@ TEST_F(PluginTest, ActivatePlugin) { // associate plugin to body mjsBody* body = mjs_addBody(mjs_findBody(spec, "world"), 0); mjs_setString(body->plugin.name, plugin_name.c_str()); - body->plugin.instance = mjs_addPlugin(spec)->instance; + body->plugin.element = mjs_addPlugin(spec)->element; body->plugin.active = true; mjsGeom* geom = mjs_addGeom(body, 0); geom->type = mjGEOM_BOX; @@ -191,7 +191,7 @@ TEST_F(PluginTest, DeletePlugin) { mjsActuator* actuator = mjs_addActuator(spec, 0); mjs_setString(actuator->target, "j1"); mjs_setString(actuator->plugin.name, plugin_name.c_str()); - actuator->plugin.instance = mjs_addPlugin(spec)->instance; + actuator->plugin.element = mjs_addPlugin(spec)->element; actuator->plugin.active = true; actuator->trntype = mjTRN_JOINT;