11/* ****************************************************************************
22 *
3- * PROJECT: Multi Theft Auto v1.0
3+ * PROJECT: Multi Theft Auto
44 * LICENSE: See LICENSE in the top level directory
5- * FILE: game_sa/CAnimManagerSA.cpp
5+ * FILE: Client/ game_sa/CAnimManagerSA.cpp
66 * PURPOSE: Animation manager
77 *
8- * Multi Theft Auto is available from http ://www. multitheftauto.com/
8+ * Multi Theft Auto is available from https ://multitheftauto.com/
99 *
1010 *****************************************************************************/
1111
2121
2222extern CGameSA* pGame;
2323
24- using std::list;
24+ // This "gateway" animation will allow us to play custom animations by simply playing this animation
25+ // and then in AddAnimation and AddAnimationAndSync hook, we can return our custom animation in the
26+ // hook instead of run_wuzi. This will trick GTA SA into thinking that it is playing run_wuzi from
27+ // ped block, but in reality, it's playing our custom animation, and Of course, we can return run_wuzi
28+ // animation within the hook if we want to play it instead. Why run_wuzi? We can also use another animation,
29+ // but I've tested with this one mostly, so let's stick to this.
30+ static const char * const kGateWayBlockName = " ped" ;
31+ static const char * const kGateWayAnimationName = " run_wuzi" ;
2532
2633CAnimManagerSA::CAnimManagerSA ()
2734{
@@ -195,7 +202,7 @@ int CAnimManagerSA::RegisterAnimBlock(const char* szName)
195202 return iReturn;
196203}
197204
198- std::unique_ptr<CAnimBlendAssocGroup> CAnimManagerSA::GetAnimBlendAssoc (AssocGroupId groupID)
205+ std::unique_ptr<CAnimBlendAssocGroup> CAnimManagerSA::GetAnimBlendAssoc (AssocGroupId groupID) const
199206{
200207 CAnimBlendAssocGroupSAInterface* pInterface = nullptr ;
201208 DWORD dwFunc = FUNC_CAnimManager_GetAnimBlendAssoc;
@@ -274,8 +281,12 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::CreateAnimAssociation(Ass
274281 return nullptr ;
275282}
276283
277- CAnimManagerSA::StaticAssocIntface_type CAnimManagerSA::GetAnimStaticAssociation (eAnimGroup animGroup, eAnimID animID)
284+ CAnimManagerSA::StaticAssocIntface_type CAnimManagerSA::GetAnimStaticAssociation (eAnimGroup animGroup, eAnimID animID) const
278285{
286+ // We check the validity of the group, avoid crashes due to an invalid group
287+ if (!IsValidGroup (static_cast <std::uint32_t >(animGroup)))
288+ return nullptr ;
289+
279290 CAnimBlendStaticAssociationSAInterface* pInterface = nullptr ;
280291 DWORD dwFunc = FUNC_CAnimManager_GetAnimAssociation;
281292 _asm
@@ -295,6 +306,10 @@ CAnimManagerSA::StaticAssocIntface_type CAnimManagerSA::GetAnimStaticAssociation
295306
296307std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::GetAnimAssociation (AssocGroupId animGroup, const char * szAnimName)
297308{
309+ // We check the validity of the group, avoid crashes due to an invalid group
310+ if (!IsValidGroup (animGroup))
311+ return nullptr ;
312+
298313 CAnimBlendAssociationSAInterface* pInterface = nullptr ;
299314 DWORD dwFunc = FUNC_CAnimManager_GetAnimAssociation_str;
300315 _asm
@@ -363,7 +378,7 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::AddAnimationAndSync(RpClu
363378 AnimationId animID)
364379{
365380 if (!pClump)
366- return NULL ;
381+ return nullptr ;
367382
368383 CAnimBlendAssociationSAInterface* pInterface = nullptr ;
369384 DWORD dwFunc = FUNC_CAnimManager_AddAnimationAndSync;
@@ -387,8 +402,8 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::AddAnimationAndSync(RpClu
387402
388403std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation (RpClump* pClump, AssocGroupId animGroup, AnimationId animID, float fBlendDelta )
389404{
390- if (!pClump)
391- return NULL ;
405+ if (!pClump || ! IsValidAnim (animGroup, animID) )
406+ return nullptr ;
392407
393408 CAnimBlendAssociationSAInterface* pInterface = nullptr ;
394409 DWORD dwFunc = FUNC_CAnimManager_BlendAnimation;
@@ -495,7 +510,10 @@ void CAnimManagerSA::RemoveAnimBlock(int ID)
495510AnimAssocDefinition* CAnimManagerSA::AddAnimAssocDefinition (const char * szBlockName, const char * szAnimName, AssocGroupId animGroup, AnimationId animID,
496511 AnimDescriptor* pDescriptor)
497512{
498- AnimAssocDefinition* pReturn;
513+ if (!IsValidAnim (animGroup, animID))
514+ return nullptr ;
515+
516+ AnimAssocDefinition* pReturn{};
499517 DWORD dwFunc = FUNC_CAnimManager_AddAnimAssocDefinition;
500518 _asm
501519 {
@@ -508,7 +526,7 @@ AnimAssocDefinition* CAnimManagerSA::AddAnimAssocDefinition(const char* szBlockN
508526 mov pReturn, eax
509527 add esp, 0x14
510528 }
511- return NULL ;
529+ return pReturn ;
512530}
513531
514532void CAnimManagerSA::ReadAnimAssociationDefinitions ()
@@ -849,5 +867,33 @@ void CAnimManagerSA::DeleteCustomAnimSequenceInterface(CAnimBlendSequenceSAInter
849867
850868bool CAnimManagerSA::isGateWayAnimationHierarchy (CAnimBlendHierarchySAInterface* pInterface)
851869{
852- return pGame->GetKeyGen ()->GetUppercaseKey (m_kGateWayAnimationName.c_str ()) == pInterface->uiHashKey ;
870+ return pGame->GetKeyGen ()->GetUppercaseKey (kGateWayAnimationName ) == pInterface->uiHashKey ;
871+ }
872+
873+ const char * CAnimManagerSA::GetGateWayBlockName () const
874+ {
875+ return kGateWayBlockName ;
876+ }
877+
878+ const char * CAnimManagerSA::GetGateWayAnimationName () const
879+ {
880+ return kGateWayAnimationName ;
881+ }
882+
883+ bool CAnimManagerSA::IsValidGroup (std::uint32_t uiAnimGroup) const
884+ {
885+ const auto pGroup = GetAnimBlendAssoc (uiAnimGroup);
886+ return pGroup && pGroup->IsCreated ();
887+ }
888+
889+ bool CAnimManagerSA::IsValidAnim (std::uint32_t uiAnimGroup, std::uint32_t uiAnimID) const
890+ {
891+ // We get an animation for the checks
892+ const auto pAnim = GetAnimStaticAssociation ((eAnimGroup)uiAnimGroup, (eAnimID)uiAnimID);
893+ if (!pAnim)
894+ return false ;
895+
896+ // We check the interface and sAnimID, if AnimID is not in GTA:SA, it will differ from our indicators in sAnimID
897+ const auto pInterface = pAnim->GetInterface ();
898+ return pInterface && pInterface->sAnimID == uiAnimID;
853899}
0 commit comments