@@ -1350,10 +1350,21 @@ CFlyingHandlingEntry* CVehicleSA::GetFlyingHandlingData()
13501350
13511351void CVehicleSA::SetHandlingData (CHandlingEntry* pHandling)
13521352{
1353+ if (!pHandling)
1354+ return ;
1355+
1356+ CVehicleSAInterface* pVehicleInterface = GetVehicleInterface ();
1357+ if (!pVehicleInterface)
1358+ return ;
1359+
13531360 // Store the handling and recalculate it
13541361 m_pHandlingData = static_cast <CHandlingEntrySA*>(pHandling);
1355- GetVehicleInterface ()->pHandlingData = m_pHandlingData->GetInterface ();
1356- RecalculateHandling ();
1362+ pVehicleInterface->pHandlingData = m_pHandlingData->GetInterface ();
1363+
1364+ // Only recalculate if collision model is loaded (needed for suspension lines)
1365+ CModelInfo* pModelInfo = pGame->GetModelInfo (GetModelIndex ());
1366+ if (pModelInfo && pModelInfo->GetInterface ()->pColModel && pModelInfo->GetInterface ()->pColModel ->m_data )
1367+ RecalculateHandling ();
13571368}
13581369
13591370void CVehicleSA::SetFlyingHandlingData (CFlyingHandlingEntry* pFlyingHandling)
@@ -1369,13 +1380,24 @@ void CVehicleSA::RecalculateHandling()
13691380 if (!m_pHandlingData)
13701381 return ;
13711382
1383+ // Validate vehicle interface
1384+ CVehicleSAInterface* pInt = GetVehicleInterface ();
1385+ if (!pInt)
1386+ return ;
1387+
1388+ // Ensure collision model is loaded before recalculating (needed for suspension lines)
1389+ CModelInfo* pModelInfo = pGame->GetModelInfo (GetModelIndex ());
1390+ if (!pModelInfo || !pModelInfo->GetInterface ()->pColModel || !pModelInfo->GetInterface ()->pColModel ->m_data )
1391+ return ;
1392+
13721393 m_pHandlingData->Recalculate ();
13731394
1374- // Recalculate the suspension lines
1375- RecalculateSuspensionLines ();
1395+ // Recalculate the suspension lines (only for vehicles that have suspension)
1396+ // Already validated that pColModel and m_data exist above
1397+ if (pModelInfo->IsCar () || pModelInfo->IsMonsterTruck () || pModelInfo->IsTrailer () || pModelInfo->IsBike ())
1398+ RecalculateSuspensionLines ();
13761399
13771400 // Put it in our interface
1378- CVehicleSAInterface* pInt = GetVehicleInterface ();
13791401 unsigned int uiHandlingFlags = m_pHandlingData->GetInterface ()->uiHandlingFlags ;
13801402 bool hydralicsInstalled = false , nitroInstalled = false ;
13811403
@@ -1758,6 +1780,11 @@ void* CVehicleSA::GetPrivateSuspensionLines()
17581780 if (m_pSuspensionLines == NULL )
17591781 {
17601782 CModelInfo* pModelInfo = pGame->GetModelInfo (GetModelIndex ());
1783+ // pColModel can be NULL if collision data hasn't been streamed in yet.
1784+ // GTA SA loads visual models and collision models separately via CColStore.
1785+ // The model can be marked as "loaded" even if collision data is still pending.
1786+ if (!pModelInfo->GetInterface ()->pColModel || !pModelInfo->GetInterface ()->pColModel ->m_data )
1787+ return NULL ;
17611788 CColDataSA* pColData = pModelInfo->GetInterface ()->pColModel ->m_data ;
17621789 if (pModelInfo->IsMonsterTruck ())
17631790 {
@@ -1782,6 +1809,9 @@ void* CVehicleSA::GetPrivateSuspensionLines()
17821809void CVehicleSA::CopyGlobalSuspensionLinesToPrivate ()
17831810{
17841811 CModelInfo* pModelInfo = pGame->GetModelInfo (GetModelIndex ());
1812+ // Collision model may not be loaded yet (see GetPrivateSuspensionLines)
1813+ if (!pModelInfo->GetInterface ()->pColModel || !pModelInfo->GetInterface ()->pColModel ->m_data )
1814+ return ;
17851815 CColDataSA* pColData = pModelInfo->GetInterface ()->pColModel ->m_data ;
17861816 if (pModelInfo->IsMonsterTruck ())
17871817 {
@@ -1815,8 +1845,14 @@ void CVehicleSA::RecalculateSuspensionLines()
18151845 if (pModelInfo->IsTrain () || dwModel == 571 || dwModel == 570 || dwModel == 569 || dwModel == 590 )
18161846 return ;
18171847
1818- GetVehicleInterface ()->SetupSuspensionLines ();
1848+ // Ensure collision model is loaded before setting up suspension
1849+ if (!pModelInfo->GetInterface ()->pColModel || !pModelInfo->GetInterface ()->pColModel ->m_data )
1850+ return ;
18191851
1852+ // Note: We skip calling SetupSuspensionLines() because it's GTA SA's native code that can
1853+ // access pColModel->m_data without validation. If collision model is unloaded during execution
1854+ // (race condition), it causes crashes. CopyGlobalSuspensionLinesToPrivate() is safer as it
1855+ // validates collision model before accessing.
18201856 CopyGlobalSuspensionLinesToPrivate ();
18211857 }
18221858}
0 commit comments