Skip to content

Commit d112a3b

Browse files
committed
Objects animations
1 parent 1660597 commit d112a3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+778
-25
lines changed

Client/game_sa/CAnimBlendAssociationSA.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ class CAnimBlendAssociationSA : public CAnimBlendAssociation
171171
float GetLength() const noexcept { return GetAnimHierarchy()->GetTotalTime(); }
172172
void SetAnimID(short sAnimID) { m_pInterface->sAnimID = sAnimID; }
173173
void SetAnimGroup(short sAnimGroup) { m_pInterface->sAnimGroup = sAnimGroup; }
174+
175+
short GetFlags() const override { return m_pInterface->m_nFlags; }
174176
void SetFlags(short sFlags) { m_pInterface->m_nFlags = sFlags; }
175177

176178
protected:

Client/game_sa/CAnimManagerSA.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,13 +418,17 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* p
418418
}
419419

420420
std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* pClump, CAnimBlendHierarchy* pHierarchy, int ID, float fBlendDelta)
421+
{
422+
return BlendAnimation(pClump, pHierarchy->GetInterface(), ID, fBlendDelta);
423+
}
424+
425+
std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* pClump, CAnimBlendHierarchySAInterface* pHierarchyInterface, int ID, float fBlendDelta)
421426
{
422427
if (!pClump)
423-
return NULL;
428+
return nullptr;
424429

425430
CAnimBlendAssociationSAInterface* pInterface = nullptr;
426431
DWORD dwFunc = FUNC_CAnimManager_BlendAnimation_hier;
427-
CAnimBlendHierarchySAInterface* pHierarchyInterface = pHierarchy->GetInterface();
428432
__asm
429433
{
430434
push fBlendDelta
@@ -435,10 +439,10 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* p
435439
mov pInterface, eax
436440
add esp, 0x10
437441
}
442+
438443
if (pInterface)
439-
{
440444
return std::make_unique<CAnimBlendAssociationSA>(pInterface);
441-
}
445+
442446
return nullptr;
443447
}
444448

Client/game_sa/CAnimManagerSA.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class CAnimManagerSA : public CAnimManager
109109
AnimationId animID);
110110
std::unique_ptr<CAnimBlendAssociation> BlendAnimation(RpClump* pClump, AssocGroupId animGroup, AnimationId animID, float fBlendDelta);
111111
std::unique_ptr<CAnimBlendAssociation> BlendAnimation(RpClump* pClump, CAnimBlendHierarchy* pHierarchy, int ID, float fBlendDelta);
112+
std::unique_ptr<CAnimBlendAssociation> BlendAnimation(RpClump* pClump, CAnimBlendHierarchySAInterface* pHierarchyInterface, int ID, float fBlendDelta);
112113

113114
void AddAnimBlockRef(int ID);
114115
void RemoveAnimBlockRef(int ID);

Client/game_sa/CBuildingSA.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "CGameSA.h"
1616
#include "CMatrixLinkSA.h"
1717
#include "CDynamicPool.h"
18+
#include "CAnimManagerSA.h"
19+
#include "gamesa_renderware.h"
1820

1921
extern CGameSA* pGame;
2022

@@ -70,6 +72,33 @@ void CBuildingSA::SetLod(CBuilding* pLod)
7072
}
7173
}
7274

75+
void CBuildingSA::SetAnimation(CAnimBlendHierarchySAInterface* animation)
76+
{
77+
if (!m_pInterface || !m_pInterface->m_pRwObject)
78+
return;
79+
80+
RpClump* clump = reinterpret_cast<RpClump*>(m_pInterface->m_pRwObject);
81+
82+
if (!RpAnimBlendClumpIsInitialized(clump) && animation)
83+
RpAnimBlendClumpInit(clump);
84+
85+
if (animation)
86+
pGame->GetAnimManager()->BlendAnimation(clump, animation, ANIMATION_IS_LOOPED, 1.0f);
87+
}
88+
89+
bool CBuildingSA::SetAnimationSpeed(float speed)
90+
{
91+
if (!m_pInterface || !m_pInterface->m_pRwObject)
92+
return false;
93+
94+
auto assoc = pGame->GetAnimManager()->RpAnimBlendClumpGetFirstAssociation(GetRpClump());
95+
if (!assoc)
96+
return false;
97+
98+
assoc->SetCurrentSpeed(speed);
99+
return true;
100+
}
101+
73102
void CBuildingSA::AllocateMatrix()
74103
{
75104
auto* newMatrix = g_matrixPool.AllocateItem();

Client/game_sa/CBuildingSA.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class CBuildingSA final : public virtual CBuilding, public virtual CEntitySA
2727
CBuildingSAInterface* GetBuildingInterface() { return static_cast<CBuildingSAInterface*>(GetInterface()); };
2828

2929
void SetLod(CBuilding* pLod) override;
30+
void SetAnimation(class CAnimBlendHierarchySAInterface* animation) override;
31+
bool SetAnimationSpeed(float speed) override;
3032

3133
void AllocateMatrix();
3234
void ReallocateMatrix();

Client/game_sa/CBuildingsPoolSA.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ CClientEntity* CBuildingsPoolSA::GetClientBuilding(CBuildingSAInterface* pGameIn
6060
return m_buildingPool.entities[poolIndex].pClientEntity;
6161
}
6262

63-
CBuilding* CBuildingsPoolSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t modelId, CVector* vPos, CVector* vRot, uint8_t interior)
63+
CBuilding* CBuildingsPoolSA::AddBuilding(CClientBuilding* pClientBuilding, uint16_t modelId, CVector* vPos, CVector* vRot, uint8_t interior, bool anim)
6464
{
6565
if (!HasFreeBuildingSlot())
6666
return nullptr;
@@ -80,7 +80,13 @@ CBuilding* CBuildingsPoolSA::AddBuilding(CClientBuilding* pClientBuilding, uint1
8080
instance.position = *vPos;
8181
instance.rotation = {};
8282

83+
// Trick to create CAnimatedBuilding
84+
bool hasAnimBlend = modelInfo->GetInterface()->bHasAnimBlend;
85+
if (anim)
86+
modelInfo->GetInterface()->bHasAnimBlend = true;
87+
8388
auto pBuilding = static_cast<CBuildingSAInterface*>(CFileLoaderSA::LoadObjectInstance(&instance));
89+
modelInfo->GetInterface()->bHasAnimBlend = hasAnimBlend;
8490

8591
// Disable lod and ipl
8692
pBuilding->m_pLod = nullptr;

Client/game_sa/CBuildingsPoolSA.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class CBuildingsPoolSA : public CBuildingsPool
2222
CBuildingsPoolSA();
2323
~CBuildingsPoolSA() = default;
2424

25-
CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector* vPos, CVector* vRot, uint8_t interior);
25+
CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector* vPos, CVector* vRot, uint8_t interior, bool anim);
2626
void RemoveBuilding(CBuilding* pBuilding);
2727
bool HasFreeBuildingSlot();
2828

Client/game_sa/CGameSA.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,28 @@ CModelInfo* CGameSA::GetModelInfo(DWORD dwModelID, bool bCanBeInvalid)
372372
return nullptr;
373373
}
374374

375+
CModelInfo* CGameSA::GetModelInfo(CBaseModelInfoSAInterface* baseModelInfo)
376+
{
377+
static std::unordered_map<CBaseModelInfoSAInterface*, CModelInfoSA*> s_cache;
378+
379+
auto it = s_cache.find(baseModelInfo);
380+
if (it != s_cache.end())
381+
return it->second;
382+
383+
const std::size_t count = GetCountOfAllFileIDs();
384+
for (std::size_t i = 0; i < count; i++)
385+
{
386+
CModelInfoSA* modelInfo = &ModelInfo[i];
387+
if (modelInfo && modelInfo->IsValid() && modelInfo->GetInterface() == baseModelInfo)
388+
{
389+
s_cache[baseModelInfo] = modelInfo;
390+
return modelInfo;
391+
}
392+
}
393+
394+
return nullptr;
395+
}
396+
375397
/**
376398
* Starts the game
377399
* \todo make addresses into constants
@@ -1155,6 +1177,11 @@ void CGameSA::ResetModelTimes()
11551177
CModelInfoSA::StaticResetModelTimes();
11561178
}
11571179

1180+
void CGameSA::ResetModelAnimations()
1181+
{
1182+
CModelInfoSA::StaticResetModelAnimations();
1183+
}
1184+
11581185
void CGameSA::ResetAlphaTransparencies()
11591186
{
11601187
CModelInfoSA::StaticResetAlphaTransparencies();

Client/game_sa/CGameSA.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ class CGameSA : public CGame
183183

184184
CWeaponInfo* GetWeaponInfo(eWeaponType weapon, eWeaponSkill skill = WEAPONSKILL_STD);
185185
CModelInfo* GetModelInfo(DWORD dwModelID, bool bCanBeInvalid = false);
186+
CModelInfo* GetModelInfo(CBaseModelInfoSAInterface* baseModelInfo);
186187
CObjectGroupPhysicalProperties* GetObjectGroupPhysicalProperties(unsigned char ucObjectGroup);
187188

188189
uint32_t GetBaseIDforDFF() override { return 0; }
@@ -302,6 +303,7 @@ class CGameSA : public CGame
302303
void ResetAlphaTransparencies();
303304
void DisableVSync();
304305
void ResetModelTimes();
306+
void ResetModelAnimations() override;
305307

306308
void OnPedContextChange(CPed* pPedContext);
307309
CPed* GetPedContext();

Client/game_sa/CModelInfoSA.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "CPedSA.h"
2121
#include "CWorldSA.h"
2222
#include "gamesa_renderware.h"
23+
#include "CAnimManagerSA.h"
2324

2425
extern CCoreInterface* g_pCore;
2526
extern CGameSA* pGame;
@@ -36,6 +37,7 @@ std::map<CTimeInfoSAInterface*, CTimeInfoSAInterface*> CModelInfo
3637
std::unordered_map<DWORD, unsigned short> CModelInfoSA::ms_OriginalObjectPropertiesGroups;
3738
std::unordered_map<DWORD, std::pair<float, float>> CModelInfoSA::ms_VehicleModelDefaultWheelSizes;
3839
std::map<unsigned short, int> CModelInfoSA::ms_DefaultTxdIDMap;
40+
std::unordered_set<std::uint32_t> CModelInfoSA::ms_modelsModifiedAnim;
3941

4042
union tIdeFlags
4143
{
@@ -1517,6 +1519,28 @@ void CModelInfoSA::ResetAllVehiclesWheelSizes()
15171519
ms_VehicleModelDefaultWheelSizes.clear();
15181520
}
15191521

1522+
void CModelInfoSA::StaticResetModelAnimations()
1523+
{
1524+
for (auto& it : ms_modelsModifiedAnim)
1525+
{
1526+
CModelInfo* modelInfo = pGame->GetModelInfo(it);
1527+
if (modelInfo)
1528+
{
1529+
modelInfo->DisableObjectAnimation(false);
1530+
modelInfo->SetObjectAnimation(nullptr, 0);
1531+
}
1532+
1533+
CBaseModelInfoSAInterface* modelInfoInterface = modelInfo->GetInterface();
1534+
if (modelInfoInterface)
1535+
{
1536+
modelInfoInterface->bHasAnimBlend = static_cast<CClumpModelInfoSAInterface*>(modelInfoInterface)->m_nAnimFileIndex != -1;
1537+
modelInfoInterface->bAnimSomething = modelInfoInterface->bHasAnimBlend;
1538+
}
1539+
}
1540+
1541+
ms_modelsModifiedAnim.clear();
1542+
}
1543+
15201544
bool CModelInfoSA::SetCustomModel(RpClump* pClump)
15211545
{
15221546
if (!pClump)
@@ -1938,6 +1962,8 @@ static void __declspec(naked) HOOK_NodeNameStreamRead()
19381962
void CModelInfoSA::StaticSetHooks()
19391963
{
19401964
EZHookInstall(NodeNameStreamRead);
1965+
1966+
HookInstallVTBLCall((void*)0x85BD5C, (std::uintptr_t)CClumpModelInfoSAInterface::CreateInstance);
19411967
}
19421968

19431969
// Recursive RwFrame children searching function
@@ -2183,3 +2209,52 @@ bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) con
21832209
{
21842210
return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex);
21852211
}
2212+
2213+
RpClump* __fastcall CClumpModelInfoSAInterface::CreateInstance(CClumpModelInfoSAInterface* clumpModelInfo)
2214+
{
2215+
if (!clumpModelInfo->pRwObject)
2216+
return nullptr;
2217+
2218+
clumpModelInfo->AddRef();
2219+
2220+
RpClump* clump = RpClumpClone(reinterpret_cast<RpClump*>(clumpModelInfo->pRwObject));
2221+
2222+
if (IsClumpSkinned(clump) && !clumpModelInfo->bHasComplexHierarchy)
2223+
{
2224+
RpHAnimHierarchy* hier = GetAnimHierarchyFromClump(clump);
2225+
RpClumpForAllAtomics(clump, *(RpClumpForAllAtomicsCB_t*)0x4C4EF0, hier);
2226+
2227+
RtAnimAnimation* animForHierarchy = RpAnimBlendCreateAnimationForHierarchy(hier);
2228+
RtAnimInterpolatorSetCurrentAnim(hier->currentAnim, animForHierarchy);
2229+
hier->flags = rpHANIMHIERARCHYUPDATEMODELLINGMATRICES | rpHANIMHIERARCHYUPDATELTMS;
2230+
}
2231+
2232+
if (clumpModelInfo->bHasAnimBlend)
2233+
{
2234+
CAnimBlendHierarchySAInterface* anim = nullptr;
2235+
auto* modelInfo = pGame->GetModelInfo(static_cast<CBaseModelInfoSAInterface*>(clumpModelInfo));
2236+
2237+
if (clumpModelInfo->m_nAnimFileIndex != -1)
2238+
{
2239+
if (!modelInfo || !modelInfo->IsObjectAnimationDisabled())
2240+
{
2241+
if (auto block = pGame->GetAnimManager()->GetAnimationBlock(clumpModelInfo->m_nAnimFileIndex))
2242+
{
2243+
if (auto animation = pGame->GetAnimManager()->GetAnimation(clumpModelInfo->ulHashKey, block))
2244+
anim = animation->GetInterface();
2245+
}
2246+
}
2247+
}
2248+
else if (modelInfo)
2249+
anim = modelInfo->GetObjectAnimation();
2250+
2251+
if (anim)
2252+
{
2253+
RpAnimBlendClumpInit(clump);
2254+
pGame->GetAnimManager()->BlendAnimation(clump, anim, ANIMATION_IS_LOOPED, 1.0f);
2255+
}
2256+
}
2257+
2258+
clumpModelInfo->RemoveRef();
2259+
return clump;
2260+
}

0 commit comments

Comments
 (0)