remake - v1
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "common.h"
|
||||
#include "schema.h"
|
||||
#include "entity2/entitysystem.h"
|
||||
#include "entity2/entityinstance.h"
|
||||
#include "entityhandle.h"
|
||||
|
||||
#include <cstdlib>
|
||||
@@ -109,6 +110,12 @@ static bool DesignerContains(CEntityIdentity* identity, const char* needle)
|
||||
return designer && V_stristr(designer, needle);
|
||||
}
|
||||
|
||||
static bool DesignerEquals(CEntityIdentity* identity, const char* value)
|
||||
{
|
||||
const char* designer = identity ? identity->m_designerName.String() : nullptr;
|
||||
return designer && !V_stricmp(designer, value);
|
||||
}
|
||||
|
||||
static int EntityIndex(CEntityIdentity* identity)
|
||||
{
|
||||
return identity ? identity->m_EHandle.GetEntryIndex() : -1;
|
||||
@@ -274,13 +281,68 @@ bool OverrideManager::SetHealth42Test(bool enabled, std::string& error)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OverrideManager::SetRecipientHealthValue(int recipientSlot, int value, std::string& error)
|
||||
{
|
||||
if (recipientSlot < -1 || recipientSlot >= static_cast<int>(m_recipientHealthSet.size()))
|
||||
{
|
||||
error = "recipient slot must be all/-1 or 0..63";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RequiredField("CBaseEntity", "m_iHealth", error))
|
||||
return false;
|
||||
|
||||
if (recipientSlot == -1)
|
||||
{
|
||||
m_defaultHealth42Value = value;
|
||||
SPMessage("health_42 default recipient value=%d\n", value);
|
||||
return true;
|
||||
}
|
||||
|
||||
m_recipientHealthSet[recipientSlot] = true;
|
||||
m_recipientHealthValue[recipientSlot] = value;
|
||||
SPMessage("health_42 recipient slot %d value=%d\n", recipientSlot, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OverrideManager::ClearRecipientHealthValues()
|
||||
{
|
||||
m_defaultHealth42Value = 42;
|
||||
m_recipientHealthSet.fill(false);
|
||||
m_recipientHealthValue.fill(0);
|
||||
SPMessage("health_42 recipient values cleared\n");
|
||||
}
|
||||
|
||||
bool OverrideManager::TryGetHealth42Value(CPlayerSlot recipient, int& value) const
|
||||
{
|
||||
if (!m_health42Test)
|
||||
return false;
|
||||
|
||||
int slot = recipient.Get();
|
||||
if (slot >= 0 && slot < static_cast<int>(m_recipientHealthSet.size()) && m_recipientHealthSet[slot])
|
||||
{
|
||||
value = m_recipientHealthValue[slot];
|
||||
return true;
|
||||
}
|
||||
|
||||
value = m_defaultHealth42Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OverrideManager::Dump() const
|
||||
{
|
||||
SPMessage("%zu static rules loaded; %zu dynamic rules loaded; trace=%d\n", m_rules.size(), DynamicRuleCount(), m_trace ? 1 : 0);
|
||||
if (m_healthMoneyTest)
|
||||
SPMessage("dynamic: teammate CBaseEntity::m_iHealth = recipient CCSPlayerController_InGameMoneyServices::m_iAccount\n");
|
||||
if (m_health42Test)
|
||||
SPMessage("dynamic: all player CBaseEntity::m_iHealth = 42\n");
|
||||
{
|
||||
SPMessage("dynamic: all non-own player CBaseEntity::m_iHealth = per-recipient value, default=%d\n", m_defaultHealth42Value);
|
||||
for (size_t i = 0; i < m_recipientHealthSet.size(); ++i)
|
||||
{
|
||||
if (m_recipientHealthSet[i])
|
||||
SPMessage("dynamic: recipient slot %zu health=%d\n", i, m_recipientHealthValue[i]);
|
||||
}
|
||||
}
|
||||
for (const auto& rule : m_rules)
|
||||
SPMessage("#%d recipient=%d target=%s field=%s::%s type=%s\n", rule.id, rule.recipientSlot, rule.target.c_str(), rule.className.c_str(), rule.fieldName.c_str(), TypeName(rule.type));
|
||||
}
|
||||
@@ -399,44 +461,71 @@ void OverrideManager::ApplyHealthMoneyTest(CPlayerSlot slot, std::vector<Applied
|
||||
SPMessage("health_money_test recipient=%d money=%d changed=%d\n", slot.Get(), money, changed);
|
||||
}
|
||||
|
||||
void OverrideManager::ApplyHealth42Test(CPlayerSlot slot, std::vector<AppliedOverride>& applied)
|
||||
std::vector<AppliedOverride> OverrideManager::ApplyGlobalHealth42()
|
||||
{
|
||||
std::vector<AppliedOverride> applied;
|
||||
if (!m_health42Test)
|
||||
return;
|
||||
return applied;
|
||||
if (!g_entitySystem)
|
||||
g_entitySystem = GameEntitySystem();
|
||||
if (!g_entitySystem)
|
||||
return;
|
||||
return applied;
|
||||
|
||||
int changed = 0;
|
||||
auto healthField = schema::FindField("CBaseEntity", "m_iHealth");
|
||||
if (!healthField.found)
|
||||
return applied;
|
||||
|
||||
applied.reserve(16);
|
||||
int visited = 0;
|
||||
for (auto* identity = g_entitySystem->m_EntityList.m_pFirstActiveEntity; identity && visited < 16384; identity = identity->m_pNext, ++visited)
|
||||
{
|
||||
if (!identity->m_pInstance)
|
||||
continue;
|
||||
if (!DesignerContains(identity, "player") || DesignerContains(identity, "controller"))
|
||||
if (!DesignerEquals(identity, "player"))
|
||||
continue;
|
||||
|
||||
uintptr_t entity = reinterpret_cast<uintptr_t>(identity->m_pInstance);
|
||||
auto* healthAddress = FieldAddress(entity, "CBaseEntity", "m_iHealth");
|
||||
if (!healthAddress)
|
||||
continue;
|
||||
auto* healthAddress = reinterpret_cast<uint8_t*>(identity->m_pInstance) + healthField.offset;
|
||||
|
||||
AppliedOverride saved {healthAddress, FieldType::Int32, ReadBits(healthAddress, FieldType::Int32)};
|
||||
WriteBits(healthAddress, FieldType::Int32, 42);
|
||||
AppliedOverride saved {healthAddress, FieldType::Int32, static_cast<uint32_t>(*reinterpret_cast<int*>(healthAddress))};
|
||||
*reinterpret_cast<int*>(healthAddress) = 42;
|
||||
applied.push_back(saved);
|
||||
}
|
||||
|
||||
return applied;
|
||||
}
|
||||
|
||||
int OverrideManager::MarkPlayerHealthDirty()
|
||||
{
|
||||
if (!g_entitySystem)
|
||||
g_entitySystem = GameEntitySystem();
|
||||
if (!g_entitySystem)
|
||||
return 0;
|
||||
|
||||
auto healthField = schema::FindField("CBaseEntity", "m_iHealth");
|
||||
if (!healthField.found)
|
||||
return 0;
|
||||
|
||||
int changed = 0;
|
||||
int visited = 0;
|
||||
for (auto* identity = g_entitySystem->m_EntityList.m_pFirstActiveEntity; identity && visited < 16384; identity = identity->m_pNext, ++visited)
|
||||
{
|
||||
if (!identity->m_pInstance || !DesignerEquals(identity, "player"))
|
||||
continue;
|
||||
|
||||
NetworkStateChangedData data(static_cast<uint32>(healthField.offset));
|
||||
identity->m_pInstance->NetworkStateChanged(data);
|
||||
++changed;
|
||||
}
|
||||
|
||||
if (m_trace)
|
||||
SPMessage("health_42_test recipient=%d changed=%d\n", slot.Get(), changed);
|
||||
SPMessage("marked player health dirty changed=%d\n", changed);
|
||||
return changed;
|
||||
}
|
||||
|
||||
std::vector<AppliedOverride> OverrideManager::ApplyForRecipient(CPlayerSlot slot)
|
||||
{
|
||||
std::vector<AppliedOverride> applied;
|
||||
ApplyHealthMoneyTest(slot, applied);
|
||||
ApplyHealth42Test(slot, applied);
|
||||
for (const auto& rule : m_rules)
|
||||
{
|
||||
if (!rule.enabled || (rule.recipientSlot != -1 && rule.recipientSlot != slot.Get()))
|
||||
|
||||
Reference in New Issue
Block a user