Skip to content

Commit 7d28f3b

Browse files
Synchronize changes from 1.6 branch [ci skip]
2df1c14 Addendum to a9be1ec - it's more complex than it seemed, .. (read below)
2 parents 4425e2f + 2df1c14 commit 7d28f3b

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

Client/game_sa/CModelInfoSA.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1280,11 +1280,15 @@ unsigned int CModelInfoSA::GetNumRemaps()
12801280

12811281
void* CModelInfoSA::GetVehicleSuspensionData()
12821282
{
1283+
if (!GetInterface()->pColModel || !GetInterface()->pColModel->m_data)
1284+
return nullptr;
12831285
return GetInterface()->pColModel->m_data->m_suspensionLines;
12841286
}
12851287

12861288
void* CModelInfoSA::SetVehicleSuspensionData(void* pSuspensionLines)
12871289
{
1290+
if (!GetInterface()->pColModel || !GetInterface()->pColModel->m_data)
1291+
return nullptr;
12881292
CColDataSA* pColData = GetInterface()->pColModel->m_data;
12891293
void* pOrigSuspensionLines = pColData->m_suspensionLines;
12901294
pColData->m_suspensionLines = reinterpret_cast<CColLineSA*>(pSuspensionLines);
@@ -1617,7 +1621,7 @@ void CModelInfoSA::RestoreColModel()
16171621

16181622
// Force the game to load the original collision model data, if we applied a custom collision model before
16191623
// there was any object/building, which would've provoked CColStore to request it.
1620-
if (!m_pInterface->pColModel->m_data && m_dwReferences > 1)
1624+
if (m_pInterface->pColModel && !m_pInterface->pColModel->m_data && m_dwReferences > 1)
16211625
{
16221626
pGame->GetStreaming()->RemoveModel(RESOURCE_ID_COL + m_pInterface->pColModel->m_sphere.m_collisionSlot);
16231627
}

Client/game_sa/CPhysicalSA.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ CRect* CPhysicalSAInterface::GetBoundRect_(CRect* pRect)
2222
{
2323
CVector boundCentre;
2424
CEntitySAInterface::GetBoundCentre(&boundCentre);
25-
float fRadius = CModelInfoSAInterface::GetModelInfo(m_nModelIndex)->pColModel->m_sphere.m_radius;
25+
CBaseModelInfoSAInterface* pModelInfo = CModelInfoSAInterface::GetModelInfo(m_nModelIndex);
26+
27+
if (!pModelInfo || !pModelInfo->pColModel)
28+
return pRect;
29+
30+
float fRadius = pModelInfo->pColModel->m_sphere.m_radius;
2631
*pRect = CRect(boundCentre.fX - fRadius, boundCentre.fY - fRadius, boundCentre.fX + fRadius, boundCentre.fY + fRadius);
27-
pRect->FixIncorrectTopLeft(); // Fix #1613: custom map collision crashes in CPhysical class (infinite loop)
32+
pRect->FixIncorrectTopLeft(); // Fix #1613: custom map collision crashes in CPhysical class (infinite loop)
2833
return pRect;
2934
}
3035

Client/game_sa/CVehicleSA.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,10 +1350,21 @@ CFlyingHandlingEntry* CVehicleSA::GetFlyingHandlingData()
13501350

13511351
void 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

13591370
void 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()
17821809
void 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
}

Client/mods/deathmatch/logic/CClientVehicle.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4305,6 +4305,10 @@ void CClientVehicle::ApplyHandling()
43054305
if (!pModelInfo || !pModelInfo->IsLoaded())
43064306
return;
43074307

4308+
// Ensure collision model is loaded before recalculating (needed for suspension lines)
4309+
if (!pModelInfo->GetInterface()->pColModel || !pModelInfo->GetInterface()->pColModel->m_data)
4310+
return;
4311+
43084312
m_pVehicle->RecalculateHandling();
43094313

43104314
if (m_eVehicleType == CLIENTVEHICLE_BMX || m_eVehicleType == CLIENTVEHICLE_BIKE)

0 commit comments

Comments
 (0)