Skip to content

Commit adfbd69

Browse files
committed
Add crash fix for train rail distance wrapping
1 parent 679a6a2 commit adfbd69

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

Client/multiplayer_sa/CMultiplayerSA_CrashFixHacks.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,74 @@ void _declspec(naked) HOOK_CStreaming_AreAnimsUsedByRequestedModels()
15631563
}
15641564
}
15651565

1566+
//////////////////////////////////////////////////////////////////////////////////////////
1567+
//
1568+
// CTrain::ProcessControl
1569+
//
1570+
// This hook overwrites the logic to wrap the train's rail distance, because in the
1571+
// original game code this could cause an infinite loop
1572+
//
1573+
//////////////////////////////////////////////////////////////////////////////////////////
1574+
// 0x6F8F83 | 88 9E CA 05 00 00 | mov [esi + 5CAh], bl
1575+
// >>> 0x6F8F89 | D9 86 A8 05 00 00 | fld dword ptr [esi + 5A8h]
1576+
// 0x6F8F8F | D8 1D 50 8B 85 00 | fcomp ds: __real @00000000
1577+
#define HOOKPOS_CTrain__ProcessControl 0x6F8F89
1578+
#define HOOKSIZE_CTrain__ProcessControl 6
1579+
static DWORD CONTINUE_CTrain__ProcessControl = 0x6F8FE5;
1580+
1581+
// 0xC37FEC; float RailTrackLength[NUM_TRACKS]
1582+
static float* RailTrackLength = reinterpret_cast<float*>(0xC37FEC);
1583+
1584+
static void _cdecl WrapTrainRailDistance(CVehicleSAInterface* train)
1585+
{
1586+
// Check if the train is driving on a valid rail track (id < NUM_TRACKS)
1587+
if (train->m_ucRailTrackID >= 4)
1588+
{
1589+
train->m_fTrainRailDistance = 0.0f;
1590+
return;
1591+
}
1592+
1593+
// Check if the current rail track has a valid length (>= 1.0f)
1594+
const float railTrackLength = RailTrackLength[train->m_ucRailTrackID];
1595+
1596+
if (railTrackLength < 1.0f)
1597+
{
1598+
train->m_fTrainRailDistance = 0.0f;
1599+
return;
1600+
}
1601+
1602+
// Check if the current rail distance is in the interval [0, railTrackLength)
1603+
float railDistance = train->m_fTrainRailDistance;
1604+
1605+
if (railDistance >= 0.0f && railDistance < railTrackLength)
1606+
return;
1607+
1608+
// Wrap the current rail distance
1609+
if (railDistance > 0.0f)
1610+
{
1611+
railDistance = std::fmodf(railDistance, railTrackLength);
1612+
}
1613+
else
1614+
{
1615+
railDistance = railTrackLength - std::fmodf(std::fabsf(railDistance), railTrackLength);
1616+
}
1617+
1618+
train->m_fTrainRailDistance = railDistance;
1619+
}
1620+
1621+
static void _declspec(naked) HOOK_CTrain__ProcessControl()
1622+
{
1623+
_asm
1624+
{
1625+
pushad
1626+
push esi // CVehicleSAInterface*
1627+
call WrapTrainRailDistance
1628+
add esp, 4
1629+
popad
1630+
jmp CONTINUE_CTrain__ProcessControl
1631+
}
1632+
}
1633+
15661634
//////////////////////////////////////////////////////////////////////////////////////////
15671635
//
15681636
// Setup hooks for CrashFixHacks
@@ -1612,6 +1680,7 @@ void CMultiplayerSA::InitHooks_CrashFixHacks()
16121680
EZHookInstall(CTaskComplexCarSlowBeDraggedOut_CreateFirstSubTask);
16131681
EZHookInstallChecked(printf);
16141682
EZHookInstallChecked(RwMatrixMultiply);
1683+
EZHookInstall(CTrain__ProcessControl);
16151684

16161685
// Install train crossing crashfix (the temporary variable is required for the template logic)
16171686
void (*temp)() = HOOK_TrainCrossingBarrierCrashFix<RETURN_CObject_Destructor_TrainCrossing_Check, RETURN_CObject_Destructor_TrainCrossing_Invalid>;

0 commit comments

Comments
 (0)