Skip to content

Commit

Permalink
Merge branch 'master' into building/fix_lods_crash
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNormalnij authored Jul 15, 2024
2 parents c10f4ff + bea4823 commit 466b521
Show file tree
Hide file tree
Showing 565 changed files with 9,357 additions and 8,923 deletions.
70 changes: 58 additions & 12 deletions Client/game_sa/CAnimManagerSA.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CAnimManagerSA.cpp
* FILE: Client/game_sa/CAnimManagerSA.cpp
* PURPOSE: Animation manager
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
* Multi Theft Auto is available from https://multitheftauto.com/
*
*****************************************************************************/

Expand All @@ -21,7 +21,14 @@

extern CGameSA* pGame;

using std::list;
// This "gateway" animation will allow us to play custom animations by simply playing this animation
// and then in AddAnimation and AddAnimationAndSync hook, we can return our custom animation in the
// hook instead of run_wuzi. This will trick GTA SA into thinking that it is playing run_wuzi from
// ped block, but in reality, it's playing our custom animation, and Of course, we can return run_wuzi
// animation within the hook if we want to play it instead. Why run_wuzi? We can also use another animation,
// but I've tested with this one mostly, so let's stick to this.
static const char* const kGateWayBlockName = "ped";
static const char* const kGateWayAnimationName = "run_wuzi";

CAnimManagerSA::CAnimManagerSA()
{
Expand Down Expand Up @@ -195,7 +202,7 @@ int CAnimManagerSA::RegisterAnimBlock(const char* szName)
return iReturn;
}

std::unique_ptr<CAnimBlendAssocGroup> CAnimManagerSA::GetAnimBlendAssoc(AssocGroupId groupID)
std::unique_ptr<CAnimBlendAssocGroup> CAnimManagerSA::GetAnimBlendAssoc(AssocGroupId groupID) const
{
CAnimBlendAssocGroupSAInterface* pInterface = nullptr;
DWORD dwFunc = FUNC_CAnimManager_GetAnimBlendAssoc;
Expand Down Expand Up @@ -274,8 +281,12 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::CreateAnimAssociation(Ass
return nullptr;
}

CAnimManagerSA::StaticAssocIntface_type CAnimManagerSA::GetAnimStaticAssociation(eAnimGroup animGroup, eAnimID animID)
CAnimManagerSA::StaticAssocIntface_type CAnimManagerSA::GetAnimStaticAssociation(eAnimGroup animGroup, eAnimID animID) const
{
// We check the validity of the group, avoid crashes due to an invalid group
if (!IsValidGroup(static_cast<std::uint32_t>(animGroup)))
return nullptr;

CAnimBlendStaticAssociationSAInterface* pInterface = nullptr;
DWORD dwFunc = FUNC_CAnimManager_GetAnimAssociation;
_asm
Expand All @@ -295,6 +306,10 @@ CAnimManagerSA::StaticAssocIntface_type CAnimManagerSA::GetAnimStaticAssociation

std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::GetAnimAssociation(AssocGroupId animGroup, const char* szAnimName)
{
// We check the validity of the group, avoid crashes due to an invalid group
if (!IsValidGroup(animGroup))
return nullptr;

CAnimBlendAssociationSAInterface* pInterface = nullptr;
DWORD dwFunc = FUNC_CAnimManager_GetAnimAssociation_str;
_asm
Expand Down Expand Up @@ -363,7 +378,7 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::AddAnimationAndSync(RpClu
AnimationId animID)
{
if (!pClump)
return NULL;
return nullptr;

CAnimBlendAssociationSAInterface* pInterface = nullptr;
DWORD dwFunc = FUNC_CAnimManager_AddAnimationAndSync;
Expand All @@ -387,8 +402,8 @@ std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::AddAnimationAndSync(RpClu

std::unique_ptr<CAnimBlendAssociation> CAnimManagerSA::BlendAnimation(RpClump* pClump, AssocGroupId animGroup, AnimationId animID, float fBlendDelta)
{
if (!pClump)
return NULL;
if (!pClump || !IsValidAnim(animGroup, animID))
return nullptr;

CAnimBlendAssociationSAInterface* pInterface = nullptr;
DWORD dwFunc = FUNC_CAnimManager_BlendAnimation;
Expand Down Expand Up @@ -495,7 +510,10 @@ void CAnimManagerSA::RemoveAnimBlock(int ID)
AnimAssocDefinition* CAnimManagerSA::AddAnimAssocDefinition(const char* szBlockName, const char* szAnimName, AssocGroupId animGroup, AnimationId animID,
AnimDescriptor* pDescriptor)
{
AnimAssocDefinition* pReturn;
if (!IsValidAnim(animGroup, animID))
return nullptr;

AnimAssocDefinition* pReturn{};
DWORD dwFunc = FUNC_CAnimManager_AddAnimAssocDefinition;
_asm
{
Expand All @@ -508,7 +526,7 @@ AnimAssocDefinition* CAnimManagerSA::AddAnimAssocDefinition(const char* szBlockN
mov pReturn, eax
add esp, 0x14
}
return NULL;
return pReturn;
}

void CAnimManagerSA::ReadAnimAssociationDefinitions()
Expand Down Expand Up @@ -849,5 +867,33 @@ void CAnimManagerSA::DeleteCustomAnimSequenceInterface(CAnimBlendSequenceSAInter

bool CAnimManagerSA::isGateWayAnimationHierarchy(CAnimBlendHierarchySAInterface* pInterface)
{
return pGame->GetKeyGen()->GetUppercaseKey(m_kGateWayAnimationName.c_str()) == pInterface->uiHashKey;
return pGame->GetKeyGen()->GetUppercaseKey(kGateWayAnimationName) == pInterface->uiHashKey;
}

const char* CAnimManagerSA::GetGateWayBlockName() const
{
return kGateWayBlockName;
}

const char* CAnimManagerSA::GetGateWayAnimationName() const
{
return kGateWayAnimationName;
}

bool CAnimManagerSA::IsValidGroup(std::uint32_t uiAnimGroup) const
{
const auto pGroup = GetAnimBlendAssoc(uiAnimGroup);
return pGroup && pGroup->IsCreated();
}

bool CAnimManagerSA::IsValidAnim(std::uint32_t uiAnimGroup, std::uint32_t uiAnimID) const
{
// We get an animation for the checks
const auto pAnim = GetAnimStaticAssociation((eAnimGroup)uiAnimGroup, (eAnimID)uiAnimID);
if (!pAnim)
return false;

// We check the interface and sAnimID, if AnimID is not in GTA:SA, it will differ from our indicators in sAnimID
const auto pInterface = pAnim->GetInterface();
return pInterface && pInterface->sAnimID == uiAnimID;
}
27 changes: 10 additions & 17 deletions Client/game_sa/CAnimManagerSA.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CAnimManagerSA.h
* FILE: Client/game_sa/CAnimManagerSA.h
* PURPOSE: Header file for animation manager class
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
* Multi Theft Auto is available from https://multitheftauto.com/
*
*****************************************************************************/

Expand Down Expand Up @@ -94,14 +94,14 @@ class CAnimManagerSA : public CAnimManager
int GetAnimationBlockIndex(const char* szName);
int RegisterAnimBlock(const char* szName);

std::unique_ptr<CAnimBlendAssocGroup> GetAnimBlendAssoc(AssocGroupId groupID);
std::unique_ptr<CAnimBlendAssocGroup> GetAnimBlendAssoc(AssocGroupId groupID) const;
AssocGroupId GetFirstAssocGroup(const char* szName);

const char* GetAnimGroupName(AssocGroupId groupID);
const char* GetAnimBlockName(AssocGroupId groupID);

std::unique_ptr<CAnimBlendAssociation> CreateAnimAssociation(AssocGroupId animGroup, AnimationId animID);
StaticAssocIntface_type GetAnimStaticAssociation(eAnimGroup animGroup, eAnimID animID);
StaticAssocIntface_type GetAnimStaticAssociation(eAnimGroup animGroup, eAnimID animID) const;
std::unique_ptr<CAnimBlendAssociation> GetAnimAssociation(AssocGroupId animGroup, const char* szAnimName);
std::unique_ptr<CAnimBlendAssociation> AddAnimation(RpClump* pClump, AssocGroupId animGroup, AnimationId animID);
std::unique_ptr<CAnimBlendAssociation> AddAnimation(RpClump* pClump, CAnimBlendHierarchy*, int ID);
Expand Down Expand Up @@ -159,20 +159,13 @@ class CAnimManagerSA : public CAnimManager
void DeleteCustomAnimHierarchyInterface(CAnimBlendHierarchySAInterface* pInterface);
void DeleteCustomAnimSequenceInterface(CAnimBlendSequenceSAInterface* pInterface);

bool isGateWayAnimationHierarchy(CAnimBlendHierarchySAInterface* pInterface);
const SString& GetGateWayBlockName() { return m_kGateWayBlockName; };
const SString& GetGateWayAnimationName() { return m_kGateWayAnimationName; };
bool isGateWayAnimationHierarchy(CAnimBlendHierarchySAInterface* pInterface);
const char* GetGateWayBlockName() const;
const char* GetGateWayAnimationName() const;

bool IsValidGroup(std::uint32_t uiAnimGroup) const;
bool IsValidAnim(std::uint32_t uiAnimGroup, std::uint32_t uiAnimID) const;
private:
CAnimBlendAssocGroup* m_pAnimAssocGroups[MAX_ANIM_GROUPS];
CAnimBlock* m_pAnimBlocks[MAX_ANIM_BLOCKS];

// This "gateway" animation will allow us to play custom animations by simply playing this animation
// and then in AddAnimation and AddAnimationAndSync hook, we can return our custom animation in the
// hook instead of run_wuzi. This will trick GTA SA into thinking that it is playing run_wuzi from
// ped block, but in reality, it's playing our custom animation, and Of course, we can return run_wuzi
// animation within the hook if we want to play it instead. Why run_wuzi? We can also use another animation,
// but I've tested with this one mostly, so let's stick to this.
const SString m_kGateWayBlockName = "ped";
const SString m_kGateWayAnimationName = "run_wuzi";
};
6 changes: 6 additions & 0 deletions Client/game_sa/CBuildingRemovalSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,4 +716,10 @@ void CBuildingRemovalSA::DropCaches()

m_pBinaryBuildings->clear();
m_pDataBuildings->clear();

for (auto &pRemoval : *m_pBuildingRemovals)
{
pRemoval.second->m_pDataRemoveList->clear();
pRemoval.second->m_pBinaryRemoveList->clear();
}
}
40 changes: 40 additions & 0 deletions Client/game_sa/CCheckpointSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
#include "C3DMarkerSA.h"
#include "C3DMarkersSA.h"
#include "CCheckpointSA.h"
#include "CCheckpointsSA.h"
#include "CGameSA.h"

extern CGameSA* pGame;

void CCheckpointSA::SetPosition(CVector* vecPosition)
{
Expand Down Expand Up @@ -132,3 +136,39 @@ void CCheckpointSA::Remove()
GetInterface()->m_nType = 257;
GetInterface()->rwColour = 0;
}

void CCheckpointSA::SetTargetArrowData(const SColor color, float size) noexcept
{
m_targetArrowColor = color;
m_targetArrowSize = size;
}

static void __cdecl RenderTargetArrow(CCheckpointSAInterface* pCheckpoint)
{
CCheckpoint* checkpoint = pGame->GetCheckpoints()->FindMarker(pCheckpoint->m_nIdentifier);
if (!checkpoint)
return;

CVector* position = checkpoint->GetPosition();
CVector* direction = checkpoint->GetPointDirection();
SColor color = checkpoint->GetTargetArrowColor();

((void(__cdecl*)(float, float, float, float, std::uint8_t, std::uint8_t, std::uint8_t, std::uint8_t, float, float, float))C3dMarkers_DirectionArrowSet)(position->fX, position->fY, position->fZ, checkpoint->GetTargetArrowSize(), color.R, color.G, color.B, color.A, -direction->fX, -direction->fY, -direction->fZ);
}

static void _declspec(naked) HOOK_CCheckpoint__Render()
{
_asm {
pushad
push esi
call RenderTargetArrow
add esp, 4
popad
jmp RETURN_CCheckpoint__Render
}
}

void CCheckpointSA::StaticSetHooks()
{
EZHookInstall(CCheckpoint__Render);
}
13 changes: 13 additions & 0 deletions Client/game_sa/CCheckpointSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
#include <CVector.h>
#include <game/CCheckpoint.h>

#define HOOKPOS_CCheckpoint__Render 0x725E56
#define HOOKSIZE_CCheckpoint__Render 0x5
static constexpr std::uint32_t RETURN_CCheckpoint__Render = 0x725E5B;

#define C3dMarkers_DirectionArrowSet 0x721140

class CCheckpointSAInterface
{
public:
Expand All @@ -36,12 +42,16 @@ class CCheckpointSA : public CCheckpoint
{
private:
CCheckpointSAInterface* internalInterface;
SColor m_targetArrowColor{0xFFFF4040};
float m_targetArrowSize{0.625f};

public:
CCheckpointSA(CCheckpointSAInterface* checkpointInterface) { internalInterface = checkpointInterface; };

CCheckpointSAInterface* GetInterface() { return internalInterface; }

static void StaticSetHooks();

void SetPosition(CVector* vecPosition);
CVector* GetPosition();
void SetPointDirection(CVector* vecPointDirection);
Expand All @@ -62,4 +72,7 @@ class CCheckpointSA : public CCheckpoint
void SetPulseFraction(float fPulseFraction); // doesn't work propperly (not virtualed)
float GetPulseFraction();
void Remove();
SColor GetTargetArrowColor() const noexcept override { return m_targetArrowColor; };
float GetTargetArrowSize() const noexcept override { return m_targetArrowSize; };
void SetTargetArrowData(const SColor color, float size) noexcept;
};
11 changes: 11 additions & 0 deletions Client/game_sa/CCheckpointsSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,14 @@ CCheckpoint* CCheckpointsSA::FindFreeMarker()
}
return NULL;
}

CCheckpoint* CCheckpointsSA::FindMarker(DWORD identifier)
{
for (CCheckpointSA* checkpoint : Checkpoints)
{
if (checkpoint->GetIdentifier() == identifier)
return checkpoint;
}

return nullptr;
}
1 change: 1 addition & 0 deletions Client/game_sa/CCheckpointsSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ class CCheckpointsSA : public CCheckpoints
CCheckpoint* CreateCheckpoint(DWORD Identifier, WORD wType, CVector* vecPosition, CVector* vecPointDir, float fSize, float fPulseFraction,
const SharedUtil::SColor color);
CCheckpoint* FindFreeMarker();
CCheckpoint* FindMarker(DWORD identifier);
};
Loading

0 comments on commit 466b521

Please sign in to comment.