From 5eaaef20a025836b897cf16e902970e49f513941 Mon Sep 17 00:00:00 2001 From: darknight0847 Date: Sat, 8 Nov 2025 14:26:09 +0530 Subject: [PATCH] fix(user): Make skin and bone compatible with attachImplements ResolveReferences for mjCSkin and adds prefixingin mjCModel::operator+= to ensure skin bone body names arecorrectly updated when a model is attached.This prevents an 'unknown body' error during compilationof an attached model.Fixes #2923 --- src/user/user_model.cc | 14 ++++++++++++++ src/user/user_objects.cc | 23 ++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/user/user_model.cc b/src/user/user_model.cc index ad7af6ddcf..75da5ed2df 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -447,7 +447,20 @@ mjCModel& mjCModel::operator+=(const mjCModel& other) { // do not copy assets for self-attach // TODO: asset should be copied only when referenced CopyList(meshes_, other.meshes_); + int old_nskin = skins_.size(); CopyList(skins_, other.skins_); + int new_nskin = skins_.size(); + + // Iterate ONLY over the newly added skins + for (int i = old_nskin; i < new_nskin; ++i) { + mjCSkin* skin = skins_[i]; + for (std::string& bodyname : skin->bodyname_) { + if (!bodyname.empty()) { + bodyname = prefix + bodyname; + } + } + } + CopyList(hfields_, other.hfields_); CopyList(textures_, other.textures_); CopyList(materials_, other.materials_); @@ -1921,6 +1934,7 @@ void mjCModel::IndexAssets(bool discard) { throw mjCError(skin, "material '%s' not found in skin %d", skin->material_.c_str(), i); } } + skin->ResolveReferences(this); } // materials referenced in sites diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 758783e4d5..a582cf260f 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -2598,7 +2598,28 @@ void mjCBody::Compile(void) { } - +// skin attach issue fix--------- +void mjCSkin::ResolveReferences(const mjCModel* m) { + // Resize the bodyid list to match the bodyname list + bodyid.resize(bodyname_.size()); + + for (int i = 0; i < bodyname_.size(); ++i) { + if (!bodyname_[i].empty()) { + // Find the body object using the (now prefixed) name + mjCBody* b = (mjCBody*)m->FindObject(mjOBJ_BODY, bodyname_[i]); + if (b) { + // Success! Store the numerical ID. + bodyid[i] = b->id; + } else { + // This is the error we are fixing! + throw mjCError(this, "unknown body '%s' in skin", bodyname_[i].c_str()); + } + } else { + // This bone doesn't reference a body. + bodyid[i] = -1; + } + } +} //------------------ class mjCFrame implementation ------------------------------------------------- // initialize frame