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
2 changes: 2 additions & 0 deletions Client/game_sa/CAnimBlendAssociationSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class CAnimBlendAssociationSA : public CAnimBlendAssociation
float GetLength() const noexcept { return GetAnimHierarchy()->GetTotalTime(); }
void SetAnimID(short sAnimID) { m_pInterface->sAnimID = sAnimID; }
void SetAnimGroup(short sAnimGroup) { m_pInterface->sAnimGroup = sAnimGroup; }

short GetFlags() const override { return m_pInterface->m_nFlags; }
void SetFlags(short sFlags) { m_pInterface->m_nFlags = sFlags; }

protected:
Expand Down
12 changes: 8 additions & 4 deletions Client/game_sa/CAnimManagerSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,13 +418,17 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* p
}

std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* pClump, CAnimBlendHierarchy* pHierarchy, int ID, float fBlendDelta)
{
return BlendAnimation(pClump, pHierarchy->GetInterface(), ID, fBlendDelta);
}

std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* pClump, CAnimBlendHierarchySAInterface* pHierarchyInterface, int ID, float fBlendDelta)
{
if (!pClump)
return NULL;
return nullptr;

CAnimBlendAssociationSAInterface* pInterface = nullptr;
DWORD dwFunc = FUNC_CAnimManager_BlendAnimation_hier;
CAnimBlendHierarchySAInterface* pHierarchyInterface = pHierarchy->GetInterface();
__asm
{
push fBlendDelta
Expand All @@ -435,10 +439,10 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* p
mov pInterface, eax
add esp, 0x10
}

if (pInterface)
{
return std::make_unique<CAnimBlendAssociationSA>(pInterface);
}

return nullptr;
}

Expand Down
1 change: 1 addition & 0 deletions Client/game_sa/CAnimManagerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class CAnimManagerSA : public CAnimManager
AnimationId animID);
std::unique_ptr<CAnimBlendAssociation> BlendAnimation(RpClump* pClump, AssocGroupId animGroup, AnimationId animID, float fBlendDelta);
std::unique_ptr<CAnimBlendAssociation> BlendAnimation(RpClump* pClump, CAnimBlendHierarchy* pHierarchy, int ID, float fBlendDelta);
std::unique_ptr<CAnimBlendAssociation> BlendAnimation(RpClump* pClump, CAnimBlendHierarchySAInterface* pHierarchyInterface, int ID, float fBlendDelta);

void AddAnimBlockRef(int ID);
void RemoveAnimBlockRef(int ID);
Expand Down
29 changes: 29 additions & 0 deletions Client/game_sa/CBuildingSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "CGameSA.h"
#include "CMatrixLinkSA.h"
#include "CDynamicPool.h"
#include "CAnimManagerSA.h"
#include "gamesa_renderware.h"

extern CGameSA* pGame;

Expand Down Expand Up @@ -70,6 +72,33 @@ void CBuildingSA::SetLod(CBuilding* pLod)
}
}

void CBuildingSA::SetAnimation(CAnimBlendHierarchySAInterface* animation, eAnimationFlags flags)
{
if (!m_pInterface || !m_pInterface->m_pRwObject)
return;

RpClump* clump = reinterpret_cast<RpClump*>(m_pInterface->m_pRwObject);

if (!RpAnimBlendClumpIsInitialized(clump) && animation)
RpAnimBlendClumpInit(clump);

if (animation)
pGame->GetAnimManager()->BlendAnimation(clump, animation, flags, 1.0f);
}

bool CBuildingSA::SetAnimationSpeed(float speed)
{
if (!m_pInterface || !m_pInterface->m_pRwObject)
return false;

auto assoc = pGame->GetAnimManager()->RpAnimBlendClumpGetFirstAssociation(GetRpClump());
if (!assoc)
return false;

assoc->SetCurrentSpeed(speed);
return true;
}

void CBuildingSA::AllocateMatrix()
{
auto* newMatrix = g_matrixPool.AllocateItem();
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/CBuildingSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class CBuildingSA final : public virtual CBuilding, public virtual CEntitySA
CBuildingSAInterface* GetBuildingInterface() { return static_cast<CBuildingSAInterface*>(GetInterface()); };

void SetLod(CBuilding* pLod) override;
void SetAnimation(class CAnimBlendHierarchySAInterface* animation, eAnimationFlags flags) override;
bool SetAnimationSpeed(float speed) override;

void AllocateMatrix();
void ReallocateMatrix();
Expand Down
8 changes: 7 additions & 1 deletion Client/game_sa/CBuildingsPoolSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ CClientEntity* CBuildingsPoolSA::GetClientBuilding(CBuildingSAInterface* pGameIn
return m_buildingPool.entities[poolIndex].pClientEntity;
}

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

// Trick to create CAnimatedBuilding
bool hasAnimBlend = modelInfo->GetInterface()->bHasAnimBlend;
if (anim)
modelInfo->GetInterface()->bHasAnimBlend = true;

auto pBuilding = static_cast<CBuildingSAInterface*>(CFileLoaderSA::LoadObjectInstance(&instance));
modelInfo->GetInterface()->bHasAnimBlend = hasAnimBlend;

// Disable lod and ipl
pBuilding->m_pLod = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion Client/game_sa/CBuildingsPoolSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class CBuildingsPoolSA : public CBuildingsPool
CBuildingsPoolSA();
~CBuildingsPoolSA() = default;

CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector* vPos, CVector* vRot, uint8_t interior);
CBuilding* AddBuilding(CClientBuilding*, uint16_t modelId, CVector* vPos, CVector* vRot, uint8_t interior, bool anim);
void RemoveBuilding(CBuilding* pBuilding);
bool HasFreeBuildingSlot();

Expand Down
27 changes: 27 additions & 0 deletions Client/game_sa/CGameSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,28 @@ CModelInfo* CGameSA::GetModelInfo(DWORD dwModelID, bool bCanBeInvalid)
return nullptr;
}

CModelInfo* CGameSA::GetModelInfo(CBaseModelInfoSAInterface* baseModelInfo)
{
static std::unordered_map<CBaseModelInfoSAInterface*, CModelInfoSA*> s_cache;

auto it = s_cache.find(baseModelInfo);
if (it != s_cache.end())
return it->second;

const std::size_t count = GetCountOfAllFileIDs();
for (std::size_t i = 0; i < count; i++)
{
CModelInfoSA* modelInfo = &ModelInfo[i];
if (modelInfo && modelInfo->IsValid() && modelInfo->GetInterface() == baseModelInfo)
{
s_cache[baseModelInfo] = modelInfo;
return modelInfo;
}
}

return nullptr;
}

/**
* Starts the game
* \todo make addresses into constants
Expand Down Expand Up @@ -1155,6 +1177,11 @@ void CGameSA::ResetModelTimes()
CModelInfoSA::StaticResetModelTimes();
}

void CGameSA::ResetModelAnimations()
{
CModelInfoSA::StaticResetModelAnimations();
}

void CGameSA::ResetAlphaTransparencies()
{
CModelInfoSA::StaticResetAlphaTransparencies();
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/CGameSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ class CGameSA : public CGame

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

uint32_t GetBaseIDforDFF() override { return 0; }
Expand Down Expand Up @@ -302,6 +303,7 @@ class CGameSA : public CGame
void ResetAlphaTransparencies();
void DisableVSync();
void ResetModelTimes();
void ResetModelAnimations() override;

void OnPedContextChange(CPed* pPedContext);
CPed* GetPedContext();
Expand Down
79 changes: 79 additions & 0 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "CPedSA.h"
#include "CWorldSA.h"
#include "gamesa_renderware.h"
#include "CAnimManagerSA.h"

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

union tIdeFlags
{
Expand Down Expand Up @@ -1517,6 +1519,28 @@ void CModelInfoSA::ResetAllVehiclesWheelSizes()
ms_VehicleModelDefaultWheelSizes.clear();
}

void CModelInfoSA::StaticResetModelAnimations()
{
for (auto& it : ms_modelsModifiedAnim)
{
CModelInfo* modelInfo = pGame->GetModelInfo(it);
if (modelInfo)
{
modelInfo->DisableObjectAnimation(false);
modelInfo->SetObjectAnimation(nullptr, 0, 0);
}

CBaseModelInfoSAInterface* modelInfoInterface = modelInfo->GetInterface();
if (modelInfoInterface)
{
modelInfoInterface->bHasAnimBlend = static_cast<CClumpModelInfoSAInterface*>(modelInfoInterface)->m_nAnimFileIndex != -1;
modelInfoInterface->bAnimSomething = modelInfoInterface->bHasAnimBlend;
}
}

ms_modelsModifiedAnim.clear();
}

bool CModelInfoSA::SetCustomModel(RpClump* pClump)
{
if (!pClump)
Expand Down Expand Up @@ -1938,6 +1962,8 @@ static void __declspec(naked) HOOK_NodeNameStreamRead()
void CModelInfoSA::StaticSetHooks()
{
EZHookInstall(NodeNameStreamRead);

HookInstallVTBLCall((void*)0x85BD5C, (std::uintptr_t)CClumpModelInfoSAInterface::CreateInstance);
}

// Recursive RwFrame children searching function
Expand Down Expand Up @@ -2183,3 +2209,56 @@ bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) con
{
return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex);
}

RpClump* __fastcall CClumpModelInfoSAInterface::CreateInstance(CClumpModelInfoSAInterface* clumpModelInfo)
{
if (!clumpModelInfo->pRwObject)
return nullptr;

clumpModelInfo->AddRef();

RpClump* clump = RpClumpClone(reinterpret_cast<RpClump*>(clumpModelInfo->pRwObject));

if (IsClumpSkinned(clump) && !clumpModelInfo->bHasComplexHierarchy)
{
RpHAnimHierarchy* hier = GetAnimHierarchyFromClump(clump);
RpClumpForAllAtomics(clump, reinterpret_cast<RpClumpForAllAtomicsCB_t>(0x4C4EF0), hier);

RtAnimAnimation* animForHierarchy = RpAnimBlendCreateAnimationForHierarchy(hier);
RtAnimInterpolatorSetCurrentAnim(hier->currentAnim, animForHierarchy);
hier->flags = rpHANIMHIERARCHYUPDATEMODELLINGMATRICES | rpHANIMHIERARCHYUPDATELTMS;
}

if (clumpModelInfo->bHasAnimBlend)
{
CAnimBlendHierarchySAInterface* anim = nullptr;
auto* modelInfo = pGame->GetModelInfo(static_cast<CBaseModelInfoSAInterface*>(clumpModelInfo));
eAnimationFlags flags = ANIMATION_IS_LOOPED;

if (clumpModelInfo->m_nAnimFileIndex != -1)
{
if (!modelInfo || !modelInfo->IsObjectAnimationDisabled())
{
if (auto block = pGame->GetAnimManager()->GetAnimationBlock(clumpModelInfo->m_nAnimFileIndex))
{
if (auto animation = pGame->GetAnimManager()->GetAnimation(clumpModelInfo->ulHashKey, block))
anim = animation->GetInterface();
}
}
}
else if (modelInfo)
{
anim = modelInfo->GetObjectAnimation();
flags = modelInfo->GetObjectAnimationFlags();
}

if (anim)
{
RpAnimBlendClumpInit(clump);
pGame->GetAnimManager()->BlendAnimation(clump, anim, flags, 1.0f);
}
}

clumpModelInfo->RemoveRef();
return clump;
}
Loading
Loading