Skip to content

Commit c0440e8

Browse files
committed
Fix recently introduced suspension bug
1 parent 895be40 commit c0440e8

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

Client/game_sa/CVehicleSA.cpp

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,11 +1360,8 @@ void CVehicleSA::SetHandlingData(CHandlingEntry* pHandling)
13601360
// Store the handling and recalculate it
13611361
m_pHandlingData = static_cast<CHandlingEntrySA*>(pHandling);
13621362
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();
1363+
1364+
RecalculateHandling();
13681365
}
13691366

13701367
void CVehicleSA::SetFlyingHandlingData(CFlyingHandlingEntry* pFlyingHandling)
@@ -1385,16 +1382,18 @@ void CVehicleSA::RecalculateHandling()
13851382
if (!pInt)
13861383
return;
13871384

1388-
// Ensure collision model is loaded before recalculating (needed for suspension lines)
13891385
CModelInfo* pModelInfo = pGame->GetModelInfo(GetModelIndex());
1390-
if (!pModelInfo || !pModelInfo->GetInterface()->pColModel || !pModelInfo->GetInterface()->pColModel->m_data)
1391-
return;
1386+
auto* pModelInterface = pModelInfo ? pModelInfo->GetInterface() : nullptr;
1387+
auto* pColModelInterface = pModelInterface ? pModelInterface->pColModel : nullptr;
1388+
bool bSuspensionDataReady = pColModelInterface && pColModelInterface->m_data;
1389+
bool bHasSuspension = pModelInfo &&
1390+
(pModelInfo->IsCar() || pModelInfo->IsMonsterTruck() || pModelInfo->IsTrailer() || pModelInfo->IsBike());
13921391

13931392
m_pHandlingData->Recalculate();
13941393

13951394
// 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())
1395+
// Skip until collision data streams in to avoid accessing null suspension lines
1396+
if (bSuspensionDataReady && bHasSuspension)
13981397
RecalculateSuspensionLines();
13991398

14001399
// Put it in our interface
@@ -1846,13 +1845,30 @@ void CVehicleSA::RecalculateSuspensionLines()
18461845
return;
18471846

18481847
// Ensure collision model is loaded before setting up suspension
1849-
if (!pModelInfo->GetInterface()->pColModel || !pModelInfo->GetInterface()->pColModel->m_data)
1848+
auto* pColModelInterface = pModelInfo->GetInterface()->pColModel;
1849+
if (!pColModelInterface || !pColModelInterface->m_data)
18501850
return;
18511851

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.
1852+
struct ScopedModelRef
1853+
{
1854+
explicit ScopedModelRef(CModelInfo* model)
1855+
: m_Model(model)
1856+
{
1857+
if (m_Model)
1858+
m_Model->ModelAddRef(EModelRequestType::BLOCKING, "CVehicleSA::RecalculateSuspensionLines");
1859+
}
1860+
1861+
~ScopedModelRef()
1862+
{
1863+
if (m_Model)
1864+
m_Model->RemoveRef();
1865+
}
1866+
1867+
CModelInfo* m_Model;
1868+
} modelRef(pModelInfo);
1869+
1870+
GetVehicleInterface()->SetupSuspensionLines();
1871+
18561872
CopyGlobalSuspensionLinesToPrivate();
18571873
}
18581874
}

0 commit comments

Comments
 (0)