Fix crash when performer's child ROIs are left dangling in ScenePlayer

NotifyROIDestroyed now walks the parent chain to also invalidate child
ROIs of the destroyed performer (head, limbs, etc.) that were placed
into the roiMap by BuildROIMap. The ancestor walk happens once; all
other fields are cleaned with simple pointer equality.
This commit is contained in:
Christian Semmler 2026-04-03 20:42:41 -07:00
parent 3cf1a38600
commit ac4cd6b979
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C

View File

@ -594,38 +594,66 @@ void ScenePlayer::NotifyROIDestroyed(LegoROI* p_roi)
return; return;
} }
for (auto& p : m_participants) { // Walk the m_roiMap once to find p_roi and all its descendants (child ROIs
if (p.roi == p_roi) { // are destroyed together with their parent). Collect them so every other
p.roi = nullptr; // field can be cleaned with simple pointer equality — the ancestor walk
} // happens in exactly one place.
if (p.vehicleROI == p_roi) { std::vector<LegoROI*> destroyed;
p.vehicleROI = nullptr; destroyed.push_back(p_roi);
}
}
if (m_roiMap) { if (m_roiMap) {
for (MxU32 i = 0; i < m_roiMapSize; i++) { for (MxU32 i = 0; i < m_roiMapSize; i++) {
if (m_roiMap[i] == p_roi) { if (!m_roiMap[i]) {
m_roiMap[i] = nullptr; continue;
}
for (OrientableROI* cur = m_roiMap[i]; cur != nullptr; cur = cur->GetParentROI()) {
if (cur == p_roi) {
if (m_roiMap[i] != p_roi) {
destroyed.push_back(m_roiMap[i]);
}
m_roiMap[i] = nullptr;
break;
}
} }
} }
} }
auto isDestroyed = [&destroyed](LegoROI* roi) {
for (LegoROI* d : destroyed) {
if (roi == d) {
return true;
}
}
return false;
};
for (auto& p : m_participants) {
if (p.roi && isDestroyed(p.roi)) {
p.roi = nullptr;
}
if (p.vehicleROI && isDestroyed(p.vehicleROI)) {
p.vehicleROI = nullptr;
}
}
for (auto& roi : m_ptAtCamROIs) { for (auto& roi : m_ptAtCamROIs) {
if (roi == p_roi) { if (roi && isDestroyed(roi)) {
roi = nullptr; roi = nullptr;
} }
} }
if (m_animRootROI == p_roi) { if (m_animRootROI && isDestroyed(m_animRootROI)) {
m_animRootROI = nullptr; m_animRootROI = nullptr;
} }
if (m_vehicleROI == p_roi) { if (m_vehicleROI && isDestroyed(m_vehicleROI)) {
m_vehicleROI = nullptr; m_vehicleROI = nullptr;
} }
m_phonemePlayer.NotifyROIDestroyed(p_roi); for (LegoROI* d : destroyed) {
m_phonemePlayer.NotifyROIDestroyed(d);
}
} }
void ScenePlayer::CleanupProps() void ScenePlayer::CleanupProps()