diff --git a/Client/game_sa/CEntitySA.cpp b/Client/game_sa/CEntitySA.cpp index 9c76c03c603..e524e882fcc 100644 --- a/Client/game_sa/CEntitySA.cpp +++ b/Client/game_sa/CEntitySA.cpp @@ -642,13 +642,33 @@ bool CEntitySA::SetBonePosition(eBone boneId, const CVector& position) RwMatrix* rwBoneMatrix = GetBoneRwMatrix(boneId); if (!rwBoneMatrix) return false; - + CMatrixSAInterface boneMatrix(rwBoneMatrix, false); boneMatrix.SetTranslateOnly(position); boneMatrix.UpdateRW(); return true; } +bool CEntitySA::GetBoneScale(eBone boneId, CVector& scale) +{ + RwMatrix* rwBoneMatrix = GetBoneRwMatrix(boneId); + if (!rwBoneMatrix) + return false; + + pGame->GetRenderWare()->RwMatrixGetScale(*rwBoneMatrix, scale); + return true; +} + +bool CEntitySA::SetBoneScale(eBone boneId, const CVector& scale) +{ + RwMatrix* rwBoneMatrix = GetBoneRwMatrix(boneId); + if (!rwBoneMatrix) + return false; + + RwMatrixScale(rwBoneMatrix, reinterpret_cast(&scale), TRANSFORM_BEFORE); + return true; +} + BYTE CEntitySA::GetAreaCode() { return m_pInterface->m_areaCode; diff --git a/Client/game_sa/CEntitySA.h b/Client/game_sa/CEntitySA.h index 815193338ca..44ee5581e12 100644 --- a/Client/game_sa/CEntitySA.h +++ b/Client/game_sa/CEntitySA.h @@ -313,6 +313,8 @@ class CEntitySA : public virtual CEntity bool SetBoneRotationQuat(eBone boneId, float x, float y, float z, float w); bool GetBonePosition(eBone boneId, CVector& position); bool SetBonePosition(eBone boneId, const CVector& position); + bool GetBoneScale(eBone boneId, CVector& scale) override; + bool SetBoneScale(eBone boneId, const CVector& scale) override; bool IsOnFire() override { return false; } bool SetOnFire(bool onFire) override { return false; } diff --git a/Client/mods/deathmatch/logic/CClientPed.cpp b/Client/mods/deathmatch/logic/CClientPed.cpp index f0f132b732d..d19066828bb 100644 --- a/Client/mods/deathmatch/logic/CClientPed.cpp +++ b/Client/mods/deathmatch/logic/CClientPed.cpp @@ -1128,6 +1128,74 @@ CVector* CClientPed::GetTransformedBonePosition(eBone bone, CVector& vecPosition return NULL; } +bool CClientPed::SetBoneScale(eBone boneId, const CVector& scale) +{ + if (!m_pPlayerPed || boneId < BONE_ROOT || boneId > BONE_LEFTBREAST) + return false; + + m_boneScales[boneId] = scale; + m_pPlayerPed->SetBoneScale(boneId, scale); + return true; +} + +bool CClientPed::GetBoneScale(eBone boneId, CVector& scale) const +{ + auto it = m_boneScales.find(boneId); + if (it != m_boneScales.end()) + { + scale = it->second; + return true; + } + + if (!m_pPlayerPed) + return false; + + return m_pPlayerPed->GetBoneScale(boneId, scale); +} + +bool CClientPed::ResetBoneScale(eBone boneId) +{ + auto it = m_boneScales.find(boneId); + if (it == m_boneScales.end()) + return false; + + m_boneScales.erase(it); + + if (m_pPlayerPed) + m_pPlayerPed->SetBoneScale(boneId, CVector(1.0f, 1.0f, 1.0f)); + + return true; +} + +void CClientPed::ResetAllBoneScales() +{ + m_boneScales.clear(); + + if (!m_pPlayerPed) + return; + + CVector defaultScale(1.0f, 1.0f, 1.0f); + for (int i = BONE_ROOT; i <= BONE_HEAD; ++i) + m_pPlayerPed->SetBoneScale(static_cast(i), defaultScale); + for (int i = BONE_RIGHTUPPERTORSO; i <= BONE_RIGHTTHUMB; ++i) + m_pPlayerPed->SetBoneScale(static_cast(i), defaultScale); + for (int i = BONE_LEFTUPPERTORSO; i <= BONE_LEFTTHUMB; ++i) + m_pPlayerPed->SetBoneScale(static_cast(i), defaultScale); + for (int i = BONE_LEFTHIP; i <= BONE_LEFTFOOT; ++i) + m_pPlayerPed->SetBoneScale(static_cast(i), defaultScale); + for (int i = BONE_RIGHTHIP; i <= BONE_RIGHTFOOT; ++i) + m_pPlayerPed->SetBoneScale(static_cast(i), defaultScale); +} + +void CClientPed::ApplyBoneScales() +{ + if (m_boneScales.empty() || !m_pPlayerPed) + return; + + for (const auto& [bone, scale] : m_boneScales) + m_pPlayerPed->SetBoneScale(bone, scale); +} + CClientVehicle* CClientPed::GetRealOccupiedVehicle() { if (m_pPlayerPed) diff --git a/Client/mods/deathmatch/logic/CClientPed.h b/Client/mods/deathmatch/logic/CClientPed.h index e4153ee5b76..f43d97b511d 100644 --- a/Client/mods/deathmatch/logic/CClientPed.h +++ b/Client/mods/deathmatch/logic/CClientPed.h @@ -23,6 +23,8 @@ class CClientPed; #include #include +#include +#include class CAnimBlock; class CClientCamera; @@ -812,4 +814,14 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule bool m_hasSyncedAnim{}; bool m_animationOverridedByClient{}; + + // Bone scaling + std::unordered_map m_boneScales; + +public: + bool SetBoneScale(eBone boneId, const CVector& scale); + bool GetBoneScale(eBone boneId, CVector& scale) const; + bool ResetBoneScale(eBone boneId); + void ResetAllBoneScales(); + void ApplyBoneScales(); }; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp index f1229eea683..3b73fe40977 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp @@ -39,6 +39,7 @@ void CLuaPedDefs::LoadFunctions() {"setElementBoneRotation", ArgumentParserWarn}, {"setElementBoneQuaternion", ArgumentParserWarn}, {"setElementBoneMatrix", ArgumentParserWarn}, + {"setElementBoneScale", ArgumentParserWarn}, {"setPedRotation", SetPedRotation}, {"setPedWeaponSlot", SetPedWeaponSlot}, {"setPedCanBeKnockedOffBike", SetPedCanBeKnockedOffBike}, @@ -69,6 +70,7 @@ void CLuaPedDefs::LoadFunctions() {"getElementBoneRotation", ArgumentParserWarn}, {"getElementBoneQuaternion", ArgumentParserWarn}, {"getElementBoneMatrix", ArgumentParserWarn}, + {"getElementBoneScale", ArgumentParserWarn}, {"getPedRotation", GetPedRotation}, {"getPedWeaponSlot", GetPedWeaponSlot}, {"canPedBeKnockedOffBike", CanPedBeKnockedOffBike}, @@ -118,6 +120,9 @@ void CLuaPedDefs::LoadFunctions() {"isPedDead", IsPedDead}, {"isPedReloadingWeapon", ArgumentParserWarn}, {"killPedTask", ArgumentParser}, + + {"resetElementBoneScale", ArgumentParserWarn}, + {"resetAllElementBoneScales", ArgumentParserWarn}, }; // Add functions @@ -1118,6 +1123,39 @@ bool CLuaPedDefs::SetElementBoneMatrix(CClientPed* ped, const std::uint16_t bone return entity->SetBoneMatrix(static_cast(bone), matrix); } +std::variant> CLuaPedDefs::GetElementBoneScale(CClientPed* ped, const std::uint16_t bone) +{ + if (bone < BONE_ROOT || bone > BONE_LEFTBREAST) + throw std::invalid_argument("Invalid bone: " + std::to_string(bone)); + + CVector scale; + if (!ped->GetBoneScale(static_cast(bone), scale)) + return false; + + return CLuaMultiReturn(scale.fX, scale.fY, scale.fZ); +} + +bool CLuaPedDefs::SetElementBoneScale(CClientPed* ped, const std::uint16_t bone, const float scaleX, const float scaleY, const float scaleZ) +{ + if (bone < BONE_ROOT || bone > BONE_LEFTBREAST) + throw std::invalid_argument("Invalid bone: " + std::to_string(bone)); + + return ped->SetBoneScale(static_cast(bone), CVector(scaleX, scaleY, scaleZ)); +} + +bool CLuaPedDefs::ResetElementBoneScale(CClientPed* ped, const std::uint16_t bone) +{ + if (bone < BONE_ROOT || bone > BONE_LEFTBREAST) + throw std::invalid_argument("Invalid bone: " + std::to_string(bone)); + + return ped->ResetBoneScale(static_cast(bone)); +} + +void CLuaPedDefs::ResetAllElementBoneScales(CClientPed* ped) +{ + ped->ResetAllBoneScales(); +} + bool CLuaPedDefs::UpdateElementRpHAnim(CClientPed* ped) { CEntity* entity = ped->GetGameEntity(); @@ -1128,15 +1166,17 @@ bool CLuaPedDefs::UpdateElementRpHAnim(CClientPed* ped) entity->UpdateRpHAnim(); if (entity->GetModelIndex() != 0) + { + ped->ApplyBoneScales(); return true; + } RpClump* clump = entity->GetRpClump(); if (clump) - { - ((void(__cdecl*)(RpClump*))0x5DF560)(clump); // CPed::ShoulderBoneRotation - } + ((void(__cdecl*)(RpClump*))0x5DF560)(clump); // CPed::ShoulderBoneRotation + ped->ApplyBoneScales(); return true; } diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.h index 20ec1aa5909..acfa35388a4 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.h @@ -55,11 +55,16 @@ class CLuaPedDefs : public CLuaDefs static std::variant> GetElementBoneRotation(CClientPed* ped, const std::uint16_t bone); static std::variant> GetElementBoneQuaternion(CClientPed* ped, const std::uint16_t bone); static std::variant, 4>> GetElementBoneMatrix(CClientPed* ped, const std::uint16_t bone); + static std::variant> GetElementBoneScale(CClientPed* ped, const std::uint16_t bone); static bool SetElementBonePosition(CClientPed* ped, const std::uint16_t bone, const CVector position); static bool SetElementBoneRotation(CClientPed* ped, const std::uint16_t bone, const float yaw, const float pitch, const float roll); static bool SetElementBoneQuaternion(CClientPed* ped, const std::uint16_t bone, const float x, const float y, const float z, const float w); static bool SetElementBoneMatrix(CClientPed* ped, const std::uint16_t bone, const CMatrix matrix); + static bool SetElementBoneScale(CClientPed* ped, const std::uint16_t bone, const float scaleX, const float scaleY, const float scaleZ); + + static bool ResetElementBoneScale(CClientPed* ped, const std::uint16_t bone); + static void ResetAllElementBoneScales(CClientPed* ped); static bool UpdateElementRpHAnim(CClientPed* ped); diff --git a/Client/sdk/game/CEntity.h b/Client/sdk/game/CEntity.h index 264c5bb14d5..ab1d708c78f 100644 --- a/Client/sdk/game/CEntity.h +++ b/Client/sdk/game/CEntity.h @@ -117,6 +117,8 @@ class CEntity virtual bool SetBoneRotationQuat(eBone boneId, float x, float y, float z, float w) = 0; virtual bool GetBonePosition(eBone boneId, CVector& position) = 0; virtual bool SetBonePosition(eBone boneId, const CVector& position) = 0; + virtual bool GetBoneScale(eBone boneId, CVector& scale) = 0; + virtual bool SetBoneScale(eBone boneId, const CVector& scale) = 0; virtual bool IsOnFire() = 0; virtual bool SetOnFire(bool onFire) = 0;