Skip to content

Commit

Permalink
Add tracking for players active ZR class & model
Browse files Browse the repository at this point in the history
We also suspected ZR classes may have been leaking memory, this smart pointer approach should make that impossible
  • Loading branch information
Vauff committed Oct 7, 2024
1 parent 6ee0968 commit 06aaf62
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 45 deletions.
10 changes: 10 additions & 0 deletions src/playermanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ enum class ETargetError
};

class ZEPlayer;
struct ZRClass;
struct ZRModelEntry;

class ZEPlayerHandle
{
Expand Down Expand Up @@ -172,6 +174,8 @@ class ZEPlayer
m_flMaxSpeed = 1.f;
m_iLastInputs = IN_NONE;
m_iLastInputTime = std::time(0);
m_pActiveZRClass = nullptr;
m_pActiveZRModel = nullptr;
}

~ZEPlayer()
Expand Down Expand Up @@ -227,6 +231,8 @@ class ZEPlayer
void UpdateLastInputTime() { m_iLastInputTime = std::time(0); }
void SetMaxSpeed(float flMaxSpeed) { m_flMaxSpeed = flMaxSpeed; }
void ReplicateConVar(const char* pszName, const char* pszValue);
void SetActiveZRClass(std::shared_ptr<ZRClass> pZRModel) { m_pActiveZRClass = pZRModel; }
void SetActiveZRModel(std::shared_ptr<ZRModelEntry> pZRClass) { m_pActiveZRModel = pZRClass; }

uint64 GetAdminFlags() { return m_iAdminFlags; }
int GetAdminImmunity() { return m_iAdminImmunity; }
Expand Down Expand Up @@ -262,6 +268,8 @@ class ZEPlayer
float GetMaxSpeed() { return m_flMaxSpeed; }
uint64 GetLastInputs() { return m_iLastInputs; }
std::time_t GetLastInputTime() { return m_iLastInputTime; }
std::shared_ptr<ZRClass> GetActiveZRClass() { return m_pActiveZRClass; }
std::shared_ptr<ZRModelEntry> GetActiveZRModel() { return m_pActiveZRModel; }

void OnSpawn();
void OnAuthenticated();
Expand Down Expand Up @@ -316,6 +324,8 @@ class ZEPlayer
float m_flMaxSpeed;
uint64 m_iLastInputs;
std::time_t m_iLastInputTime;
std::shared_ptr<ZRClass> m_pActiveZRClass;
std::shared_ptr<ZRModelEntry> m_pActiveZRModel;
};

class CPlayerManager
Expand Down
63 changes: 36 additions & 27 deletions src/zombiereborn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ void ZR_CreateOverlay(const char* pszOverlayParticlePath, float flAlpha, float f
UTIL_AddEntityIOEvent(particle, "Kill", nullptr, nullptr, "", flLifeTime + 1.0);
}

ZRModelEntry::ZRModelEntry(ZRModelEntry *modelEntry) :
ZRModelEntry::ZRModelEntry(std::shared_ptr<ZRModelEntry> modelEntry) :
szModelPath(modelEntry->szModelPath),
szColor(modelEntry->szColor)
{
Expand Down Expand Up @@ -237,7 +237,7 @@ ZRClass::ZRClass(ordered_json jsonKeys, std::string szClassname) :

for (auto& [key, jsonModelEntry] : jsonKeys["models"].items())
{
ZRModelEntry *modelEntry = new ZRModelEntry(jsonModelEntry);
std::shared_ptr<ZRModelEntry> modelEntry = std::make_shared<ZRModelEntry>(jsonModelEntry);
vecModels.AddToTail(modelEntry);
}
};
Expand Down Expand Up @@ -303,7 +303,7 @@ void ZRClass::Override(ordered_json jsonKeys, std::string szClassname)

for (auto& [key, jsonModelEntry] : jsonKeys["models"].items())
{
ZRModelEntry *modelEntry = new ZRModelEntry(jsonModelEntry);
std::shared_ptr<ZRModelEntry> modelEntry = std::make_shared<ZRModelEntry>(jsonModelEntry);
vecModels.AddToTail(modelEntry);
}
}
Expand Down Expand Up @@ -460,13 +460,13 @@ void CZRPlayerClassManager::LoadPlayerClass()

if (bHuman)
{
ZRHumanClass *pHumanClass;
std::shared_ptr<ZRHumanClass> pHumanClass;
if (!szBase.empty())
{
ZRHumanClass *pBaseHumanClass = GetHumanClass(szBase.c_str());
std::shared_ptr<ZRHumanClass> pBaseHumanClass = GetHumanClass(szBase.c_str());
if (pBaseHumanClass)
{
pHumanClass = new ZRHumanClass(pBaseHumanClass);
pHumanClass = std::make_shared<ZRHumanClass>(pBaseHumanClass);
pHumanClass->Override(jsonClass, szClassName);
}
else
Expand All @@ -476,7 +476,7 @@ void CZRPlayerClassManager::LoadPlayerClass()
}
}
else
pHumanClass = new ZRHumanClass(jsonClass, szClassName);
pHumanClass = std::make_shared<ZRHumanClass>(jsonClass, szClassName);

m_HumanClassMap.Insert(hash_32_fnv1a_const(szClassName.c_str()), pHumanClass);

Expand All @@ -487,13 +487,13 @@ void CZRPlayerClassManager::LoadPlayerClass()
}
else
{
ZRZombieClass *pZombieClass;
std::shared_ptr<ZRZombieClass> pZombieClass;
if (!szBase.empty())
{
ZRZombieClass *pBaseZombieClass = GetZombieClass(szBase.c_str());
std::shared_ptr<ZRZombieClass> pBaseZombieClass = GetZombieClass(szBase.c_str());
if (pBaseZombieClass)
{
pZombieClass = new ZRZombieClass(pBaseZombieClass);
pZombieClass = std::make_shared<ZRZombieClass>(pBaseZombieClass);
pZombieClass->Override(jsonClass, szClassName);
}
else
Expand All @@ -503,7 +503,7 @@ void CZRPlayerClassManager::LoadPlayerClass()
}
}
else
pZombieClass = new ZRZombieClass(jsonClass, szClassName);
pZombieClass = std::make_shared<ZRZombieClass>(jsonClass, szClassName);

m_ZombieClassMap.Insert(hash_32_fnv1a_const(szClassName.c_str()), pZombieClass);
if (bTeamDefault)
Expand All @@ -526,9 +526,9 @@ void split(const std::string& s, char delim, Out result)
*result++ = item;
}

void CZRPlayerClassManager::ApplyBaseClass(ZRClass* pClass, CCSPlayerPawn *pPawn)
void CZRPlayerClassManager::ApplyBaseClass(std::shared_ptr<ZRClass> pClass, CCSPlayerPawn* pPawn)
{
ZRModelEntry *pModelEntry = pClass->GetRandomModelEntry();
std::shared_ptr<ZRModelEntry> pModelEntry = pClass->GetRandomModelEntry();
Color clrRender;
V_StringToColor(pModelEntry->szColor.c_str(), clrRender);

Expand All @@ -547,36 +547,45 @@ void CZRPlayerClassManager::ApplyBaseClass(ZRClass* pClass, CCSPlayerPawn *pPawn
if (const auto pPlayer = pController != nullptr ? pController->GetZEPlayer() : nullptr)
{
pPlayer->SetMaxSpeed(pClass->flSpeed);
pPlayer->SetActiveZRClass(pClass);
pPlayer->SetActiveZRModel(pModelEntry);
}

// This has to be done a bit later
UTIL_AddEntityIOEvent(pPawn, "SetScale", nullptr, nullptr, pClass->flScale);
}

// only changes that should not (directly) affect gameplay
void CZRPlayerClassManager::ApplyBaseClassVisuals(ZRClass *pClass, CCSPlayerPawn *pPawn)
void CZRPlayerClassManager::ApplyBaseClassVisuals(std::shared_ptr<ZRClass> pClass, CCSPlayerPawn* pPawn)
{
ZRModelEntry *pModelEntry = pClass->GetRandomModelEntry();
std::shared_ptr<ZRModelEntry> pModelEntry = pClass->GetRandomModelEntry();
Color clrRender;
V_StringToColor(pModelEntry->szColor.c_str(), clrRender);

pPawn->SetModel(pModelEntry->szModelPath.c_str());
pPawn->m_clrRender = clrRender;
pPawn->AcceptInput("Skin", pModelEntry->GetRandomSkin());

const auto pController = reinterpret_cast<CCSPlayerController*>(pPawn->GetController());
if (const auto pPlayer = pController != nullptr ? pController->GetZEPlayer() : nullptr)
{
pPlayer->SetActiveZRClass(pClass);
pPlayer->SetActiveZRModel(pModelEntry);
}

// This has to be done a bit later
UTIL_AddEntityIOEvent(pPawn, "SetScale", nullptr, nullptr, pClass->flScale);
}

ZRHumanClass* CZRPlayerClassManager::GetHumanClass(const char *pszClassName)
std::shared_ptr<ZRHumanClass> CZRPlayerClassManager::GetHumanClass(const char* pszClassName)
{
uint16 index = m_HumanClassMap.Find(hash_32_fnv1a_const(pszClassName));
if (!m_HumanClassMap.IsValidIndex(index))
return nullptr;
return m_HumanClassMap[index];
}

void CZRPlayerClassManager::ApplyHumanClass(ZRHumanClass *pClass, CCSPlayerPawn *pPawn)
void CZRPlayerClassManager::ApplyHumanClass(std::shared_ptr<ZRHumanClass> pClass, CCSPlayerPawn* pPawn)
{
ApplyBaseClass(pClass, pPawn);
CCSPlayerController *pController = CCSPlayerController::FromPawn(pPawn);
Expand Down Expand Up @@ -609,7 +618,7 @@ void CZRPlayerClassManager::ApplyPreferredOrDefaultHumanClass(CCSPlayerPawn *pPa

// Get the human class user preference, or default if no class is set
int iSlot = pController->GetPlayerSlot();
ZRHumanClass* humanClass = nullptr;
std::shared_ptr<ZRHumanClass> humanClass = nullptr;
const char* sPreferredHumanClass = g_pUserPreferencesSystem->GetPreference(iSlot, HUMAN_CLASS_KEY_NAME);

// If the preferred human class exists and can be applied, override the default
Expand All @@ -633,7 +642,7 @@ void CZRPlayerClassManager::ApplyPreferredOrDefaultHumanClassVisuals(CCSPlayerPa

// Get the human class user preference, or default if no class is set
int iSlot = pController->GetPlayerSlot();
ZRHumanClass* humanClass = nullptr;
std::shared_ptr<ZRHumanClass> humanClass = nullptr;
const char* sPreferredHumanClass = g_pUserPreferencesSystem->GetPreference(iSlot, HUMAN_CLASS_KEY_NAME);

// If the preferred human class exists and can be applied, override the default
Expand All @@ -647,18 +656,18 @@ void CZRPlayerClassManager::ApplyPreferredOrDefaultHumanClassVisuals(CCSPlayerPa
return;
}

ApplyBaseClassVisuals((ZRClass *)humanClass, pPawn);
ApplyBaseClassVisuals(humanClass, pPawn);
}

ZRZombieClass* CZRPlayerClassManager::GetZombieClass(const char *pszClassName)
std::shared_ptr<ZRZombieClass> CZRPlayerClassManager::GetZombieClass(const char* pszClassName)
{
uint16 index = m_ZombieClassMap.Find(hash_32_fnv1a_const(pszClassName));
if (!m_ZombieClassMap.IsValidIndex(index))
return nullptr;
return m_ZombieClassMap[index];
}

void CZRPlayerClassManager::ApplyZombieClass(ZRZombieClass *pClass, CCSPlayerPawn *pPawn)
void CZRPlayerClassManager::ApplyZombieClass(std::shared_ptr<ZRZombieClass> pClass, CCSPlayerPawn* pPawn)
{
ApplyBaseClass(pClass, pPawn);
CCSPlayerController *pController = CCSPlayerController::FromPawn(pPawn);
Expand All @@ -673,7 +682,7 @@ void CZRPlayerClassManager::ApplyPreferredOrDefaultZombieClass(CCSPlayerPawn *pP

// Get the zombie class user preference, or default if no class is set
int iSlot = pController->GetPlayerSlot();
ZRZombieClass* zombieClass = nullptr;
std::shared_ptr<ZRZombieClass> zombieClass = nullptr;
const char* sPreferredZombieClass = g_pUserPreferencesSystem->GetPreference(iSlot, ZOMBIE_CLASS_KEY_NAME);

// If the preferred zombie class exists and can be applied, override the default
Expand All @@ -690,7 +699,7 @@ void CZRPlayerClassManager::ApplyPreferredOrDefaultZombieClass(CCSPlayerPawn *pP
ApplyZombieClass(zombieClass, pPawn);
}

void CZRPlayerClassManager::GetZRClassList(int iTeam, CUtlVector<ZRClass*> &vecClasses, CCSPlayerController* pController)
void CZRPlayerClassManager::GetZRClassList(int iTeam, CUtlVector<std::shared_ptr<ZRClass>>& vecClasses, CCSPlayerController* pController)
{
if (iTeam == CS_TEAM_T || iTeam == CS_TEAM_NONE)
{
Expand Down Expand Up @@ -1187,7 +1196,7 @@ void ZR_InfectMotherZombie(CCSPlayerController *pVictimController, std::vector<S
pVictimController->SwitchTeam(CS_TEAM_T);
pVictimPawn->EmitSound("zr.amb.scream");

ZRZombieClass *pClass = g_pZRPlayerClassManager->GetZombieClass("MotherZombie");
std::shared_ptr<ZRZombieClass> pClass = g_pZRPlayerClassManager->GetZombieClass("MotherZombie");
if (pClass)
g_pZRPlayerClassManager->ApplyZombieClass(pClass, pVictimPawn);
else
Expand Down Expand Up @@ -1730,7 +1739,7 @@ CON_COMMAND_CHAT(zclass, "<teamname/class name/number> - Find and select your Z:
return;
}

CUtlVector<ZRClass*> vecClasses;
CUtlVector<std::shared_ptr<ZRClass>> vecClasses;
int iSlot = player->GetPlayerSlot();
bool bListingZombie = true;
bool bListingHuman = true;
Expand Down Expand Up @@ -1773,7 +1782,7 @@ CON_COMMAND_CHAT(zclass, "<teamname/class name/number> - Find and select your Z:
{
const char* sClassName = vecClasses[i]->szClassName.c_str();
bool bClassMatches = !V_stricmp(sClassName, args[1]) || (V_StringToInt32(args[1], -1) - 1) == i;
ZRClass* pClass = vecClasses[i];
std::shared_ptr<ZRClass> pClass = vecClasses[i];

if (bClassMatches)
{
Expand Down
36 changes: 18 additions & 18 deletions src/zombiereborn.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct ZRModelEntry
std::string szModelPath;
CUtlVector<int> vecSkins;
std::string szColor;
ZRModelEntry(ZRModelEntry* modelEntry);
ZRModelEntry(std::shared_ptr<ZRModelEntry> modelEntry);
ZRModelEntry(ordered_json jsonModelEntry);
int GetRandomSkin()
{
Expand All @@ -66,12 +66,12 @@ struct ZRClass
bool bEnabled;
std::string szClassName;
int iHealth;
CUtlVector<ZRModelEntry*> vecModels;
CUtlVector<std::shared_ptr<ZRModelEntry>> vecModels;
float flScale;
float flSpeed;
float flGravity;
uint64 iAdminFlag;
ZRClass(ZRClass *pClass, int iTeam) :
ZRClass(std::shared_ptr<ZRClass> pClass, int iTeam) :
iTeam(iTeam),
bEnabled(pClass->bEnabled),
szClassName(pClass->szClassName),
Expand All @@ -84,7 +84,7 @@ struct ZRClass
vecModels.Purge();
FOR_EACH_VEC(pClass->vecModels, i)
{
ZRModelEntry *modelEntry = new ZRModelEntry(pClass->vecModels[i]);
std::shared_ptr<ZRModelEntry> modelEntry = std::make_shared<ZRModelEntry>(pClass->vecModels[i]);
vecModels.AddToTail(modelEntry);
}
};
Expand Down Expand Up @@ -127,7 +127,7 @@ struct ZRClass
void Override(ordered_json jsonKeys, std::string szClassname);
bool IsApplicableTo(CCSPlayerController *pController);
uint64 ParseClassFlags(const char* pszFlags);
ZRModelEntry *GetRandomModelEntry()
std::shared_ptr<ZRModelEntry> GetRandomModelEntry()
{
return vecModels[rand() % vecModels.Count()];
};
Expand All @@ -136,15 +136,15 @@ struct ZRClass

struct ZRHumanClass : ZRClass
{
ZRHumanClass(ZRHumanClass *pClass) : ZRClass(pClass, CS_TEAM_CT){};
ZRHumanClass(std::shared_ptr<ZRHumanClass> pClass) : ZRClass(pClass, CS_TEAM_CT) {};
ZRHumanClass(ordered_json jsonKeys, std::string szClassname);
};

struct ZRZombieClass : ZRClass
{
int iHealthRegenCount;
float flHealthRegenInterval;
ZRZombieClass(ZRZombieClass *pClass) :
ZRZombieClass(std::shared_ptr<ZRZombieClass> pClass) :
ZRClass(pClass, CS_TEAM_T),
iHealthRegenCount(pClass->iHealthRegenCount),
flHealthRegenInterval(pClass->flHealthRegenInterval){};
Expand Down Expand Up @@ -199,22 +199,22 @@ class CZRPlayerClassManager
m_HumanClassMap.SetLessFunc(DefLessFunc(uint32));
};
void LoadPlayerClass();
void ApplyBaseClassVisuals(ZRClass *pClass, CCSPlayerPawn *pPawn);
ZRHumanClass* GetHumanClass(const char *pszClassName);
void ApplyHumanClass(ZRHumanClass *pClass, CCSPlayerPawn *pPawn);
void ApplyBaseClassVisuals(std::shared_ptr<ZRClass> pClass, CCSPlayerPawn* pPawn);
std::shared_ptr<ZRHumanClass> GetHumanClass(const char* pszClassName);
void ApplyHumanClass(std::shared_ptr<ZRHumanClass> pClass, CCSPlayerPawn* pPawn);
void ApplyPreferredOrDefaultHumanClass(CCSPlayerPawn *pPawn);
void ApplyPreferredOrDefaultHumanClassVisuals(CCSPlayerPawn *pPawn);
ZRZombieClass* GetZombieClass(const char*pszClassName);
void ApplyZombieClass(ZRZombieClass *pClass, CCSPlayerPawn *pPawn);
std::shared_ptr<ZRZombieClass> GetZombieClass(const char* pszClassName);
void ApplyZombieClass(std::shared_ptr<ZRZombieClass> pClass, CCSPlayerPawn* pPawn);
void ApplyPreferredOrDefaultZombieClass(CCSPlayerPawn *pPawn);
void PrecacheModels(IEntityResourceManifest* pResourceManifest);
void GetZRClassList(int iTeam, CUtlVector<ZRClass*> &vecClasses, CCSPlayerController* pController = nullptr);
void GetZRClassList(int iTeam, CUtlVector<std::shared_ptr<ZRClass>>& vecClasses, CCSPlayerController* pController = nullptr);
private:
void ApplyBaseClass(ZRClass* pClass, CCSPlayerPawn *pPawn);
CUtlVector<ZRZombieClass*> m_vecZombieDefaultClass;
CUtlVector<ZRHumanClass*> m_vecHumanDefaultClass;
CUtlMap<uint32, ZRZombieClass*> m_ZombieClassMap;
CUtlMap<uint32, ZRHumanClass*> m_HumanClassMap;
void ApplyBaseClass(std::shared_ptr<ZRClass> pClass, CCSPlayerPawn* pPawn);
CUtlVector<std::shared_ptr<ZRZombieClass>> m_vecZombieDefaultClass;
CUtlVector<std::shared_ptr<ZRHumanClass>> m_vecHumanDefaultClass;
CUtlMap<uint32, std::shared_ptr<ZRZombieClass>> m_ZombieClassMap;
CUtlMap<uint32, std::shared_ptr<ZRHumanClass>> m_HumanClassMap;
};

class CZRRegenTimer : public CTimerBase
Expand Down

0 comments on commit 06aaf62

Please sign in to comment.