mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 02:23:56 +00:00
Fix use-after-free crash in ScenePlayer when remote player disconnects mid-animation
When a remote player's ROI is destroyed (disconnect, timeout, or respawn), notify all active ScenePlayer instances to null out dangling references before the ROI is freed. The animation engine already handles null ROI map entries gracefully, so playback continues for remaining participants.
This commit is contained in:
parent
11bf290396
commit
3cf1a38600
@ -30,6 +30,7 @@ class PhonemePlayer {
|
|||||||
);
|
);
|
||||||
void Tick(float p_elapsedMs, const std::vector<SceneAnimData::PhonemeTrack>& p_tracks);
|
void Tick(float p_elapsedMs, const std::vector<SceneAnimData::PhonemeTrack>& p_tracks);
|
||||||
void Cleanup();
|
void Cleanup();
|
||||||
|
void NotifyROIDestroyed(LegoROI* p_roi);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<PhonemeState> m_states;
|
std::vector<PhonemeState> m_states;
|
||||||
|
|||||||
@ -45,6 +45,7 @@ class ScenePlayer {
|
|||||||
);
|
);
|
||||||
void Tick();
|
void Tick();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
void NotifyROIDestroyed(LegoROI* p_roi);
|
||||||
bool IsPlaying() const { return m_playing; }
|
bool IsPlaying() const { return m_playing; }
|
||||||
bool IsObserverMode() const { return m_observerMode; }
|
bool IsObserverMode() const { return m_observerMode; }
|
||||||
|
|
||||||
|
|||||||
@ -222,6 +222,7 @@ class NetworkManager : public MxCore {
|
|||||||
void TickAnimation();
|
void TickAnimation();
|
||||||
void StopScenePlayback(uint16_t p_animIndex, bool p_unlockRemotes);
|
void StopScenePlayback(uint16_t p_animIndex, bool p_unlockRemotes);
|
||||||
void StopAllPlayback();
|
void StopAllPlayback();
|
||||||
|
void NotifyAnimationsROIDestroyed(RemotePlayer* p_player);
|
||||||
void UnlockRemotesForAnim(uint16_t p_animIndex);
|
void UnlockRemotesForAnim(uint16_t p_animIndex);
|
||||||
|
|
||||||
// Horn sound synchronization
|
// Horn sound synchronization
|
||||||
|
|||||||
@ -188,6 +188,15 @@ void PhonemePlayer::Tick(float p_elapsedMs, const std::vector<SceneAnimData::Pho
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhonemePlayer::NotifyROIDestroyed(LegoROI* p_roi)
|
||||||
|
{
|
||||||
|
for (auto& state : m_states) {
|
||||||
|
if (state.targetROI == p_roi) {
|
||||||
|
state.targetROI = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PhonemePlayer::Cleanup()
|
void PhonemePlayer::Cleanup()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_states.size(); i++) {
|
for (size_t i = 0; i < m_states.size(); i++) {
|
||||||
|
|||||||
@ -567,9 +567,11 @@ void ScenePlayer::Stop()
|
|||||||
m_roiMapSize = 0;
|
m_roiMapSize = 0;
|
||||||
|
|
||||||
for (auto& p : m_participants) {
|
for (auto& p : m_participants) {
|
||||||
|
if (p.roi) {
|
||||||
p.roi->WrappedSetLocal2WorldWithWorldDataUpdate(p.savedTransform);
|
p.roi->WrappedSetLocal2WorldWithWorldDataUpdate(p.savedTransform);
|
||||||
p.roi->SetVisibility(TRUE);
|
p.roi->SetVisibility(TRUE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
m_participants.clear();
|
m_participants.clear();
|
||||||
|
|
||||||
BackgroundAudioManager()->RaiseVolume();
|
BackgroundAudioManager()->RaiseVolume();
|
||||||
@ -586,6 +588,46 @@ void ScenePlayer::Stop()
|
|||||||
m_hideOnStop = false;
|
m_hideOnStop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScenePlayer::NotifyROIDestroyed(LegoROI* p_roi)
|
||||||
|
{
|
||||||
|
if (!m_playing || !p_roi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& p : m_participants) {
|
||||||
|
if (p.roi == p_roi) {
|
||||||
|
p.roi = nullptr;
|
||||||
|
}
|
||||||
|
if (p.vehicleROI == p_roi) {
|
||||||
|
p.vehicleROI = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_roiMap) {
|
||||||
|
for (MxU32 i = 0; i < m_roiMapSize; i++) {
|
||||||
|
if (m_roiMap[i] == p_roi) {
|
||||||
|
m_roiMap[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& roi : m_ptAtCamROIs) {
|
||||||
|
if (roi == p_roi) {
|
||||||
|
roi = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_animRootROI == p_roi) {
|
||||||
|
m_animRootROI = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_vehicleROI == p_roi) {
|
||||||
|
m_vehicleROI = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_phonemePlayer.NotifyROIDestroyed(p_roi);
|
||||||
|
}
|
||||||
|
|
||||||
void ScenePlayer::CleanupProps()
|
void ScenePlayer::CleanupProps()
|
||||||
{
|
{
|
||||||
for (auto* propROI : m_propROIs) {
|
for (auto* propROI : m_propROIs) {
|
||||||
|
|||||||
@ -1029,6 +1029,7 @@ void NetworkManager::HandleState(const PlayerStateMsg& p_msg)
|
|||||||
|
|
||||||
// Respawn only if display actor changed (not on actorId change)
|
// Respawn only if display actor changed (not on actorId change)
|
||||||
if (it->second->GetDisplayActorIndex() != p_msg.displayActorIndex) {
|
if (it->second->GetDisplayActorIndex() != p_msg.displayActorIndex) {
|
||||||
|
NotifyAnimationsROIDestroyed(it->second.get());
|
||||||
if (it->second->GetROI()) {
|
if (it->second->GetROI()) {
|
||||||
m_roiToPlayer.erase(it->second->GetROI());
|
m_roiToPlayer.erase(it->second->GetROI());
|
||||||
}
|
}
|
||||||
@ -1261,6 +1262,7 @@ void NetworkManager::RemoveRemotePlayer(uint32_t p_peerId)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NotifyAnimationsROIDestroyed(it->second.get());
|
||||||
if (it->second->GetROI()) {
|
if (it->second->GetROI()) {
|
||||||
m_roiToPlayer.erase(it->second->GetROI());
|
m_roiToPlayer.erase(it->second->GetROI());
|
||||||
}
|
}
|
||||||
@ -1280,6 +1282,7 @@ void NetworkManager::RemoveRemotePlayer(uint32_t p_peerId)
|
|||||||
void NetworkManager::RemoveAllRemotePlayers()
|
void NetworkManager::RemoveAllRemotePlayers()
|
||||||
{
|
{
|
||||||
for (auto& [peerId, player] : m_remotePlayers) {
|
for (auto& [peerId, player] : m_remotePlayers) {
|
||||||
|
NotifyAnimationsROIDestroyed(player.get());
|
||||||
player->Despawn();
|
player->Despawn();
|
||||||
}
|
}
|
||||||
m_remotePlayers.clear();
|
m_remotePlayers.clear();
|
||||||
@ -1428,6 +1431,21 @@ void NetworkManager::StopAllPlayback()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkManager::NotifyAnimationsROIDestroyed(RemotePlayer* p_player)
|
||||||
|
{
|
||||||
|
LegoROI* roi = p_player->GetROI();
|
||||||
|
LegoROI* vehicleROI = p_player->GetRideVehicleROI();
|
||||||
|
|
||||||
|
for (auto& [animIndex, scenePlayer] : m_playingAnims) {
|
||||||
|
if (roi) {
|
||||||
|
scenePlayer->NotifyROIDestroyed(roi);
|
||||||
|
}
|
||||||
|
if (vehicleROI) {
|
||||||
|
scenePlayer->NotifyROIDestroyed(vehicleROI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkManager::UnlockRemotesForAnim(uint16_t p_animIndex)
|
void NetworkManager::UnlockRemotesForAnim(uint16_t p_animIndex)
|
||||||
{
|
{
|
||||||
for (auto& [peerId, player] : m_remotePlayers) {
|
for (auto& [peerId, player] : m_remotePlayers) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user