remake - v1

This commit is contained in:
2026-08-10 14:21:28 +02:00
parent 1ecb7f777e
commit f1a5250613
7 changed files with 517 additions and 28 deletions

View File

@@ -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()))