Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
78 changes: 66 additions & 12 deletions Client/mods/deathmatch/logic/CClientPed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3631,7 +3631,20 @@ void CClientPed::_CreateModel()
// Replace the loaded model info with the model we're going to load and
// add a reference to it.
m_pLoadedModelInfo = m_pModelInfo;
if (!m_pLoadedModelInfo)
{
NotifyUnableToCreate();
return;
}

m_pLoadedModelInfo->ModelAddRef(BLOCKING, "CClientPed::_CreateModel");
if (!m_pLoadedModelInfo->GetRwObject())
{
m_pLoadedModelInfo->RemoveRef();
m_pLoadedModelInfo = nullptr;
NotifyUnableToCreate();
return;
}

// Create the new ped
m_pPlayerPed = dynamic_cast<CPlayerPed*>(g_pGame->GetPools()->AddPed(this, m_ulModel));
Expand Down Expand Up @@ -3767,7 +3780,20 @@ void CClientPed::_CreateLocalModel()

// Add a reference to the model we're using
m_pLoadedModelInfo = m_pModelInfo;
if (!m_pLoadedModelInfo)
{
NotifyUnableToCreate();
return;
}

m_pLoadedModelInfo->ModelAddRef(BLOCKING, "CClientPed::_CreateLocalModel");
if (!m_pLoadedModelInfo->GetRwObject())
{
m_pLoadedModelInfo->RemoveRef();
m_pLoadedModelInfo = nullptr;
NotifyUnableToCreate();
return;
}

// Make sure we are CJ
if (m_pPlayerPed->GetModelIndex() != m_ulModel)
Expand Down Expand Up @@ -3901,12 +3927,20 @@ void CClientPed::_DestroyLocalModel()
// Make sure we are CJ again
if (m_pPlayerPed->GetModelIndex() != 0)
{
m_pPlayerPed->SetModelIndex(0);
auto* pDefaultModelInfo = g_pGame->GetModelInfo(0);
if (pDefaultModelInfo && pDefaultModelInfo->GetRwObject())
m_pPlayerPed->SetModelIndex(0);
}

// Remove reference to our previous model
m_pLoadedModelInfo->RemoveRef();
m_pLoadedModelInfo = NULL;
// Remove reference to our previous model.
// Always release regardless of whether the default model was restored;
// the ped is being abandoned by MTA here, and GTA's native ped ref still protects
// the model from streaming eviction if SetModelIndex(0) was not possible.
if (m_pLoadedModelInfo)
{
m_pLoadedModelInfo->RemoveRef();
m_pLoadedModelInfo = nullptr;
}

// NULL our pointers, we don't destroy the local player
m_pPlayerPed = NULL;
Expand All @@ -3918,6 +3952,32 @@ void CClientPed::_ChangeModel()
// Different model than before?
if (m_pPlayerPed->GetModelIndex() != m_ulModel)
{
CModelInfo* pLoadedModel = nullptr;
if (m_bIsLocalPlayer)
{
// Remember the model we had loaded and store the new model we're going to load
pLoadedModel = m_pLoadedModelInfo;
m_pLoadedModelInfo = m_pModelInfo;
if (!m_pLoadedModelInfo)
{
m_pLoadedModelInfo = pLoadedModel;
if (m_clientModel && m_clientModel->GetModelID() != m_ulModel)
m_clientModel = nullptr;
return;
}

// Add reference to the model
m_pLoadedModelInfo->ModelAddRef(BLOCKING, "CClientPed::_ChangeModel");
if (!m_pLoadedModelInfo->GetRwObject())
{
m_pLoadedModelInfo->RemoveRef();
m_pLoadedModelInfo = pLoadedModel;
if (m_clientModel && m_clientModel->GetModelID() != m_ulModel)
m_clientModel = nullptr;
return;
}
}

g_pMultiplayer->SetAutomaticVehicleStartupOnPedEnter(false);

// We need to reset visual stats when changing from CJ model
Expand Down Expand Up @@ -3965,13 +4025,6 @@ void CClientPed::_ChangeModel()
// Takes care of clothes/task issues
Respawn(NULL, true, false);

// Remember the model we had loaded and store the new model we're going to load
CModelInfo* pLoadedModel = m_pLoadedModelInfo;
m_pLoadedModelInfo = m_pModelInfo;

// Add reference to the model
m_pLoadedModelInfo->ModelAddRef(BLOCKING, "CClientPed::_ChangeModel");

// Set the new player model and restore the interior
m_pPlayerPed->SetModelIndex(m_ulModel);

Expand All @@ -3985,7 +4038,8 @@ void CClientPed::_ChangeModel()
}

// Remove reference to the old model we used (Flag extra GTA reference to be removed as well)
pLoadedModel->RemoveRef(true);
if (pLoadedModel)
pLoadedModel->RemoveRef(true);
pLoadedModel = NULL;

// Warp into it again
Expand Down
82 changes: 75 additions & 7 deletions Client/multiplayer_sa/CMultiplayerSA_CrashFixHacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2832,29 +2832,32 @@ static void __declspec(naked) HOOK_CVolumetricShadowMgr_Update()
////////////////////////////////////////////////////////////////////////
// CAnimManager::CreateAnimAssocGroups
//
// CModelInfo::ms_modelInfoPtrs at the given index is a null pointer
// Missing model info or RwObject before the clump is used for associations
////////////////////////////////////////////////////////////////////////
void OnMY_CAnimManager_CreateAnimAssocGroups(uint uiModelId)
bool OnMY_CAnimManager_CreateAnimAssocGroups(uint uiModelId)
{
CModelInfo* pModelInfo = pGameInterface->GetModelInfo(uiModelId);
CBaseModelInfoSAInterface* pInterface = pModelInfo ? pModelInfo->GetInterface() : nullptr;
if (!pInterface || pInterface->pRwObject == nullptr)
if (!pInterface || !pInterface->pRwObject)
{
// Crash will occur at offset 00349b7b
OnCrashAverted(816);
LogEvent(816, "Model not loaded", "CAnimManager_CreateAnimAssocGroups", SString("No RwObject for model:%d", uiModelId), 5416);
CArgMap argMap;
argMap.Set("id", uiModelId);
argMap.Set("reason", "createanim");
SetApplicationSetting("diagnostics", "gta-model-fail", argMap.ToString());
return false;
}
return true;
}

// Hook info
#define HOOKPOS_CAnimManager_CreateAnimAssocGroups 0x4D3D52
#define HOOKSIZE_CAnimManager_CreateAnimAssocGroups 5
#define HOOKCHECK_CAnimManager_CreateAnimAssocGroups 0x8B
DWORD RETURN_CAnimManager_CreateAnimAssocGroups = 0x4D3D59;
static void __declspec(naked) HOOK_CAnimManager_CreateAnimAssocGroups()
DWORD RETURN_CAnimManager_CreateAnimAssocGroups = 0x4D3D59;
DWORD RETURN_CAnimManager_CreateAnimAssocGroups_Skip = 0x4D3D71;
void _declspec(naked) HOOK_CAnimManager_CreateAnimAssocGroups()
{
MTA_VERIFY_HOOK_LOCAL_SIZE;

Expand All @@ -2865,15 +2868,80 @@ static void __declspec(naked) HOOK_CAnimManager_CreateAnimAssocGroups()
push eax
call OnMY_CAnimManager_CreateAnimAssocGroups
add esp, 4*1
test al, al
popad
jz skipCreateInstance

// Replaced code
// Replaced code
push ecx
mov ecx, dword ptr[ARRAY_ModelInfo]
mov eax, dword ptr[ecx + eax*4]
pop ecx

jmp RETURN_CAnimManager_CreateAnimAssocGroups

skipCreateInstance:
xor ebx, ebx
jmp RETURN_CAnimManager_CreateAnimAssocGroups_Skip
}
// clang-format on
}

void OnMY_CAnimBlendAssocGroup_CreateAssociations(CBaseModelInfoSAInterface* pModelInfo)
{
OnCrashAverted(816);

int iModelId = -1;
CBaseModelInfoSAInterface** ppModelInfo = (CBaseModelInfoSAInterface**)ARRAY_ModelInfo;
const int maximumModelId = pGameInterface->GetBaseIDforTXD();
for (int i = 0; i < maximumModelId; i++)
{
if (ppModelInfo[i] == pModelInfo)
{
iModelId = i;
break;
}
}

LogEvent(816, "Model not loaded", "CAnimBlendAssocGroup_CreateAssociations", SString("No RwObject for model:%d", iModelId), 5416);
CArgMap argMap;
argMap.Set("id", iModelId);
argMap.Set("reason", "createassoc");
SetApplicationSetting("diagnostics", "gta-model-fail", argMap.ToString());
}

#define HOOKPOS_CAnimBlendAssocGroup_CreateAssociations 0x4CE2F7
#define HOOKSIZE_CAnimBlendAssocGroup_CreateAssociations 7
#define HOOKCHECK_CAnimBlendAssocGroup_CreateAssociations 0x8B
DWORD RETURN_CAnimBlendAssocGroup_CreateAssociations = 0x4CE2FE;
DWORD RETURN_CAnimBlendAssocGroup_CreateAssociations_Skip = 0x4CE36F;
void _declspec(naked) HOOK_CAnimBlendAssocGroup_CreateAssociations()
{
// clang-format off

MTA_VERIFY_HOOK_LOCAL_SIZE;
__asm
{
test eax, eax
jz skipCreateAssociation
cmp dword ptr[eax+1Ch], 0
jnz continueCreateAssociation

pushad
push eax
call OnMY_CAnimBlendAssocGroup_CreateAssociations
add esp, 4*1
popad
jmp skipCreateAssociation

continueCreateAssociation:
mov edx, [eax]
mov ecx, eax
call dword ptr[edx+2Ch]
jmp RETURN_CAnimBlendAssocGroup_CreateAssociations

skipCreateAssociation:
jmp RETURN_CAnimBlendAssocGroup_CreateAssociations_Skip
}
// clang-format on
}
Expand Down
Loading