From fd9c0fadd567e7ca62346afdc3ffca1d0bc9d190 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 7 Dec 2025 00:17:51 +0100 Subject: [PATCH] fix(tunnel): Fix crashing in TunnelTracker::onTunnelDestroyed and incomplete asset transfer in Team::setControllingPlayer --- .../Code/GameEngine/Source/Common/RTS/Team.cpp | 11 ++++++++++- .../Source/Common/RTS/TunnelTracker.cpp | 15 ++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Team.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Team.cpp index 701debf163..aadcc0da93 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Team.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Team.cpp @@ -1391,6 +1391,7 @@ Player *Team::getControllingPlayer() const // ------------------------------------------------------------------------ void Team::setControllingPlayer(Player *newController) { + Player* oldOwner = m_proto->getControllingPlayer(); // NULL is not allowed, but is caught by TeamPrototype::setControllingPlayer() m_proto->setControllingPlayer(newController); @@ -1399,6 +1400,7 @@ void Team::setControllingPlayer(Player *newController) // The Team doesn't change, it just starts to return a different answer when you ask for // the controlling player. I don't want to make the major change of onCapture on everyone, // so I will do the minor fix for the specific bug, which is harmless even when misused. + // TheSuperHackers @fix xezon 07/12/2025 Now does onCapture on everyone. // Tell all members to redo their looking status, as their Player has changed, but they don't know. for (DLINK_ITERATOR iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) @@ -1407,7 +1409,14 @@ void Team::setControllingPlayer(Player *newController) if (!obj) continue; - obj->handlePartitionCellMaintenance(); + if constexpr (RETAIL_COMPATIBLE_CRC) // Not sure if necessary. But likely is. + { + obj->handlePartitionCellMaintenance(); + } + else + { + obj->onCapture(oldOwner, newController); + } } } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp index 55bc3f6671..f193a4f7c5 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp @@ -220,9 +220,18 @@ void TunnelTracker::onTunnelCreated( const Object *newTunnel ) // ------------------------------------------------------------------------ void TunnelTracker::onTunnelDestroyed( const Object *deadTunnel ) { - m_tunnelCount--; - m_tunnelIDs.remove( deadTunnel->getID() ); - m_needsFullHealTimeUpdate = true; + { + std::list::iterator it = std::find(m_tunnelIDs.begin(), m_tunnelIDs.end(), deadTunnel->getID()); + if (it == m_tunnelIDs.end()) + { + DEBUG_CRASH(("TunnelTracker::onTunnelDestroyed - Attempting to remove object '%s' that has never been tracked as a tunnel", deadTunnel->getName().str())); + return; + } + + m_tunnelCount--; + m_tunnelIDs.erase(it); + m_needsFullHealTimeUpdate = true; + } if( m_tunnelCount == 0 ) {