Skip to content

Commit

Permalink
#5885: fix loss of attached entity offset after Reload Defs
Browse files Browse the repository at this point in the history
To render the entity offset, we are using the localToParent matrix
exposed by the ITransformNode interface. However this matrix was only
being set once, when the attachments were constructed, which isn't
sufficiently "sticky" -- the localToParent matrix can easily be
recalculated by code in the attached entity itself.

We now set the localToParent matrix immediately before rendering each
attached entity, ensuring it is always up to date.
  • Loading branch information
Matthew Mott committed Feb 2, 2022
1 parent 0ffea8f commit 90958ed
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 8 deletions.
8 changes: 4 additions & 4 deletions radiantcore/entity/EntityNode.cpp
Expand Up @@ -137,7 +137,7 @@ void EntityNode::createAttachedEntities()
// Construct and store the attached entity
auto attachedEnt = GlobalEntityModule().createEntity(cls);
assert(attachedEnt);
_attachedEnts.push_back(attachedEnt);
_attachedEnts.push_back({attachedEnt, a.offset});

// Set ourselves as the parent of the attached entity (for
// localToParent transforms)
Expand All @@ -156,8 +156,8 @@ void EntityNode::transformChanged()

// Broadcast transformChanged to all attached entities so they can update
// their position
for (auto attached: _attachedEnts)
attached->transformChanged();
for (auto [node, offset]: _attachedEnts)
node->transformChanged();
}

void EntityNode::onEntityClassChanged()
Expand Down Expand Up @@ -395,7 +395,7 @@ void EntityNode::setRenderSystem(const RenderSystemPtr& renderSystem)
_colourKey.setRenderSystem(renderSystem);

// Make sure any attached entities have a render system too
for (IEntityNodePtr node: _attachedEnts)
for (auto [node, offset]: _attachedEnts)
node->setRenderSystem(renderSystem);
}

Expand Down
11 changes: 7 additions & 4 deletions radiantcore/entity/EntityNode.h
Expand Up @@ -87,7 +87,8 @@ class EntityNode :
// sure that everything will play nicely with entities as children of other
// entities, and (2) storing entity node pointers instead of generic node
// pointers avoids some extra dynamic_casting.
using AttachedEntities = std::list<IEntityNodePtr>;
using AttachedEntity = std::pair<IEntityNodePtr, Vector3 /* offset */>;
using AttachedEntities = std::list<AttachedEntity>;
AttachedEntities _attachedEnts;

protected:
Expand Down Expand Up @@ -198,8 +199,11 @@ class EntityNode :
// Render all attached entities
template <typename RenderFunc> void renderAttachments(RenderFunc func) const
{
for (const IEntityNodePtr& ent: _attachedEnts)
for (auto [entityNode, offset]: _attachedEnts)
{
// Before rendering the attached entity, ensure its offset is correct
entityNode->setLocalToParent(Matrix4::getTranslation(offset));

// Attached entities might themselves have child nodes (e.g. func_static
// which has its model as a child node), so we must traverse() the
// attached entities, not just render them alone
Expand All @@ -215,9 +219,8 @@ class EntityNode :
return true;
}
};

ChildRenderer cr(func);
ent->traverse(cr);
entityNode->traverse(cr);
}
}

Expand Down

0 comments on commit 90958ed

Please sign in to comment.