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/CPedSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class CVehicleSAInterface;

// CPedClothesDesc && CClothes
#define FUNC_CPedClothesDesc__SetTextureAndModel 0x5A8080 // CPedClothesDesc::SetTextureAndModel
#define FUNC_CPedClothesDesc__Initialise 0x5A78F0 // CPedClothesDesc::Initialise
#define FUNC_CClothes__RebuildPlayer 0x5A82C0 // CClothes::RebuildPlayer
#define SIZEOF_CPedClothesDesc 0x78

// CAEPedWeaponAudioEntity
#define FUNC_CAEPedWeaponAudioEntity__AddAudioEvent 0x4E69F0 // CAEPedWeaponAudioEntity::AddAudioEvent
Expand Down
10 changes: 6 additions & 4 deletions Client/game_sa/CPlayerPedSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ extern CGameSA* pGame;

class CPedClothesDesc;

static CPedClothesDesc* pLocalClothes = 0;
static CWantedSAInterface* pLocalWanted = 0;
static std::set<SString> ms_DoneAnimBlockRefMap;

Expand Down Expand Up @@ -80,8 +79,11 @@ CPlayerPedSA::CPlayerPedSA(unsigned int nModelIndex)
m_pData->m_Wanted = pLocalWanted;
m_pData->m_fTimeCanRun = 1000.0f;

// Clothes pointers or we'll crash later (TODO: Wrap up with some cloth classes and make it unique per player)
m_pData->m_pClothes = pLocalClothes;
// Give each remote ped its own clothes descriptor. Sharing a single
// descriptor between peds caused script-driven changes on one player
// to leak onto others after a rebuild (reconnect/respawn). See #4380.
m_pData->m_pClothes = static_cast<CPedClothesDesc*>(operator new(SIZEOF_CPedClothesDesc));
((void(__thiscall*)(void*))FUNC_CPedClothesDesc__Initialise)(m_pData->m_pClothes);

// Not sure why was this here (svn blame reports that this line came from the old SVN),
// but it's causing a bug in what the just streamed-in players that are in the air are
Expand Down Expand Up @@ -121,7 +123,6 @@ CPlayerPedSA::CPlayerPedSA(CPlayerPedSAInterface* pPlayer)
GetPlayerPedInterface()->pedFlags.bIsLanding = false;
GetPlayerPedInterface()->fRotationSpeed = 7.5;

pLocalClothes = m_pData->m_pClothes;
pLocalWanted = m_pData->m_Wanted;

GetPlayerPedInterface()->pedFlags.bCanBeShotInVehicle = true;
Expand Down Expand Up @@ -150,6 +151,7 @@ CPlayerPedSA::~CPlayerPedSA()
// Delete the player data
if (!m_bIsLocal)
{
operator delete(m_pData->m_pClothes);
delete m_pData;
}
}
Expand Down
27 changes: 23 additions & 4 deletions Client/mods/deathmatch/logic/CClientPlayerClothes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,19 @@ bool CClientPlayerClothes::RemoveClothes(unsigned char ucType, bool bRemoveFromM
// Remove them from the model now?
if (bRemoveFromModel)
{
InternalAddClothes(NULL, ucType);
// For slots 0-3 we apply the bare clothing directly (InternalAddClothes filters
// it out); for others we clear the slot. Needed to strip CJ's default clothes.
if (m_Clothes[ucType] && m_pPlayerModel)
{
CPlayerPed* pPlayerPed = m_pPlayerModel->GetGamePlayer();
if (pPlayerPed)
pPlayerPed->SetClothesTextureAndModel(m_Clothes[ucType]->texture.c_str(), m_Clothes[ucType]->model.c_str(), ucType);
m_GlobalClothes[ucType] = m_Clothes[ucType];
}
else
{
InternalAddClothes(NULL, ucType);
}
}

return true;
Expand All @@ -419,16 +431,23 @@ void CClientPlayerClothes::AddAllToModel()
{
for (unsigned char ucType = 0; ucType < PLAYER_CLOTHING_SLOTS; ucType++)
{
const SPlayerClothing* pPrevious = m_GlobalClothes[ucType];
const SPlayerClothing* pCurrent = m_Clothes[ucType];
if (pCurrent)
{
if (!pPrevious || pPrevious != pCurrent)
// Apply the empty clothing (slot 0-3 bare torso/face/legs/shoes) directly:
// InternalAddClothes filters it out, which would leave the CJ model's default
// clothes visible after removePedClothes.
if (IsEmptyClothing(pCurrent, ucType))
{
pPlayerPed->SetClothesTextureAndModel(pCurrent->texture.c_str(), pCurrent->model.c_str(), ucType);
m_GlobalClothes[ucType] = pCurrent;
}
else
{
InternalAddClothes(pCurrent, ucType);
}
}
else if (pPrevious)
else
{
InternalAddClothes(NULL, ucType);
}
Expand Down