From 347b6b66cc09232df86f5908fa542b452fc52b18 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 11 Jan 2026 17:31:37 +0100 Subject: [PATCH 1/8] Load uncompressed ANPK anims --- Client/game_sa/CAnimBlendHierarchySA.cpp | 2 +- Client/game_sa/CAnimBlendHierarchySA.h | 2 +- Client/mods/deathmatch/logic/CClientIFP.cpp | 15 +++++++++++---- Client/mods/deathmatch/logic/CClientIFP.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Client/game_sa/CAnimBlendHierarchySA.cpp b/Client/game_sa/CAnimBlendHierarchySA.cpp index ad418673d66..f5bc943cc57 100644 --- a/Client/game_sa/CAnimBlendHierarchySA.cpp +++ b/Client/game_sa/CAnimBlendHierarchySA.cpp @@ -25,7 +25,7 @@ void CAnimBlendHierarchySA::Initialize() m_pInterface->pSequences = 0; m_pInterface->usNumSequences = 0; m_pInterface->bRunningCompressed = 0; - m_pInterface->pad = 0; + m_pInterface->keepCompressed = 0; m_pInterface->iAnimBlockID = -1; m_pInterface->fTotalTime = 0; m_pInterface->pLinkPtr = 0; diff --git a/Client/game_sa/CAnimBlendHierarchySA.h b/Client/game_sa/CAnimBlendHierarchySA.h index 5c87ac7c6ff..05135c86019 100644 --- a/Client/game_sa/CAnimBlendHierarchySA.h +++ b/Client/game_sa/CAnimBlendHierarchySA.h @@ -32,7 +32,7 @@ class CAnimBlendHierarchySAInterface CAnimBlendSequenceSAInterface* pSequences; unsigned short usNumSequences; bool bRunningCompressed; - BYTE pad; + bool keepCompressed; int iAnimBlockID; float fTotalTime; DWORD* pLinkPtr; diff --git a/Client/mods/deathmatch/logic/CClientIFP.cpp b/Client/mods/deathmatch/logic/CClientIFP.cpp index 9b36b5a97fc..2e151fde4b8 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.cpp +++ b/Client/mods/deathmatch/logic/CClientIFP.cpp @@ -111,6 +111,10 @@ void CClientIFP::ReadIFPVersion1() Animation.pHierarchy = m_pAnimManager->GetCustomAnimBlendHierarchy(); InitializeAnimationHierarchy(Animation.pHierarchy, Animation.Name, Dgan.Info.Entries); + + // ANPK animations are uncompressed + Animation.pHierarchy->SetRunningCompressed(false); + Animation.pSequencesMemory = AllocateSequencesMemory(Animation.pHierarchy); Animation.pHierarchy->SetSequences(reinterpret_cast(Animation.pSequencesMemory + 4)); @@ -193,7 +197,7 @@ WORD CClientIFP::ReadSequencesVersion1(std::unique_ptr& pAn InitializeAnimationSequence(pAnimationSequence, Anim.Name, iBoneID); eFrameType iFrameType = ReadKfrm(); - if ((ReadSequenceKeyFrames(pAnimationSequence, iFrameType, Anim.Frames)) && (!bUnknownSequence)) + if ((ReadSequenceKeyFrames(pAnimationSequence, iFrameType, Anim.Frames, true)) && (!bUnknownSequence)) { MapOfSequences[iBoneID] = std::move(pAnimationSequence); } @@ -273,14 +277,17 @@ void CClientIFP::ReadSequenceVersion2(SSequenceHeaderV2& ObjectNode) strncpy(ObjectNode.Name, strCorrectBoneName, strCorrectBoneName.size() + 1); } -bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames) +bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool loadUncompressed) { size_t iCompressedFrameSize = GetSizeOfCompressedFrame(iFrameType); if (iCompressedFrameSize) { BYTE* pKeyFrames = m_pAnimManager->AllocateKeyFramesMemory(iCompressedFrameSize * cFrames); - pAnimationSequence->SetKeyFrames(cFrames, IsKeyFramesTypeRoot(iFrameType), m_kbAllKeyFramesCompressed, pKeyFrames); - ReadKeyFramesAsCompressed(pAnimationSequence, iFrameType, cFrames); + pAnimationSequence->SetKeyFrames(cFrames, IsKeyFramesTypeRoot(iFrameType), m_kbAllKeyFramesCompressed && !loadUncompressed, pKeyFrames); + + if (!loadUncompressed) + ReadKeyFramesAsCompressed(pAnimationSequence, iFrameType, cFrames); + return true; } return false; diff --git a/Client/mods/deathmatch/logic/CClientIFP.h b/Client/mods/deathmatch/logic/CClientIFP.h index 6218ff5182b..b1b71254492 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.h +++ b/Client/mods/deathmatch/logic/CClientIFP.h @@ -236,7 +236,7 @@ class CClientIFP final : public CClientEntity, CFileReader CClientIFP::eFrameType ReadKfrm(); void ReadAnimationHeaderVersion2(SAnimationHeaderV2& AnimationNode, bool bAnp3); - bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames); + bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool loadUncompressed = false); void ReadKeyFramesAsCompressed(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames); void ReadKrtsFramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); void ReadKrt0FramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); From c7e2642c119de57a384e96d75c660e47c9454b57 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 11 Jan 2026 21:26:54 +0100 Subject: [PATCH 2/8] Read frame data --- Client/game_sa/CAnimBlendHierarchySA.h | 2 +- Client/mods/deathmatch/logic/CClientIFP.cpp | 106 ++++++++++++++------ Client/mods/deathmatch/logic/CClientIFP.h | 19 ++-- Client/sdk/game/CAnimBlendHierarchy.h | 2 +- Client/sdk/game/CRenderWare.h | 7 ++ 5 files changed, 98 insertions(+), 38 deletions(-) diff --git a/Client/game_sa/CAnimBlendHierarchySA.h b/Client/game_sa/CAnimBlendHierarchySA.h index 05135c86019..71fc9ee92c4 100644 --- a/Client/game_sa/CAnimBlendHierarchySA.h +++ b/Client/game_sa/CAnimBlendHierarchySA.h @@ -47,7 +47,7 @@ class CAnimBlendHierarchySA : public CAnimBlendHierarchy void SetName(const char* szName); void SetSequences(CAnimBlendSequenceSAInterface* pSequences) { m_pInterface->pSequences = pSequences; } void SetNumSequences(unsigned short uNumSequences) { m_pInterface->usNumSequences = uNumSequences; } - void SetRunningCompressed(bool bCompressed) { m_pInterface->bRunningCompressed = bCompressed; } + void SetRunningCompressed(bool bCompressed, bool isANPK) { m_pInterface->bRunningCompressed = bCompressed; if (isANPK && !bCompressed) m_pInterface->keepCompressed = false; } void SetAnimationBlockID(int iBlockID) { m_pInterface->iAnimBlockID = iBlockID; } void RemoveAnimSequences(); void RemoveFromUncompressedCache(); diff --git a/Client/mods/deathmatch/logic/CClientIFP.cpp b/Client/mods/deathmatch/logic/CClientIFP.cpp index 2e151fde4b8..a410d1e5d10 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.cpp +++ b/Client/mods/deathmatch/logic/CClientIFP.cpp @@ -110,15 +110,12 @@ void CClientIFP::ReadIFPVersion1() ReadDgan(Dgan); Animation.pHierarchy = m_pAnimManager->GetCustomAnimBlendHierarchy(); - InitializeAnimationHierarchy(Animation.pHierarchy, Animation.Name, Dgan.Info.Entries); - - // ANPK animations are uncompressed - Animation.pHierarchy->SetRunningCompressed(false); + InitializeAnimationHierarchy(Animation.pHierarchy, Animation.Name, Dgan.Info.Entries, true); Animation.pSequencesMemory = AllocateSequencesMemory(Animation.pHierarchy); Animation.pHierarchy->SetSequences(reinterpret_cast(Animation.pSequencesMemory + 4)); - *(DWORD*)Animation.pSequencesMemory = ReadSequencesWithDummies(Animation.pHierarchy); + *(DWORD*)Animation.pSequencesMemory = ReadSequencesWithDummies(Animation.pHierarchy, true); PreProcessAnimationHierarchy(Animation.pHierarchy); } } @@ -147,12 +144,12 @@ void CClientIFP::ReadIFPVersion2(bool bAnp3) } } -WORD CClientIFP::ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy) +WORD CClientIFP::ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, bool isANPK) { SequenceMapType MapOfSequences; WORD wUnknownSequences = ReadSequences(pAnimationHierarchy, MapOfSequences); - MoveSequencesWithDummies(pAnimationHierarchy, MapOfSequences); + MoveSequencesWithDummies(pAnimationHierarchy, MapOfSequences, isANPK); WORD cSequences = m_kcIFPSequences + wUnknownSequences; // As we need support for all 32 bones, we must change the total sequences count @@ -277,16 +274,14 @@ void CClientIFP::ReadSequenceVersion2(SSequenceHeaderV2& ObjectNode) strncpy(ObjectNode.Name, strCorrectBoneName, strCorrectBoneName.size() + 1); } -bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool loadUncompressed) +bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK) { - size_t iCompressedFrameSize = GetSizeOfCompressedFrame(iFrameType); + size_t iCompressedFrameSize = GetSizeOfCompressedFrame(iFrameType, isANPK); if (iCompressedFrameSize) { BYTE* pKeyFrames = m_pAnimManager->AllocateKeyFramesMemory(iCompressedFrameSize * cFrames); - pAnimationSequence->SetKeyFrames(cFrames, IsKeyFramesTypeRoot(iFrameType), m_kbAllKeyFramesCompressed && !loadUncompressed, pKeyFrames); - - if (!loadUncompressed) - ReadKeyFramesAsCompressed(pAnimationSequence, iFrameType, cFrames); + pAnimationSequence->SetKeyFrames(cFrames, IsKeyFramesTypeRoot(iFrameType), m_kbAllKeyFramesCompressed && !isANPK, pKeyFrames); + ReadKeyFrames(pAnimationSequence, iFrameType, cFrames, isANPK); return true; } @@ -341,23 +336,35 @@ void CClientIFP::ReadAnimationHeaderVersion2(SAnimationHeaderV2& AnimationNode, } } -void CClientIFP::ReadKeyFramesAsCompressed(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames) +void CClientIFP::ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK) { switch (iFrameType) { case eFrameType::KRTS: { - ReadKrtsFramesAsCompressed(pAnimationSequence, cFrames); + if (isANPK) + ReadKrtsFramesUncompessed(pAnimationSequence, cFrames); + else + ReadKrtsFramesAsCompressed(pAnimationSequence, cFrames); + break; } case eFrameType::KRT0: { - ReadKrt0FramesAsCompressed(pAnimationSequence, cFrames); + if (isANPK) + ReadKrt0FramesUncompressed(pAnimationSequence, cFrames); + else + ReadKrt0FramesAsCompressed(pAnimationSequence, cFrames); + break; } case eFrameType::KR00: { - ReadKr00FramesAsCompressed(pAnimationSequence, cFrames); + if (isANPK) + ReadKr00FramesUncompressed(pAnimationSequence, cFrames); + else + ReadKr00FramesAsCompressed(pAnimationSequence, cFrames); + break; } case eFrameType::KR00_COMPRESSED: @@ -373,6 +380,20 @@ void CClientIFP::ReadKeyFramesAsCompressed(std::unique_ptr& } } +void CClientIFP::ReadKrtsFramesUncompessed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) +{ + for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) + { + SKrt0* krt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrt0))); + SKrts Krts; + ReadBuffer(&Krts); + + krt0->Rotation = Krts.Rotation; + krt0->Time = Krts.Time; + krt0->Translation = Krts.Translation; + } +} + void CClientIFP::ReadKrtsFramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) { for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) @@ -392,6 +413,20 @@ void CClientIFP::ReadKrtsFramesAsCompressed(std::unique_ptr& } } +void CClientIFP::ReadKrt0FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) +{ + for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) + { + SKrt0* frameKrt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrt0))); + SKrt0 Krt0; + ReadBuffer(&Krt0); + + frameKrt0->Rotation = Krt0.Rotation; + frameKrt0->Time = Krt0.Time; + frameKrt0->Translation = Krt0.Translation; + } +} + void CClientIFP::ReadKrt0FramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) { for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) @@ -411,6 +446,19 @@ void CClientIFP::ReadKrt0FramesAsCompressed(std::unique_ptr& } } +void CClientIFP::ReadKr00FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) +{ + for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) + { + SKr00* frameKr00 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKr00))); + SKr00 Kr00; + ReadBuffer(&Kr00); + + frameKr00->Rotation = Kr00.Rotation; + frameKr00->Time = Kr00.Time; + } +} + void CClientIFP::ReadKr00FramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) { for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) @@ -427,21 +475,21 @@ void CClientIFP::ReadKr00FramesAsCompressed(std::unique_ptr& } } -size_t CClientIFP::GetSizeOfCompressedFrame(eFrameType iFrameType) +size_t CClientIFP::GetSizeOfCompressedFrame(eFrameType iFrameType, bool isANPK) { switch (iFrameType) { case eFrameType::KRTS: { - return sizeof(SCompressed_KRT0); + return isANPK ? sizeof(SKrts) : sizeof(SCompressed_KRT0); } case eFrameType::KRT0: { - return sizeof(SCompressed_KRT0); + return isANPK ? sizeof(SKrt0) : sizeof(SCompressed_KRT0); } case eFrameType::KR00: { - return sizeof(SCompressed_KR00); + return isANPK ? sizeof(SKr00) : sizeof(SCompressed_KR00); } case eFrameType::KR00_COMPRESSED: { @@ -456,13 +504,13 @@ size_t CClientIFP::GetSizeOfCompressedFrame(eFrameType iFrameType) } void CClientIFP::InitializeAnimationHierarchy(std::unique_ptr& pAnimationHierarchy, const SString& strAnimationName, - const std::int32_t& iSequences) + const std::int32_t& iSequences, bool isANPK) { pAnimationHierarchy->Initialize(); pAnimationHierarchy->SetName(strAnimationName); pAnimationHierarchy->SetNumSequences(static_cast(iSequences)); pAnimationHierarchy->SetAnimationBlockID(-1); - pAnimationHierarchy->SetRunningCompressed(m_kbAllKeyFramesCompressed); + pAnimationHierarchy->SetRunningCompressed(m_kbAllKeyFramesCompressed && !isANPK, isANPK); } void CClientIFP::InitializeAnimationSequence(std::unique_ptr& pAnimationSequence, const SString& strName, const std::int32_t& iBoneID) @@ -481,7 +529,7 @@ void CClientIFP::PreProcessAnimationHierarchy(std::unique_ptr& pAnimationHierarchy, SequenceMapType& mapOfSequences) +void CClientIFP::MoveSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, SequenceMapType& mapOfSequences, bool isANPK) { for (size_t SequenceIndex = 0; SequenceIndex < m_kcIFPSequences; SequenceIndex++) { @@ -500,7 +548,7 @@ void CClientIFP::MoveSequencesWithDummies(std::unique_ptr& } else { - InsertAnimationDummySequence(pAnimationSequence, BoneName, BoneID); + InsertAnimationDummySequence(pAnimationSequence, BoneName, BoneID, isANPK); } } } @@ -529,7 +577,7 @@ CClientIFP::eFrameType CClientIFP::GetFrameTypeFromFourCC(const char* szFourCC) return eFrameType::UNKNOWN_FRAME; } -void CClientIFP::InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID) +void CClientIFP::InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isANPK) { InitializeAnimationSequence(pAnimationSequence, BoneName, dwBoneID); @@ -539,18 +587,18 @@ void CClientIFP::InsertAnimationDummySequence(std::unique_ptrAllocateKeyFramesMemory(FramesDataSizeInBytes); - pAnimationSequence->SetKeyFrames(cKeyFrames, bHasTranslationValues, m_kbAllKeyFramesCompressed, pKeyFrames); + pAnimationSequence->SetKeyFrames(cKeyFrames, bHasTranslationValues, m_kbAllKeyFramesCompressed && !isANPK, pKeyFrames); CopyDummyKeyFrameByBoneID(pKeyFrames, dwBoneID); } diff --git a/Client/mods/deathmatch/logic/CClientIFP.h b/Client/mods/deathmatch/logic/CClientIFP.h index b1b71254492..650bd98e06f 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.h +++ b/Client/mods/deathmatch/logic/CClientIFP.h @@ -223,7 +223,7 @@ class CClientIFP final : public CClientEntity, CFileReader void ReadIFPVersion1(); void ReadIFPVersion2(bool bAnp3); - WORD ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy); + WORD ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, bool isANPK = false); WORD ReadSequences(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences); WORD ReadSequencesVersion1(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences); WORD ReadSequencesVersion2(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences); @@ -236,8 +236,13 @@ class CClientIFP final : public CClientEntity, CFileReader CClientIFP::eFrameType ReadKfrm(); void ReadAnimationHeaderVersion2(SAnimationHeaderV2& AnimationNode, bool bAnp3); - bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool loadUncompressed = false); - void ReadKeyFramesAsCompressed(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames); + bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK = false); + void ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK = false); + + void ReadKrtsFramesUncompessed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); + void ReadKrt0FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); + void ReadKr00FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); + void ReadKrtsFramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); void ReadKrt0FramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); void ReadKr00FramesAsCompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); @@ -251,14 +256,14 @@ class CClientIFP final : public CClientEntity, CFileReader } void InitializeAnimationHierarchy(std::unique_ptr& pAnimationHierarchy, const SString& strAnimationName, - const std::int32_t& iSequences); + const std::int32_t& iSequences, bool isANPK = false); void InitializeAnimationSequence(std::unique_ptr& pAnimationSequence, const SString& strName, const std::int32_t& iBoneID); void PreProcessAnimationHierarchy(std::unique_ptr& pAnimationHierarchy); void MoveSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, - std::map>& mapOfSequences); + std::map>& mapOfSequences, bool isANPK = false); BYTE* AllocateSequencesMemory(std::unique_ptr& pAnimationHierarchy); - void InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID); + void InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isANPK = false); void CopyDummyKeyFrameByBoneID(BYTE* pKeyFrames, DWORD dwBoneID); SString ConvertStringToKey(const SString& strBoneName); @@ -266,7 +271,7 @@ class CClientIFP final : public CClientEntity, CFileReader constexpr bool IsKeyFramesTypeRoot(eFrameType iFrameType); eFrameType GetFrameTypeFromFourCC(const char* szFourCC); - size_t GetSizeOfCompressedFrame(eFrameType FrameType); + size_t GetSizeOfCompressedFrame(eFrameType FrameType, bool isANPK = false); std::int32_t GetBoneIDFromName(const SString& strBoneName); SString GetCorrectBoneNameFromName(const SString& strBoneName); SString GetCorrectBoneNameFromID(const std::int32_t& iBoneID); diff --git a/Client/sdk/game/CAnimBlendHierarchy.h b/Client/sdk/game/CAnimBlendHierarchy.h index 72c7d3abecf..45a478b2725 100644 --- a/Client/sdk/game/CAnimBlendHierarchy.h +++ b/Client/sdk/game/CAnimBlendHierarchy.h @@ -21,7 +21,7 @@ class CAnimBlendHierarchy virtual void SetName(const char* szName) = 0; virtual void SetSequences(CAnimBlendSequenceSAInterface* pSequences) = 0; virtual void SetNumSequences(unsigned short uNumSequences) = 0; - virtual void SetRunningCompressed(bool bCompressed) = 0; + virtual void SetRunningCompressed(bool bCompressed, bool isANPK) = 0; virtual void SetAnimationBlockID(int iBlockID) = 0; virtual void RemoveAnimSequences() = 0; virtual void RemoveFromUncompressedCache() = 0; diff --git a/Client/sdk/game/CRenderWare.h b/Client/sdk/game/CRenderWare.h index e05c44abc71..bccf847df01 100644 --- a/Client/sdk/game/CRenderWare.h +++ b/Client/sdk/game/CRenderWare.h @@ -132,6 +132,13 @@ class CRenderWare virtual RwFrame* GetFrameFromName(RpClump* pRoot, SString strName) = 0; virtual bool RightSizeTxd(const SString& strInTxdFilename, const SString& strOutTxdFilename, unsigned int uiSizeLimit) = 0; virtual void TxdForceUnload(unsigned short usTxdId, bool bDestroyTextures) = 0; +<<<<<<< HEAD +======= + virtual RpAtomic* GetFirstAtomic(RpClump* clump) = 0; + + virtual std::uint32_t RpGeometryGet2dFxCount(RpGeometry* geometry) = 0; + virtual RpAtomic* Get2DEffectAtomic(RpClump* clump) = 0; +>>>>>>> 6b784a49d (Read frame data) virtual void CMatrixToRwMatrix(const CMatrix& mat, RwMatrix& rwOutMatrix) = 0; virtual void RwMatrixToCMatrix(const RwMatrix& rwMatrix, CMatrix& matOut) = 0; From 15158024f10efc8e3b1c3eea809ef457eeab321b Mon Sep 17 00:00:00 2001 From: FileEX Date: Mon, 12 Jan 2026 03:23:49 +0100 Subject: [PATCH 3/8] New argument to engineLoadIFP --- Client/mods/deathmatch/logic/CClientIFP.cpp | 82 +++++++++++-------- Client/mods/deathmatch/logic/CClientIFP.h | 23 +++--- Client/mods/deathmatch/logic/CIFPEngine.cpp | 4 +- Client/mods/deathmatch/logic/CIFPEngine.h | 2 +- .../logic/luadefs/CLuaEngineDefs.cpp | 4 +- 5 files changed, 65 insertions(+), 50 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientIFP.cpp b/Client/mods/deathmatch/logic/CClientIFP.cpp index a410d1e5d10..c4900f542b7 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.cpp +++ b/Client/mods/deathmatch/logic/CClientIFP.cpp @@ -39,10 +39,11 @@ void CClientIFP::Unlink() } } -bool CClientIFP::Load(SString blockName, bool isRawData, SString input) +bool CClientIFP::Load(SString blockName, bool isRawData, SString input, std::vector&& uncompressedAnims) { m_strBlockName = std::move(blockName); m_pVecAnimations = &m_pIFPAnimations->vecAnimations; + m_uncompressedAnimations = std::move(uncompressedAnims); if (isRawData) { @@ -110,12 +111,14 @@ void CClientIFP::ReadIFPVersion1() ReadDgan(Dgan); Animation.pHierarchy = m_pAnimManager->GetCustomAnimBlendHierarchy(); - InitializeAnimationHierarchy(Animation.pHierarchy, Animation.Name, Dgan.Info.Entries, true); + + bool isUncompressed = std::find(m_uncompressedAnimations.begin(), m_uncompressedAnimations.end(), Animation.Name) != m_uncompressedAnimations.end(); + InitializeAnimationHierarchy(Animation.pHierarchy, Animation.Name, Dgan.Info.Entries, isUncompressed); Animation.pSequencesMemory = AllocateSequencesMemory(Animation.pHierarchy); Animation.pHierarchy->SetSequences(reinterpret_cast(Animation.pSequencesMemory + 4)); - *(DWORD*)Animation.pSequencesMemory = ReadSequencesWithDummies(Animation.pHierarchy, true); + *(DWORD*)Animation.pSequencesMemory = ReadSequencesWithDummies(Animation.pHierarchy, isUncompressed); PreProcessAnimationHierarchy(Animation.pHierarchy); } } @@ -144,12 +147,12 @@ void CClientIFP::ReadIFPVersion2(bool bAnp3) } } -WORD CClientIFP::ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, bool isANPK) +WORD CClientIFP::ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, bool isUncompressed) { SequenceMapType MapOfSequences; - WORD wUnknownSequences = ReadSequences(pAnimationHierarchy, MapOfSequences); + WORD wUnknownSequences = ReadSequences(pAnimationHierarchy, MapOfSequences, isUncompressed); - MoveSequencesWithDummies(pAnimationHierarchy, MapOfSequences, isANPK); + MoveSequencesWithDummies(pAnimationHierarchy, MapOfSequences, isUncompressed); WORD cSequences = m_kcIFPSequences + wUnknownSequences; // As we need support for all 32 bones, we must change the total sequences count @@ -157,16 +160,16 @@ WORD CClientIFP::ReadSequencesWithDummies(std::unique_ptr& return cSequences; } -WORD CClientIFP::ReadSequences(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences) +WORD CClientIFP::ReadSequences(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences, bool isUncompressed) { if (m_bVersion1) { - return ReadSequencesVersion1(pAnimationHierarchy, MapOfSequences); + return ReadSequencesVersion1(pAnimationHierarchy, MapOfSequences, isUncompressed); } return ReadSequencesVersion2(pAnimationHierarchy, MapOfSequences); } -WORD CClientIFP::ReadSequencesVersion1(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences) +WORD CClientIFP::ReadSequencesVersion1(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences, bool isUncompressed) { WORD wUnknownSequences = 0; for (size_t SequenceIndex = 0; SequenceIndex < pAnimationHierarchy->GetNumSequences(); SequenceIndex++) @@ -194,7 +197,7 @@ WORD CClientIFP::ReadSequencesVersion1(std::unique_ptr& pAn InitializeAnimationSequence(pAnimationSequence, Anim.Name, iBoneID); eFrameType iFrameType = ReadKfrm(); - if ((ReadSequenceKeyFrames(pAnimationSequence, iFrameType, Anim.Frames, true)) && (!bUnknownSequence)) + if ((ReadSequenceKeyFrames(pAnimationSequence, iFrameType, Anim.Frames, isUncompressed)) && (!bUnknownSequence)) { MapOfSequences[iBoneID] = std::move(pAnimationSequence); } @@ -274,14 +277,14 @@ void CClientIFP::ReadSequenceVersion2(SSequenceHeaderV2& ObjectNode) strncpy(ObjectNode.Name, strCorrectBoneName, strCorrectBoneName.size() + 1); } -bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK) +bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed) { - size_t iCompressedFrameSize = GetSizeOfCompressedFrame(iFrameType, isANPK); + size_t iCompressedFrameSize = GetSizeOfCompressedFrame(iFrameType, isUncompressed); if (iCompressedFrameSize) { BYTE* pKeyFrames = m_pAnimManager->AllocateKeyFramesMemory(iCompressedFrameSize * cFrames); - pAnimationSequence->SetKeyFrames(cFrames, IsKeyFramesTypeRoot(iFrameType), m_kbAllKeyFramesCompressed && !isANPK, pKeyFrames); - ReadKeyFrames(pAnimationSequence, iFrameType, cFrames, isANPK); + pAnimationSequence->SetKeyFrames(cFrames, IsKeyFramesTypeRoot(iFrameType), m_kbAllKeyFramesCompressed && !isUncompressed, pKeyFrames); + ReadKeyFrames(pAnimationSequence, iFrameType, cFrames, isUncompressed); return true; } @@ -336,14 +339,14 @@ void CClientIFP::ReadAnimationHeaderVersion2(SAnimationHeaderV2& AnimationNode, } } -void CClientIFP::ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK) +void CClientIFP::ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed) { switch (iFrameType) { case eFrameType::KRTS: { - if (isANPK) - ReadKrtsFramesUncompessed(pAnimationSequence, cFrames); + if (isUncompressed) + ReadKrtsFramesUncompressed(pAnimationSequence, cFrames); else ReadKrtsFramesAsCompressed(pAnimationSequence, cFrames); @@ -351,7 +354,7 @@ void CClientIFP::ReadKeyFrames(std::unique_ptr& pAnimationSe } case eFrameType::KRT0: { - if (isANPK) + if (isUncompressed) ReadKrt0FramesUncompressed(pAnimationSequence, cFrames); else ReadKrt0FramesAsCompressed(pAnimationSequence, cFrames); @@ -360,7 +363,7 @@ void CClientIFP::ReadKeyFrames(std::unique_ptr& pAnimationSe } case eFrameType::KR00: { - if (isANPK) + if (isUncompressed) ReadKr00FramesUncompressed(pAnimationSequence, cFrames); else ReadKr00FramesAsCompressed(pAnimationSequence, cFrames); @@ -380,7 +383,7 @@ void CClientIFP::ReadKeyFrames(std::unique_ptr& pAnimationSe } } -void CClientIFP::ReadKrtsFramesUncompessed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) +void CClientIFP::ReadKrtsFramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames) { for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) { @@ -388,7 +391,10 @@ void CClientIFP::ReadKrtsFramesUncompessed(std::unique_ptr& SKrts Krts; ReadBuffer(&Krts); - krt0->Rotation = Krts.Rotation; + krt0->Rotation.X = -Krts.Rotation.X; + krt0->Rotation.Y = -Krts.Rotation.Y; + krt0->Rotation.Z = -Krts.Rotation.Z; + krt0->Rotation.W = Krts.Rotation.W; krt0->Time = Krts.Time; krt0->Translation = Krts.Translation; } @@ -421,7 +427,10 @@ void CClientIFP::ReadKrt0FramesUncompressed(std::unique_ptr& SKrt0 Krt0; ReadBuffer(&Krt0); - frameKrt0->Rotation = Krt0.Rotation; + frameKrt0->Rotation.X = -Krt0.Rotation.X; + frameKrt0->Rotation.Y = -Krt0.Rotation.Y; + frameKrt0->Rotation.Z = -Krt0.Rotation.Z; + frameKrt0->Rotation.W = Krt0.Rotation.W; frameKrt0->Time = Krt0.Time; frameKrt0->Translation = Krt0.Translation; } @@ -454,7 +463,10 @@ void CClientIFP::ReadKr00FramesUncompressed(std::unique_ptr& SKr00 Kr00; ReadBuffer(&Kr00); - frameKr00->Rotation = Kr00.Rotation; + frameKr00->Rotation.X = -Kr00.Rotation.X; + frameKr00->Rotation.Y = -Kr00.Rotation.Y; + frameKr00->Rotation.Z = -Kr00.Rotation.Z; + frameKr00->Rotation.W = Kr00.Rotation.W; frameKr00->Time = Kr00.Time; } } @@ -475,21 +487,21 @@ void CClientIFP::ReadKr00FramesAsCompressed(std::unique_ptr& } } -size_t CClientIFP::GetSizeOfCompressedFrame(eFrameType iFrameType, bool isANPK) +size_t CClientIFP::GetSizeOfCompressedFrame(eFrameType iFrameType, bool isUncompressed) { switch (iFrameType) { case eFrameType::KRTS: { - return isANPK ? sizeof(SKrts) : sizeof(SCompressed_KRT0); + return isUncompressed ? sizeof(SKrts) : sizeof(SCompressed_KRT0); } case eFrameType::KRT0: { - return isANPK ? sizeof(SKrt0) : sizeof(SCompressed_KRT0); + return isUncompressed ? sizeof(SKrt0) : sizeof(SCompressed_KRT0); } case eFrameType::KR00: { - return isANPK ? sizeof(SKr00) : sizeof(SCompressed_KR00); + return isUncompressed ? sizeof(SKr00) : sizeof(SCompressed_KR00); } case eFrameType::KR00_COMPRESSED: { @@ -504,13 +516,13 @@ size_t CClientIFP::GetSizeOfCompressedFrame(eFrameType iFrameType, bool isANPK) } void CClientIFP::InitializeAnimationHierarchy(std::unique_ptr& pAnimationHierarchy, const SString& strAnimationName, - const std::int32_t& iSequences, bool isANPK) + const std::int32_t& iSequences, bool isUncompressed) { pAnimationHierarchy->Initialize(); pAnimationHierarchy->SetName(strAnimationName); pAnimationHierarchy->SetNumSequences(static_cast(iSequences)); pAnimationHierarchy->SetAnimationBlockID(-1); - pAnimationHierarchy->SetRunningCompressed(m_kbAllKeyFramesCompressed && !isANPK, isANPK); + pAnimationHierarchy->SetRunningCompressed(m_kbAllKeyFramesCompressed && !isUncompressed, isUncompressed); } void CClientIFP::InitializeAnimationSequence(std::unique_ptr& pAnimationSequence, const SString& strName, const std::int32_t& iBoneID) @@ -529,7 +541,7 @@ void CClientIFP::PreProcessAnimationHierarchy(std::unique_ptr& pAnimationHierarchy, SequenceMapType& mapOfSequences, bool isANPK) +void CClientIFP::MoveSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, SequenceMapType& mapOfSequences, bool isUncompressed) { for (size_t SequenceIndex = 0; SequenceIndex < m_kcIFPSequences; SequenceIndex++) { @@ -548,7 +560,7 @@ void CClientIFP::MoveSequencesWithDummies(std::unique_ptr& } else { - InsertAnimationDummySequence(pAnimationSequence, BoneName, BoneID, isANPK); + InsertAnimationDummySequence(pAnimationSequence, BoneName, BoneID, isUncompressed); } } } @@ -577,7 +589,7 @@ CClientIFP::eFrameType CClientIFP::GetFrameTypeFromFourCC(const char* szFourCC) return eFrameType::UNKNOWN_FRAME; } -void CClientIFP::InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isANPK) +void CClientIFP::InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isUncompressed) { InitializeAnimationSequence(pAnimationSequence, BoneName, dwBoneID); @@ -587,18 +599,18 @@ void CClientIFP::InsertAnimationDummySequence(std::unique_ptrAllocateKeyFramesMemory(FramesDataSizeInBytes); - pAnimationSequence->SetKeyFrames(cKeyFrames, bHasTranslationValues, m_kbAllKeyFramesCompressed && !isANPK, pKeyFrames); + pAnimationSequence->SetKeyFrames(cKeyFrames, bHasTranslationValues, m_kbAllKeyFramesCompressed && !isUncompressed, pKeyFrames); CopyDummyKeyFrameByBoneID(pKeyFrames, dwBoneID); } diff --git a/Client/mods/deathmatch/logic/CClientIFP.h b/Client/mods/deathmatch/logic/CClientIFP.h index 650bd98e06f..e019f321559 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.h +++ b/Client/mods/deathmatch/logic/CClientIFP.h @@ -205,7 +205,7 @@ class CClientIFP final : public CClientEntity, CFileReader void MarkAsUnloading() { m_bUnloading = true; } bool IsUnloading() { return m_bUnloading; } - bool Load(SString blockName, bool isRawData, SString input); + bool Load(SString blockName, bool isRawData, SString input, std::vector&& uncompressedAnims); const SString& GetBlockName() { return m_strBlockName; } const unsigned int& GetBlockNameHash() { return m_u32Hashkey; } @@ -223,9 +223,9 @@ class CClientIFP final : public CClientEntity, CFileReader void ReadIFPVersion1(); void ReadIFPVersion2(bool bAnp3); - WORD ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, bool isANPK = false); - WORD ReadSequences(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences); - WORD ReadSequencesVersion1(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences); + WORD ReadSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, bool isUncompressed = false); + WORD ReadSequences(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences, bool isUncompressed = false); + WORD ReadSequencesVersion1(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences, bool isUncompressed = false); WORD ReadSequencesVersion2(std::unique_ptr& pAnimationHierarchy, SequenceMapType& MapOfSequences); std::int32_t ReadSequenceVersion1(SAnim& Anim); void ReadSequenceVersion2(SSequenceHeaderV2& ObjectNode); @@ -236,10 +236,10 @@ class CClientIFP final : public CClientEntity, CFileReader CClientIFP::eFrameType ReadKfrm(); void ReadAnimationHeaderVersion2(SAnimationHeaderV2& AnimationNode, bool bAnp3); - bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK = false); - void ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isANPK = false); + bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed = false); + void ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed = false); - void ReadKrtsFramesUncompessed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); + void ReadKrtsFramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); void ReadKrt0FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); void ReadKr00FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); @@ -256,14 +256,14 @@ class CClientIFP final : public CClientEntity, CFileReader } void InitializeAnimationHierarchy(std::unique_ptr& pAnimationHierarchy, const SString& strAnimationName, - const std::int32_t& iSequences, bool isANPK = false); + const std::int32_t& iSequences, bool isUncompressed = false); void InitializeAnimationSequence(std::unique_ptr& pAnimationSequence, const SString& strName, const std::int32_t& iBoneID); void PreProcessAnimationHierarchy(std::unique_ptr& pAnimationHierarchy); void MoveSequencesWithDummies(std::unique_ptr& pAnimationHierarchy, - std::map>& mapOfSequences, bool isANPK = false); + std::map>& mapOfSequences, bool isUncompressed = false); BYTE* AllocateSequencesMemory(std::unique_ptr& pAnimationHierarchy); - void InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isANPK = false); + void InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isUncompressed = false); void CopyDummyKeyFrameByBoneID(BYTE* pKeyFrames, DWORD dwBoneID); SString ConvertStringToKey(const SString& strBoneName); @@ -271,7 +271,7 @@ class CClientIFP final : public CClientEntity, CFileReader constexpr bool IsKeyFramesTypeRoot(eFrameType iFrameType); eFrameType GetFrameTypeFromFourCC(const char* szFourCC); - size_t GetSizeOfCompressedFrame(eFrameType FrameType, bool isANPK = false); + size_t GetSizeOfCompressedFrame(eFrameType FrameType, bool isUncompressed = false); std::int32_t GetBoneIDFromName(const SString& strBoneName); SString GetCorrectBoneNameFromName(const SString& strBoneName); SString GetCorrectBoneNameFromID(const std::int32_t& iBoneID); @@ -283,6 +283,7 @@ class CClientIFP final : public CClientEntity, CFileReader bool m_bVersion1; bool m_bUnloading; CAnimManager* m_pAnimManager; + std::vector m_uncompressedAnimations; // 32 because there are 32 bones in a ped model const unsigned short m_kcIFPSequences = 32; diff --git a/Client/mods/deathmatch/logic/CIFPEngine.cpp b/Client/mods/deathmatch/logic/CIFPEngine.cpp index 44cfbdd4107..f5b34bb91a1 100644 --- a/Client/mods/deathmatch/logic/CIFPEngine.cpp +++ b/Client/mods/deathmatch/logic/CIFPEngine.cpp @@ -12,7 +12,7 @@ #include #include -std::shared_ptr CIFPEngine::LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input) +std::shared_ptr CIFPEngine::LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input, std::vector&& uncompressedAnims) { // Grab the resource root entity const unsigned int u32BlockNameHash = HashString(blockName.ToLower()); @@ -24,7 +24,7 @@ std::shared_ptr CIFPEngine::LoadIFP(CResource* resource, CClientMana std::shared_ptr pIFP(new CClientIFP(clientManager, INVALID_ELEMENT_ID)); // Try to load the IFP file - if (pIFP->Load(blockName, isRawInput, std::move(input))) + if (pIFP->Load(blockName, isRawInput, std::move(input), std::move(uncompressedAnims))) { // We can use the map to retrieve correct IFP by block name later g_pClientGame->InsertIFPPointerToMap(u32BlockNameHash, pIFP); diff --git a/Client/mods/deathmatch/logic/CIFPEngine.h b/Client/mods/deathmatch/logic/CIFPEngine.h index 9b2f5af57ed..29afb96f365 100644 --- a/Client/mods/deathmatch/logic/CIFPEngine.h +++ b/Client/mods/deathmatch/logic/CIFPEngine.h @@ -23,7 +23,7 @@ class CIFPEngine ALL }; - static std::shared_ptr LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input); + static std::shared_ptr LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input, std::vector&& uncompressedAnims); static bool EngineReplaceAnimation(CClientEntity* pEntity, const SString& strInternalBlockName, const SString& strInternalAnimName, const SString& strCustomBlockName, const SString& strCustomAnimName); static bool EngineRestoreAnimation(CClientEntity* pEntity, const SString& strInternalBlockName, const SString& strInternalAnimName, diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 8d9bc6ece59..84d7ceb6a7d 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -526,11 +526,13 @@ int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM) { SString input; SString blockName; + std::vector uncompressedAnims; CScriptArgReader argStream(luaVM); // Grab the IFP filename or data argStream.ReadString(input); argStream.ReadString(blockName); + argStream.ReadStringTable(uncompressedAnims); if (!argStream.HasErrors()) { @@ -559,7 +561,7 @@ int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM) if (bIsRawData || CResourceManager::ParseResourcePathInput(input, pResource, &filePath)) { std::shared_ptr pIFP = - CIFPEngine::LoadIFP(pResource, m_pManager, std::move(blockName), bIsRawData, bIsRawData ? std::move(input) : std::move(filePath)); + CIFPEngine::LoadIFP(pResource, m_pManager, std::move(blockName), bIsRawData, bIsRawData ? std::move(input) : std::move(filePath), std::move(uncompressedAnims)); if (pIFP) { From f69de8fc1dc81ff1fb06e4ecaa035306fcd9327c Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 24 Jan 2026 22:09:26 +0100 Subject: [PATCH 4/8] Fix memory structs (freeze) --- Client/mods/deathmatch/logic/CClientIFP.cpp | 4 ++-- Client/mods/deathmatch/logic/CClientIFP.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientIFP.cpp b/Client/mods/deathmatch/logic/CClientIFP.cpp index c4900f542b7..8fbd8329259 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.cpp +++ b/Client/mods/deathmatch/logic/CClientIFP.cpp @@ -387,7 +387,7 @@ void CClientIFP::ReadKrtsFramesUncompressed(std::unique_ptr& { for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) { - SKrt0* krt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrt0))); + SKrts_Memory* krt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrts_Memory))); SKrts Krts; ReadBuffer(&Krts); @@ -423,7 +423,7 @@ void CClientIFP::ReadKrt0FramesUncompressed(std::unique_ptr& { for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) { - SKrt0* frameKrt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrt0))); + SKrt0_Memory* frameKrt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrt0_Memory))); SKrt0 Krt0; ReadBuffer(&Krt0); diff --git a/Client/mods/deathmatch/logic/CClientIFP.h b/Client/mods/deathmatch/logic/CClientIFP.h index e019f321559..0db459c46b4 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.h +++ b/Client/mods/deathmatch/logic/CClientIFP.h @@ -108,6 +108,21 @@ class CClientIFP final : public CClientEntity, CFileReader float Time; }; + struct SKrt0_Memory + { + SQuaternion Rotation; + float Time; + SVector Translation; + }; + + struct SKrts_Memory + { + SQuaternion Rotation; + float Time; + SVector Translation; + SVector Scale; + }; + struct SCompressedQuaternion { std::int16_t X, Y, Z, W; From 8706b31edb6da4ffb6c44088072842e87aaf65c0 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 25 Jan 2026 00:54:29 +0100 Subject: [PATCH 5/8] Comments --- Client/mods/deathmatch/logic/CClientIFP.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientIFP.h b/Client/mods/deathmatch/logic/CClientIFP.h index 0db459c46b4..66ee03a1bad 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.h +++ b/Client/mods/deathmatch/logic/CClientIFP.h @@ -87,12 +87,13 @@ class CClientIFP final : public CClientEntity, CFileReader float X, Y, Z; }; - struct SKr00 + struct SKr00 // CAnimBlendKeyFrameNoTrans { SQuaternion Rotation; float Time; }; + // Structues used for reading IFP files struct SKrt0 { SQuaternion Rotation; @@ -104,11 +105,12 @@ class CClientIFP final : public CClientEntity, CFileReader { SQuaternion Rotation; SVector Translation; - SVector Scale; + SVector Scale; // unused float Time; }; - struct SKrt0_Memory + // Structures used by GTA SA (time is always at 0x10 offset for uncompressed anims) + struct SKrt0_Memory // CAnimBlendKeyFrame { SQuaternion Rotation; float Time; @@ -120,7 +122,7 @@ class CClientIFP final : public CClientEntity, CFileReader SQuaternion Rotation; float Time; SVector Translation; - SVector Scale; + SVector Scale; // unused }; struct SCompressedQuaternion From bf3b9c2be255d390f7a1d78d619dc6468c373342 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 25 Jan 2026 00:57:46 +0100 Subject: [PATCH 6/8] Fix CRenderWare.h conflict --- Client/sdk/game/CRenderWare.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Client/sdk/game/CRenderWare.h b/Client/sdk/game/CRenderWare.h index bccf847df01..e05c44abc71 100644 --- a/Client/sdk/game/CRenderWare.h +++ b/Client/sdk/game/CRenderWare.h @@ -132,13 +132,6 @@ class CRenderWare virtual RwFrame* GetFrameFromName(RpClump* pRoot, SString strName) = 0; virtual bool RightSizeTxd(const SString& strInTxdFilename, const SString& strOutTxdFilename, unsigned int uiSizeLimit) = 0; virtual void TxdForceUnload(unsigned short usTxdId, bool bDestroyTextures) = 0; -<<<<<<< HEAD -======= - virtual RpAtomic* GetFirstAtomic(RpClump* clump) = 0; - - virtual std::uint32_t RpGeometryGet2dFxCount(RpGeometry* geometry) = 0; - virtual RpAtomic* Get2DEffectAtomic(RpClump* clump) = 0; ->>>>>>> 6b784a49d (Read frame data) virtual void CMatrixToRwMatrix(const CMatrix& mat, RwMatrix& rwOutMatrix) = 0; virtual void RwMatrixToCMatrix(const RwMatrix& rwMatrix, CMatrix& matOut) = 0; From f928b7a2e73cfe75477a67b2eb7b3c4f045f55ea Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 25 Jan 2026 01:14:22 +0100 Subject: [PATCH 7/8] Make new argument optional --- Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 84d7ceb6a7d..fe4cd258f37 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -526,13 +526,15 @@ int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM) { SString input; SString blockName; - std::vector uncompressedAnims; + std::vector uncompressedAnims{}; CScriptArgReader argStream(luaVM); // Grab the IFP filename or data argStream.ReadString(input); argStream.ReadString(blockName); - argStream.ReadStringTable(uncompressedAnims); + + if (argStream.NextIsTable()) + argStream.ReadStringTable(uncompressedAnims); if (!argStream.HasErrors()) { From 4ea6101e844f6e77ef03fba73bcff5644e566d1c Mon Sep 17 00:00:00 2001 From: FileEX Date: Thu, 5 Feb 2026 22:50:11 +0100 Subject: [PATCH 8/8] clang fix --- Client/game_sa/CAnimBlendHierarchySA.h | 15 ++++++++++----- Client/mods/deathmatch/logic/CClientIFP.cpp | 10 ++++++---- Client/mods/deathmatch/logic/CClientIFP.h | 17 ++++++++++------- Client/mods/deathmatch/logic/CIFPEngine.cpp | 3 ++- Client/mods/deathmatch/logic/CIFPEngine.h | 3 ++- .../deathmatch/logic/luadefs/CLuaEngineDefs.cpp | 8 ++++---- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Client/game_sa/CAnimBlendHierarchySA.h b/Client/game_sa/CAnimBlendHierarchySA.h index 71fc9ee92c4..f96800c7a68 100644 --- a/Client/game_sa/CAnimBlendHierarchySA.h +++ b/Client/game_sa/CAnimBlendHierarchySA.h @@ -43,11 +43,16 @@ class CAnimBlendHierarchySA : public CAnimBlendHierarchy { public: CAnimBlendHierarchySA(CAnimBlendHierarchySAInterface* pInterface) { m_pInterface = pInterface; } - void Initialize(); - void SetName(const char* szName); - void SetSequences(CAnimBlendSequenceSAInterface* pSequences) { m_pInterface->pSequences = pSequences; } - void SetNumSequences(unsigned short uNumSequences) { m_pInterface->usNumSequences = uNumSequences; } - void SetRunningCompressed(bool bCompressed, bool isANPK) { m_pInterface->bRunningCompressed = bCompressed; if (isANPK && !bCompressed) m_pInterface->keepCompressed = false; } + void Initialize(); + void SetName(const char* szName); + void SetSequences(CAnimBlendSequenceSAInterface* pSequences) { m_pInterface->pSequences = pSequences; } + void SetNumSequences(unsigned short uNumSequences) { m_pInterface->usNumSequences = uNumSequences; } + void SetRunningCompressed(bool bCompressed, bool isANPK) + { + m_pInterface->bRunningCompressed = bCompressed; + if (isANPK && !bCompressed) + m_pInterface->keepCompressed = false; + } void SetAnimationBlockID(int iBlockID) { m_pInterface->iAnimBlockID = iBlockID; } void RemoveAnimSequences(); void RemoveFromUncompressedCache(); diff --git a/Client/mods/deathmatch/logic/CClientIFP.cpp b/Client/mods/deathmatch/logic/CClientIFP.cpp index 8fbd8329259..38b1c6fe41e 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.cpp +++ b/Client/mods/deathmatch/logic/CClientIFP.cpp @@ -277,7 +277,8 @@ void CClientIFP::ReadSequenceVersion2(SSequenceHeaderV2& ObjectNode) strncpy(ObjectNode.Name, strCorrectBoneName, strCorrectBoneName.size() + 1); } -bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed) +bool CClientIFP::ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, + bool isUncompressed) { size_t iCompressedFrameSize = GetSizeOfCompressedFrame(iFrameType, isUncompressed); if (iCompressedFrameSize) @@ -388,7 +389,7 @@ void CClientIFP::ReadKrtsFramesUncompressed(std::unique_ptr& for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) { SKrts_Memory* krt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrts_Memory))); - SKrts Krts; + SKrts Krts; ReadBuffer(&Krts); krt0->Rotation.X = -Krts.Rotation.X; @@ -424,7 +425,7 @@ void CClientIFP::ReadKrt0FramesUncompressed(std::unique_ptr& for (std::int32_t FrameIndex = 0; FrameIndex < cFrames; FrameIndex++) { SKrt0_Memory* frameKrt0 = static_cast(pAnimationSequence->GetKeyFrame(FrameIndex, sizeof(SKrt0_Memory))); - SKrt0 Krt0; + SKrt0 Krt0; ReadBuffer(&Krt0); frameKrt0->Rotation.X = -Krt0.Rotation.X; @@ -589,7 +590,8 @@ CClientIFP::eFrameType CClientIFP::GetFrameTypeFromFourCC(const char* szFourCC) return eFrameType::UNKNOWN_FRAME; } -void CClientIFP::InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isUncompressed) +void CClientIFP::InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, + bool isUncompressed) { InitializeAnimationSequence(pAnimationSequence, BoneName, dwBoneID); diff --git a/Client/mods/deathmatch/logic/CClientIFP.h b/Client/mods/deathmatch/logic/CClientIFP.h index 66ee03a1bad..60ba04ec6b3 100644 --- a/Client/mods/deathmatch/logic/CClientIFP.h +++ b/Client/mods/deathmatch/logic/CClientIFP.h @@ -87,7 +87,7 @@ class CClientIFP final : public CClientEntity, CFileReader float X, Y, Z; }; - struct SKr00 // CAnimBlendKeyFrameNoTrans + struct SKr00 // CAnimBlendKeyFrameNoTrans { SQuaternion Rotation; float Time; @@ -105,12 +105,12 @@ class CClientIFP final : public CClientEntity, CFileReader { SQuaternion Rotation; SVector Translation; - SVector Scale; // unused + SVector Scale; // unused float Time; }; // Structures used by GTA SA (time is always at 0x10 offset for uncompressed anims) - struct SKrt0_Memory // CAnimBlendKeyFrame + struct SKrt0_Memory // CAnimBlendKeyFrame { SQuaternion Rotation; float Time; @@ -122,7 +122,7 @@ class CClientIFP final : public CClientEntity, CFileReader SQuaternion Rotation; float Time; SVector Translation; - SVector Scale; // unused + SVector Scale; // unused }; struct SCompressedQuaternion @@ -253,8 +253,10 @@ class CClientIFP final : public CClientEntity, CFileReader CClientIFP::eFrameType ReadKfrm(); void ReadAnimationHeaderVersion2(SAnimationHeaderV2& AnimationNode, bool bAnp3); - bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed = false); - void ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, bool isUncompressed = false); + bool ReadSequenceKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, + bool isUncompressed = false); + void ReadKeyFrames(std::unique_ptr& pAnimationSequence, eFrameType iFrameType, const std::int32_t& cFrames, + bool isUncompressed = false); void ReadKrtsFramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); void ReadKrt0FramesUncompressed(std::unique_ptr& pAnimationSequence, const std::int32_t& cFrames); @@ -280,7 +282,8 @@ class CClientIFP final : public CClientEntity, CFileReader std::map>& mapOfSequences, bool isUncompressed = false); BYTE* AllocateSequencesMemory(std::unique_ptr& pAnimationHierarchy); - void InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, bool isUncompressed = false); + void InsertAnimationDummySequence(std::unique_ptr& pAnimationSequence, const SString& BoneName, const DWORD& dwBoneID, + bool isUncompressed = false); void CopyDummyKeyFrameByBoneID(BYTE* pKeyFrames, DWORD dwBoneID); SString ConvertStringToKey(const SString& strBoneName); diff --git a/Client/mods/deathmatch/logic/CIFPEngine.cpp b/Client/mods/deathmatch/logic/CIFPEngine.cpp index f5b34bb91a1..e706dc6eeb2 100644 --- a/Client/mods/deathmatch/logic/CIFPEngine.cpp +++ b/Client/mods/deathmatch/logic/CIFPEngine.cpp @@ -12,7 +12,8 @@ #include #include -std::shared_ptr CIFPEngine::LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input, std::vector&& uncompressedAnims) +std::shared_ptr CIFPEngine::LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input, + std::vector&& uncompressedAnims) { // Grab the resource root entity const unsigned int u32BlockNameHash = HashString(blockName.ToLower()); diff --git a/Client/mods/deathmatch/logic/CIFPEngine.h b/Client/mods/deathmatch/logic/CIFPEngine.h index 29afb96f365..84b11437b9f 100644 --- a/Client/mods/deathmatch/logic/CIFPEngine.h +++ b/Client/mods/deathmatch/logic/CIFPEngine.h @@ -23,7 +23,8 @@ class CIFPEngine ALL }; - static std::shared_ptr LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input, std::vector&& uncompressedAnims); + static std::shared_ptr LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input, + std::vector&& uncompressedAnims); static bool EngineReplaceAnimation(CClientEntity* pEntity, const SString& strInternalBlockName, const SString& strInternalAnimName, const SString& strCustomBlockName, const SString& strCustomAnimName); static bool EngineRestoreAnimation(CClientEntity* pEntity, const SString& strInternalBlockName, const SString& strInternalAnimName, diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index fe4cd258f37..550ec94f63e 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -524,8 +524,8 @@ int CLuaEngineDefs::EngineLoadTXD(lua_State* luaVM) int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM) { - SString input; - SString blockName; + SString input; + SString blockName; std::vector uncompressedAnims{}; CScriptArgReader argStream(luaVM); @@ -562,8 +562,8 @@ int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM) // Is this a legal filepath? if (bIsRawData || CResourceManager::ParseResourcePathInput(input, pResource, &filePath)) { - std::shared_ptr pIFP = - CIFPEngine::LoadIFP(pResource, m_pManager, std::move(blockName), bIsRawData, bIsRawData ? std::move(input) : std::move(filePath), std::move(uncompressedAnims)); + std::shared_ptr pIFP = CIFPEngine::LoadIFP(pResource, m_pManager, std::move(blockName), bIsRawData, + bIsRawData ? std::move(input) : std::move(filePath), std::move(uncompressedAnims)); if (pIFP) {