@@ -210,8 +210,105 @@ void DetachableJoint::Configure(const Entity &_entity,
210210 .first ;
211211
212212 this ->validConfig = true ;
213+
214+ this ->GetChildModelAndLinkEntities (_ecm);
213215}
214216
217+ // ////////////////////////////////////////////////
218+ void DetachableJoint::GetChildModelAndLinkEntities (
219+ EntityComponentManager &_ecm)
220+ {
221+ this ->childLinkEntity = kNullEntity ;
222+ // Look for the child model and link
223+ Entity modelEntity{kNullEntity };
224+
225+ if (" __model__" == this ->childModelName )
226+ {
227+ modelEntity = this ->model .Entity ();
228+ }
229+ else
230+ {
231+ auto entitiesMatchingName = entitiesFromScopedName (
232+ this ->childModelName , _ecm);
233+
234+ // TODO(arjoc): There is probably a more efficient way
235+ // of combining entitiesFromScopedName
236+ // With filtering.
237+ // Filter for entities with only models
238+ std::vector<Entity> candidateEntities;
239+ std::copy_if (entitiesMatchingName.begin (), entitiesMatchingName.end (),
240+ std::back_inserter (candidateEntities),
241+ [&_ecm](Entity e) {
242+ return _ecm.EntityHasComponentType (e,
243+ components::Model::typeId);
244+ });
245+
246+ if (candidateEntities.size () == 1 )
247+ {
248+ // If there is one entity select that entity itself
249+ modelEntity = *candidateEntities.begin ();
250+ }
251+ else
252+ {
253+ std::string selectedModelName;
254+ auto parentEntityScopedPath = scopedName (this ->model .Entity (), _ecm);
255+ // If there is more than one model with the given child model name,
256+ // the plugin looks for a model which is
257+ // - a descendant of the plugin's parent model with that name, and
258+ // - has a child link with the given child link name
259+ for (auto entity : candidateEntities)
260+ {
261+ auto childEntityScope = scopedName (entity, _ecm);
262+ if (childEntityScope.size () < parentEntityScopedPath.size ())
263+ {
264+ continue ;
265+ }
266+ if (childEntityScope.rfind (parentEntityScopedPath, 0 ) != 0 )
267+ {
268+ continue ;
269+ }
270+ if (modelEntity == kNullEntity )
271+ {
272+
273+ this ->childLinkEntity = _ecm.EntityByComponents (
274+ components::Link (), components::ParentEntity (entity),
275+ components::Name (this ->childLinkName ));
276+
277+ if (kNullEntity != this ->childLinkEntity )
278+ {
279+ // Only select this child model entity if the entity
280+ // has a link with the given child link name
281+ modelEntity = entity;
282+ selectedModelName = childEntityScope;
283+ gzdbg << " Selecting " << childEntityScope
284+ << " as model to be detached" << std::endl;
285+ }
286+ else
287+ {
288+ gzwarn << " Found " << childEntityScope
289+ << " with no link named " << this ->childLinkName << std::endl;
290+ }
291+ }
292+ else
293+ {
294+ gzwarn << " Found multiple models skipping " << childEntityScope
295+ << " Using " << selectedModelName << " instead" << std::endl;
296+ }
297+ }
298+ }
299+ }
300+ if (kNullEntity != modelEntity)
301+ {
302+ this ->childLinkEntity = _ecm.EntityByComponents (
303+ components::Link (), components::ParentEntity (modelEntity),
304+ components::Name (this ->childLinkName ));
305+ }
306+ else if (!this ->suppressChildWarning )
307+ {
308+ gzwarn << " Child Model " << this ->childModelName
309+ << " could not be found.\n " ;
310+ }
311+ }
215312// ////////////////////////////////////////////////
216313void DetachableJoint::PreUpdate (
217314 const UpdateInfo &/* _info*/ ,
@@ -225,54 +322,36 @@ void DetachableJoint::PreUpdate(
225322 if (!this ->attachRequested ){
226323 return ;
227324 }
228- // Look for the child model and link
229- Entity modelEntity{kNullEntity };
230325
231- if (" __model__" == this ->childModelName )
326+ if (this ->childLinkEntity == kNullEntity ||
327+ !_ecm.HasEntity (this ->childLinkEntity ))
328+ this ->GetChildModelAndLinkEntities (_ecm);
329+
330+ if (kNullEntity != this ->childLinkEntity )
232331 {
233- modelEntity = this ->model .Entity ();
332+ // Attach the models
333+ // We do this by creating a detachable joint entity.
334+ this ->detachableJointEntity = _ecm.CreateEntity ();
335+
336+ _ecm.CreateComponent (
337+ this ->detachableJointEntity ,
338+ components::DetachableJoint ({this ->parentLinkEntity ,
339+ this ->childLinkEntity , " fixed" }));
340+ this ->attachRequested = false ;
341+ this ->isAttached = true ;
342+ this ->PublishJointState (this ->isAttached );
343+ gzdbg << " Attaching entity: " << this ->detachableJointEntity
344+ << std::endl;
234345 }
235346 else
236347 {
237- modelEntity = _ecm.EntityByComponents (
238- components::Model (), components::Name (this ->childModelName ));
239- }
240- if (kNullEntity != modelEntity)
241- {
242- this ->childLinkEntity = _ecm.EntityByComponents (
243- components::Link (), components::ParentEntity (modelEntity),
244- components::Name (this ->childLinkName ));
245-
246- if (kNullEntity != this ->childLinkEntity )
247- {
248- // Attach the models
249- // We do this by creating a detachable joint entity.
250- this ->detachableJointEntity = _ecm.CreateEntity ();
251-
252- _ecm.CreateComponent (
253- this ->detachableJointEntity ,
254- components::DetachableJoint ({this ->parentLinkEntity ,
255- this ->childLinkEntity , " fixed" }));
256- this ->attachRequested = false ;
257- this ->isAttached = true ;
258- this ->PublishJointState (this ->isAttached );
259- gzdbg << " Attaching entity: " << this ->detachableJointEntity
260- << std::endl;
261- }
262- else
263- {
264- gzwarn << " Child Link " << this ->childLinkName
265- << " could not be found.\n " ;
266- }
267- }
268- else if (!this ->suppressChildWarning )
269- {
270- gzwarn << " Child Model " << this ->childModelName
348+ gzwarn << " Child Link " << this ->childLinkName
271349 << " could not be found.\n " ;
272350 }
351+
273352 }
274353
275- // only allow detaching if child entity is attached
354+ // only allow detaching if child entity is attached
276355 if (this ->isAttached )
277356 {
278357 if (this ->detachRequested && (kNullEntity != this ->detachableJointEntity ))
0 commit comments