remake - v3
This commit is contained in:
331
src/plugin.cpp
331
src/plugin.cpp
@@ -3,7 +3,6 @@
|
||||
#include "common.h"
|
||||
#include "detour.h"
|
||||
#include "gameconfig.h"
|
||||
#include "icvar.h"
|
||||
#include "iserver.h"
|
||||
#include "module.h"
|
||||
#include "overrides.h"
|
||||
@@ -27,43 +26,6 @@ CGameEntitySystem* g_entitySystem = nullptr;
|
||||
bool g_enabled = true;
|
||||
bool g_armed = false;
|
||||
|
||||
static int ForceFullUpdateForAllClients()
|
||||
{
|
||||
if (!g_networkServerService || !g_gameConfig)
|
||||
return 0;
|
||||
|
||||
CNetworkGameServerBase* server = g_networkServerService->GetIGameServer();
|
||||
if (!server)
|
||||
return 0;
|
||||
|
||||
int listOffset = g_gameConfig->GetOffset("CNetworkGameServer_ClientList");
|
||||
int deltaTickOffset = g_gameConfig->GetOffset("CServerSideClient_DeltaTick");
|
||||
if (listOffset < 0 || deltaTickOffset < 0)
|
||||
return 0;
|
||||
|
||||
auto* list = reinterpret_cast<uint8_t*>(server) + listOffset;
|
||||
int count = *reinterpret_cast<int*>(list);
|
||||
if (count <= 0 || count > 256)
|
||||
return 0;
|
||||
|
||||
auto** clients = *reinterpret_cast<void***>(list + 8);
|
||||
if (!clients)
|
||||
return 0;
|
||||
|
||||
int forced = 0;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
void* client = clients[i];
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
auto* deltaTick = reinterpret_cast<int*>(reinterpret_cast<uint8_t*>(client) + deltaTickOffset);
|
||||
*deltaTick = -1;
|
||||
++forced;
|
||||
}
|
||||
return forced;
|
||||
}
|
||||
|
||||
void SPMessage(const char* msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -97,154 +59,6 @@ CGameEntitySystem* GameEntitySystem()
|
||||
return g_entitySystem;
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_enable, "Enable SendProxy overrides", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() >= 2)
|
||||
g_enabled = atoi(args[1]) != 0;
|
||||
SPMessage("enabled=%d\n", g_enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_arm, "Arm SendProxy override application after the map is fully loaded", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() >= 2)
|
||||
g_armed = atoi(args[1]) != 0;
|
||||
SPMessage("armed=%d\n", g_armed ? 1 : 0);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_trace, "Enable SendProxy tracing", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() >= 2)
|
||||
g_overrides.SetTrace(atoi(args[1]) != 0);
|
||||
SPMessage("trace=%d\n", g_overrides.Trace() ? 1 : 0);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_dump, "Dump SendProxy state", FCVAR_NONE)
|
||||
{
|
||||
SPMessage("enabled=%d armed=%d entitySystem=%p\n", g_enabled ? 1 : 0, g_armed ? 1 : 0, GameEntitySystem());
|
||||
DumpDetourStats();
|
||||
g_overrides.Dump();
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_fullupdate, "Force full snapshot update for all connected clients", FCVAR_NONE)
|
||||
{
|
||||
int forced = ForceFullUpdateForAllClients();
|
||||
RequestSnapshotFullUpdates();
|
||||
SPMessage("forced full update for %d clients; queued snapshot fallback\n", forced);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_entities, "sp_entities [substring] [limit]", FCVAR_NONE)
|
||||
{
|
||||
CGameEntitySystem* entitySystem = GameEntitySystem();
|
||||
if (!entitySystem)
|
||||
{
|
||||
SPWarning("no entity system\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const char* filter = args.ArgC() >= 2 ? args[1] : "";
|
||||
int limit = args.ArgC() >= 3 ? atoi(args[2]) : 80;
|
||||
if (limit <= 0)
|
||||
limit = 80;
|
||||
|
||||
auto healthField = schema::FindField("CBaseEntity", "m_iHealth");
|
||||
int printed = 0;
|
||||
int visited = 0;
|
||||
for (auto* identity = entitySystem->m_EntityList.m_pFirstActiveEntity; identity && visited < 16384; identity = identity->m_pNext, ++visited)
|
||||
{
|
||||
const char* designer = identity->m_designerName.String();
|
||||
const char* classDesigner = identity->m_pClass ? identity->m_pClass->m_designerName.String() : "";
|
||||
if (filter && *filter && !V_stristr(designer ? designer : "", filter) && !V_stristr(classDesigner ? classDesigner : "", filter))
|
||||
continue;
|
||||
|
||||
int health = -999999;
|
||||
if (identity->m_pInstance && healthField.found)
|
||||
health = *reinterpret_cast<int*>(reinterpret_cast<uint8_t*>(identity->m_pInstance) + healthField.offset);
|
||||
|
||||
SPMessage("entity idx=%d inst=%p designer=%s class=%s health=%d\n",
|
||||
identity->m_EHandle.GetEntryIndex(),
|
||||
identity->m_pInstance,
|
||||
designer ? designer : "",
|
||||
classDesigner ? classDesigner : "",
|
||||
health);
|
||||
if (++printed >= limit)
|
||||
break;
|
||||
}
|
||||
SPMessage("entities printed=%d visited=%d filter=%s\n", printed, visited, filter ? filter : "");
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_clear, "Clear SendProxy rules", FCVAR_NONE)
|
||||
{
|
||||
g_overrides.Clear();
|
||||
SPMessage("rules cleared\n");
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_set_exact, "sp_set_exact <recipient|all> <entity_index> <ClassName> <field.path> <type> <value>", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 7)
|
||||
{
|
||||
SPWarning("usage: sp_set_exact <recipient|all> <entity_index> <ClassName> <field.path> <type> <value>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int recipientSlot = !V_stricmp(args[1], "all") ? -1 : atoi(args[1]);
|
||||
int entityIndex = atoi(args[2]);
|
||||
std::string error;
|
||||
int id = g_overrides.AddCompiledRule(recipientSlot, entityIndex, args[3], args[4], args[5], args[6], error);
|
||||
if (!id)
|
||||
{
|
||||
SPWarning("%s\n", error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
g_enabled = true;
|
||||
g_armed = true;
|
||||
SPMessage("enabled=1 armed=1 rule_id=%d\n", id);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_unset, "sp_unset <rule_id>", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
SPWarning("usage: sp_unset <rule_id>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int id = atoi(args[1]);
|
||||
if (!g_overrides.RemoveRule(id))
|
||||
{
|
||||
SPWarning("rule %d not found\n", id);
|
||||
return;
|
||||
}
|
||||
SPMessage("rule %d removed\n", id);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_dirty, "sp_dirty <entity_index> <ClassName> <field.path>", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 4)
|
||||
{
|
||||
SPWarning("usage: sp_dirty <entity_index> <ClassName> <field.path>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
if (!g_overrides.MarkEntityFieldDirty(atoi(args[1]), args[2], args[3], error))
|
||||
{
|
||||
SPWarning("%s\n", error.empty() ? "failed to mark field dirty" : error.c_str());
|
||||
return;
|
||||
}
|
||||
SPMessage("marked entity %d %s::%s dirty\n", atoi(args[1]), args[2], args[3]);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_set, "sp_set <recipient|all> <entity|bot|all> <ClassName> <field> <type> <value>", FCVAR_NONE)
|
||||
{
|
||||
const char* argv[8] {};
|
||||
for (int i = 0; i < args.ArgC() && i < 8; ++i)
|
||||
argv[i] = args[i];
|
||||
std::string error;
|
||||
if (!g_overrides.AddFromTokens(args.ArgC(), argv, error))
|
||||
SPWarning("%s\n", error.c_str());
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) int SendProxy_SetOverride(int recipientSlot, int entityIndex, const char* className, const char* fieldPath, const char* type, const char* value)
|
||||
{
|
||||
std::string error;
|
||||
@@ -282,159 +96,18 @@ extern "C" __attribute__((visibility("default"))) bool SendProxy_MarkDirty(int e
|
||||
return true;
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_weapon_test, "sp_weapon_test <weapon_entity_substring|all> <item_definition_index>", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 3)
|
||||
{
|
||||
SPWarning("usage: sp_weapon_test <weapon_entity_substring|all> <item_definition_index>\n");
|
||||
return;
|
||||
}
|
||||
std::string error;
|
||||
if (!g_overrides.AddWeaponItemDefRule(-1, args[1], static_cast<uint16_t>(atoi(args[2])), error))
|
||||
SPWarning("%s\n", error.c_str());
|
||||
}
|
||||
|
||||
static void SetHealthMoneyCommand(const CCommand& args)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
SPWarning("usage: sp_health_money <0|1>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool enable = atoi(args[1]) != 0;
|
||||
std::string error;
|
||||
if (!g_overrides.SetHealthMoneyTest(enable, error))
|
||||
{
|
||||
SPWarning("%s\n", error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
g_enabled = true;
|
||||
g_armed = true;
|
||||
SPMessage("enabled=1 armed=1\n");
|
||||
SPMessage("marked health dirty for %d players\n", g_overrides.MarkPlayerHealthDirty());
|
||||
}
|
||||
else if (g_overrides.Empty())
|
||||
{
|
||||
g_armed = false;
|
||||
SPMessage("armed=0\n");
|
||||
SPMessage("marked health dirty for %d players\n", g_overrides.MarkPlayerHealthDirty());
|
||||
}
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_health_money, "sp_health_money <0|1>", FCVAR_NONE)
|
||||
{
|
||||
SetHealthMoneyCommand(args);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_health_money_test, "sp_health_money_test <0|1>", FCVAR_NONE)
|
||||
{
|
||||
SetHealthMoneyCommand(args);
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_health_42, "sp_health_42 <0|1>", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
SPWarning("usage: sp_health_42 <0|1>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool enable = atoi(args[1]) != 0;
|
||||
std::string error;
|
||||
if (!g_overrides.SetHealth42Test(enable, error))
|
||||
{
|
||||
SPWarning("%s\n", error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
g_enabled = true;
|
||||
g_armed = true;
|
||||
SPMessage("enabled=1 armed=1\n");
|
||||
SPMessage("marked health dirty for %d players\n", g_overrides.MarkPlayerHealthDirty());
|
||||
}
|
||||
else if (g_overrides.Empty())
|
||||
{
|
||||
g_armed = false;
|
||||
SPMessage("armed=0\n");
|
||||
SPMessage("marked health dirty for %d players\n", g_overrides.MarkPlayerHealthDirty());
|
||||
}
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_health_recipient, "sp_health_recipient <slot|all|clear> [value]", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
SPWarning("usage: sp_health_recipient <slot|all|clear> [value]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!V_stricmp(args[1], "clear"))
|
||||
{
|
||||
g_overrides.ClearRecipientHealthValues();
|
||||
SPMessage("marked health dirty for %d players\n", g_overrides.MarkPlayerHealthDirty());
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.ArgC() < 3)
|
||||
{
|
||||
SPWarning("usage: sp_health_recipient <slot|all|clear> [value]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int recipientSlot = !V_stricmp(args[1], "all") ? -1 : atoi(args[1]);
|
||||
int value = atoi(args[2]);
|
||||
std::string error;
|
||||
if (!g_overrides.SetRecipientHealthValue(recipientSlot, value, error))
|
||||
{
|
||||
SPWarning("%s\n", error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_overrides.Health42Test())
|
||||
{
|
||||
if (!g_overrides.SetHealth42Test(true, error))
|
||||
{
|
||||
SPWarning("%s\n", error.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_enabled = true;
|
||||
g_armed = true;
|
||||
SPMessage("enabled=1 armed=1\n");
|
||||
SPMessage("marked health dirty for %d players\n", g_overrides.MarkPlayerHealthDirty());
|
||||
}
|
||||
|
||||
CON_COMMAND_F(sp_schema_fields, "sp_schema_fields <ClassName> [substring]", FCVAR_NONE)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
SPWarning("usage: sp_schema_fields <ClassName> [substring]\n");
|
||||
return;
|
||||
}
|
||||
schema::DumpFields(args[1], args.ArgC() >= 3 ? args[2] : "");
|
||||
}
|
||||
|
||||
PLUGIN_EXPOSE(SendProxyPlugin, g_SendProxy);
|
||||
|
||||
bool SendProxyPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool late)
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
ICvar* icvar = nullptr;
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_engine, IVEngineServer2, SOURCE2ENGINETOSERVER_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetEngineFactory, g_networkServerService, INetworkServerService, NETWORKSERVERSERVICE_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetServerFactory, g_gameClients, IServerGameClients, SOURCE2GAMECLIENTS_INTERFACE_VERSION);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_schemaSystem, ISchemaSystem, SCHEMASYSTEM_INTERFACE_VERSION);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_gameResourceService, IGameResourceService, GAMERESOURCESERVICESERVER_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetFileSystemFactory, g_fileSystem, IFileSystem, FILESYSTEM_INTERFACE_VERSION);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
|
||||
|
||||
modules::engine = new CModule(ROOTBIN, "engine2");
|
||||
modules::server = new CModule(GAMEBIN, "server");
|
||||
@@ -459,10 +132,7 @@ bool SendProxyPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxle
|
||||
}
|
||||
|
||||
g_SMAPI->AddListener(this, this);
|
||||
g_pCVar = icvar;
|
||||
META_CONVAR_REGISTER(FCVAR_RELEASE | FCVAR_CLIENT_CAN_EXECUTE | FCVAR_GAMEDLL);
|
||||
|
||||
g_engine->ServerCommand("execifexists addons/sendproxy/configs/sendproxy.cfg\n");
|
||||
SPMessage("loaded\n");
|
||||
return true;
|
||||
}
|
||||
@@ -470,7 +140,6 @@ bool SendProxyPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxle
|
||||
bool SendProxyPlugin::Unload(char*, size_t)
|
||||
{
|
||||
ShutdownSnapshotDetour();
|
||||
ConVar_Unregister();
|
||||
delete g_gameConfig;
|
||||
delete modules::engine;
|
||||
delete modules::server;
|
||||
|
||||
Reference in New Issue
Block a user