Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
afef0c6
Add ability to enable/disable vehicle model hierarchy typo fixes
SpeedyFolf May 12, 2026
7aca548
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf May 14, 2026
c6d0ed8
Remove vehicle model hierarchy typo fixes toggle in ResetWorldProperties
SpeedyFolf May 16, 2026
a948686
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf May 16, 2026
75228c9
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf May 18, 2026
eab6386
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf May 27, 2026
44693fc
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf May 28, 2026
05160d6
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf May 31, 2026
83d124b
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 3, 2026
f259094
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 5, 2026
fbbc3b2
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 8, 2026
e9117ac
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 11, 2026
637e501
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 11, 2026
9075bb7
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 15, 2026
9f36508
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 16, 2026
00c2100
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 18, 2026
1954974
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 23, 2026
52be2aa
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 26, 2026
a5eb895
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jun 29, 2026
6756863
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jul 2, 2026
796ae49
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jul 2, 2026
d0a1dac
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jul 3, 2026
fde702a
Merge branch 'multitheftauto:master' into feature/vehicle-model-hiera…
SpeedyFolf Jul 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*****************************************************************************/

#include "StdInc.h"
#include <multiplayer/CMultiplayer.h>
#include <game/CColPoint.h>
#include <game/CObjectGroupPhysicalProperties.h>
#include <game/CStreaming.h>
Expand Down Expand Up @@ -83,6 +84,17 @@ size_t EngineStreamingGetBufferSize()
return g_pGame->GetStreaming()->GetStreamingBufferSize();
}

// Opt-in SilentPatch-style fixes for stock vehicle.dff hierarchy typos (wheel_lm_dummy vs wheel_lm, etc.).
void EngineSetVehicleHierarchyTypoFixesEnabled(bool enabled)
{
g_pCore->GetMultiplayer()->SetVehicleHierarchyTypoFixesEnabled(enabled);
}

bool EngineGetVehicleHierarchyTypoFixesEnabled()
{
return g_pCore->GetMultiplayer()->GetVehicleHierarchyTypoFixesEnabled();
}

void CLuaEngineDefs::LoadFunctions()
{
constexpr static const std::pair<const char*, lua_CFunction> functions[]{
Expand Down Expand Up @@ -163,6 +175,8 @@ void CLuaEngineDefs::LoadFunctions()
{"enginePreloadWorldArea", ArgumentParser<EnginePreloadWorldArea>},
{"engineRestreamModel", ArgumentParser<EngineRestreamModel>},
{"engineRestream", ArgumentParser<EngineRestream>},
{"engineSetVehicleHierarchyTypoFixesEnabled", ArgumentParser<EngineSetVehicleHierarchyTypoFixesEnabled>},
{"engineGetVehicleHierarchyTypoFixesEnabled", ArgumentParser<EngineGetVehicleHierarchyTypoFixesEnabled>},

// CLuaCFunctions::AddFunction ( "engineReplaceMatchingAtomics", EngineReplaceMatchingAtomics );
// CLuaCFunctions::AddFunction ( "engineReplaceWheelAtomics", EngineReplaceWheelAtomics );
Expand Down Expand Up @@ -212,6 +226,9 @@ void CLuaEngineDefs::AddClass(lua_State* luaVM)
lua_classfunction(luaVM, "setModelTXDID", "engineSetModelTXDID");
lua_classfunction(luaVM, "resetModelTXDID", "engineResetModelTXDID");

lua_classfunction(luaVM, "setVehicleHierarchyTypoFixesEnabled", "engineSetVehicleHierarchyTypoFixesEnabled");
lua_classfunction(luaVM, "getVehicleHierarchyTypoFixesEnabled", "engineGetVehicleHierarchyTypoFixesEnabled");

lua_registerstaticclass(luaVM, "Engine");

// `EngineStreaming` class
Expand Down
3 changes: 3 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@ class CMultiplayerSA : public CMultiplayer
void SetBoatWaterSplashEnabled(bool bEnabled);
void SetTyreSmokeEnabled(bool bEnabled);

void SetVehicleHierarchyTypoFixesEnabled(bool bEnabled) override;
bool GetVehicleHierarchyTypoFixesEnabled() const override;

void SetLastStaticAnimationPlayed(eAnimGroup dwGroupID, eAnimID dwAnimID, DWORD dwAnimArrayAddress)
{
m_dwLastStaticAnimGroupID = dwGroupID;
Expand Down
82 changes: 82 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_VehicleHierarchyTypoFixes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: multiplayer_sa/CMultiplayerSA_VehicleHierarchyTypoFixes.cpp
* PURPOSE: Optional CVehicleModelInfo hierarchy compare hook (matches SilentPatch SA)
*
* GTA matches IDE/handling component names to frame names via _stricmp inside
* CVehicleModelInfo setup. Stock models use inconsistent spellings; SilentPatch
* wraps that call to accept both canonical and typo names. We expose the same
* behaviour only when enabled so servers can keep fully vanilla visuals.
*
*****************************************************************************/

#include "StdInc.h"
#include "CMultiplayerSA.h"

#include <utility>

namespace
{
// Off by default (matches stock GTA SA without SilentPatch).
bool g_bVehicleHierarchyTypoFixesEnabled = false;

int(__cdecl* g_pfnOrgStricmp)(const char*, const char*) = nullptr;

// Pairs are { correct name, name as in shipping .dff }. Must be sorted by the second string.
static constexpr std::pair<const char*, const char*> typosAndFixes[] = {
{"boat_moving_hi", "boat_moving"},
{"elevator_r", "elevator"},
{"misc_a", "misca"},
{"misc_b", "miscb"},
{"taillights", "tailights"},
{"taillights2", "tailights2"},
{"transmission_f", "transmision_f"},
{"transmission_r", "transmision_r"},
{"wheel_lm_dummy", "wheel_lm"},
};

int __cdecl Hooked_VehicleHierarchy_Stricmp(const char* dataName, const char* nodeName)
{
if (!g_bVehicleHierarchyTypoFixesEnabled)
return g_pfnOrgStricmp(dataName, nodeName);

const int origComp = g_pfnOrgStricmp(dataName, nodeName);
if (origComp == 0)
return 0;

for (const auto& typo : typosAndFixes)
{
const int nodeComp = _stricmp(typo.second, nodeName);
if (nodeComp > 0)
break;

if (nodeComp == 0 && _stricmp(typo.first, dataName) == 0)
return 0;
}

return origComp;
}
} // namespace

void InitVehicleHierarchyTypoFixesHook()
{
// SA 1.0 US: indirect call to _stricmp while CVehicleModelInfo binds handling/IDE component names to clump frames.
// Same site hooked by SilentPatch (`InterceptCall(0x4C5311, ...)`).
constexpr DWORD CALLSITE = 0x4C5311;
HookCheckOriginalByte(CALLSITE, 0xE8);
const DWORD rel = *reinterpret_cast<DWORD*>(CALLSITE + 1);
g_pfnOrgStricmp = reinterpret_cast<decltype(g_pfnOrgStricmp)>(CALLSITE + 5 + rel);
HookInstallCall(CALLSITE, reinterpret_cast<DWORD>(&Hooked_VehicleHierarchy_Stricmp));
}

void CMultiplayerSA::SetVehicleHierarchyTypoFixesEnabled(bool bEnabled)
{
g_bVehicleHierarchyTypoFixesEnabled = bEnabled;
}

bool CMultiplayerSA::GetVehicleHierarchyTypoFixesEnabled() const
{
return g_bVehicleHierarchyTypoFixesEnabled;
}
12 changes: 12 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_VehicleHierarchyTypoFixes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: multiplayer_sa/CMultiplayerSA_VehicleHierarchyTypoFixes.h
* PURPOSE: Init for optional vehicle.dff hierarchy typo matching (SilentPatch-style)
*
*****************************************************************************/

#pragma once

void InitVehicleHierarchyTypoFixesHook();
4 changes: 4 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*****************************************************************************/

#include "StdInc.h"
#include "CMultiplayerSA_VehicleHierarchyTypoFixes.h"

static bool __fastcall AreVehicleDoorsUndamageable(CVehicleSAInterface* vehicle)
{
Expand Down Expand Up @@ -72,4 +73,7 @@ static void __declspec(naked) HOOK_CDamageManager__ProgressDoorDamage()
void CMultiplayerSA::InitHooks_Vehicles()
{
EZHookInstall(CDamageManager__ProgressDoorDamage);

// SilentPatch-style optional matching for typo'd vehicle component frame names (see CMultiplayerSA_VehicleHierarchyTypoFixes.cpp).
InitVehicleHierarchyTypoFixesHook();
}
5 changes: 5 additions & 0 deletions Client/sdk/multiplayer/CMultiplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ class CMultiplayer
virtual void SetBoatWaterSplashEnabled(bool bEnabled) = 0;
virtual void SetTyreSmokeEnabled(bool bEnabled) = 0;

// When enabled, matches canonical vehicle component names to the typo'd hierarchy nodes in stock GTA SA models
// (SilentPatch-style fix). Off by default so behaviour stays vanilla unless a script opts in.
virtual void SetVehicleHierarchyTypoFixesEnabled(bool bEnabled) = 0;
virtual bool GetVehicleHierarchyTypoFixesEnabled() const = 0;

virtual eAnimGroup GetLastStaticAnimationGroupID() = 0;
virtual eAnimID GetLastStaticAnimationID() = 0;
virtual DWORD GetLastAnimArrayAddress() = 0;
Expand Down
Loading