268 lines
7.7 KiB
SourcePawn
268 lines
7.7 KiB
SourcePawn
#pragma semicolon 1
|
|
#pragma newdecls required
|
|
|
|
#include <sourcemod>
|
|
#include <sdktools>
|
|
|
|
#define PLUGIN_NAME "ScoreboardUnlocker"
|
|
#define PLUGIN_AUTHOR "Irineu"
|
|
#define PLUGIN_VERSION "1.0"
|
|
|
|
#define DPT_DataTable 6
|
|
|
|
public Plugin myinfo =
|
|
{
|
|
name = PLUGIN_NAME,
|
|
author = PLUGIN_AUTHOR,
|
|
description = "Increases the frags limit in the scoreboard",
|
|
version = PLUGIN_VERSION,
|
|
url = ""
|
|
};
|
|
|
|
bool g_bLate = false;
|
|
Address serverGameDLL = 0;
|
|
Address g_pSendTableCRC = 0;
|
|
int g_iServerClass_m_pNext = -1;
|
|
int g_iServerClass_m_pTable = -1;
|
|
int g_iSendTable_m_pNetTableName = -1;
|
|
int g_iSendTable_m_nProps = -1;
|
|
int g_iSendTable_m_pProps = -1;
|
|
int g_iSendProp_m_Type = -1;
|
|
int g_iSendProp_m_pDataTable = -1;
|
|
int g_iSendProp_m_pVarName = -1;
|
|
int g_iSendProp_m_nBits = -1;
|
|
int g_iSendProp_sizeof = -1;
|
|
Handle g_hGetAllServerClasses = INVALID_HANDLE;
|
|
|
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
|
{
|
|
g_bLate = late;
|
|
return APLRes_Success;
|
|
}
|
|
|
|
public void OnPluginStart()
|
|
{
|
|
GameData gd = new GameData("ScoreboardUnlocker");
|
|
if (!gd)
|
|
SetFailState("Missing gamedata file");
|
|
|
|
StartPrepSDKCall(SDKCall_Static);
|
|
if (!PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CreateInterface_Server"))
|
|
SetFailState("Failed to get CreateInterface_Server");
|
|
|
|
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
|
|
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
|
|
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
|
|
|
Handle call = EndPrepSDKCall();
|
|
|
|
StartPrepSDKCall(SDKCall_Raw);
|
|
if (!PrepSDKCall_SetFromConf(gd, SDKConf_Virtual, "IServerGameDLL::GetAllServerClasses"))
|
|
SetFailState("Failed to get IServerGameDLL::GetAllServerClasses");
|
|
|
|
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
|
|
|
g_hGetAllServerClasses = EndPrepSDKCall();
|
|
|
|
char GameDLLInterfaceName[64];
|
|
if (!gd.GetKeyValue("INTERFACEVERSION_SERVERGAMEDLL", GameDLLInterfaceName, sizeof(GameDLLInterfaceName)))
|
|
SetFailState("Failed to get gamedll interface name");
|
|
|
|
serverGameDLL = SDKCall(call, GameDLLInterfaceName, 0);
|
|
if (serverGameDLL == Address_Null)
|
|
SetFailState("Failed to get gamedll interface");
|
|
|
|
g_pSendTableCRC = gd.GetMemSig("g_SendTableCRC");
|
|
if (g_pSendTableCRC == Address_Null)
|
|
SetFailState("Failed to get g_SendTableCRC");
|
|
|
|
g_iServerClass_m_pNext = GetRequiredOffset(gd, "ServerClass::m_pNext");
|
|
g_iServerClass_m_pTable = GetRequiredOffset(gd, "ServerClass::m_pTable");
|
|
g_iSendTable_m_pNetTableName = GetRequiredOffset(gd, "SendTable::m_pNetTableName");
|
|
g_iSendTable_m_nProps = GetRequiredOffset(gd, "SendTable::m_nProps");
|
|
g_iSendTable_m_pProps = GetRequiredOffset(gd, "SendTable::m_pProps");
|
|
g_iSendProp_m_Type = GetRequiredOffset(gd, "SendProp::m_Type");
|
|
g_iSendProp_m_pDataTable = GetRequiredOffset(gd, "SendProp::m_pDataTable");
|
|
g_iSendProp_m_pVarName = GetRequiredOffset(gd, "SendProp::m_pVarName");
|
|
g_iSendProp_m_nBits = GetRequiredOffset(gd, "SendProp::m_nBits");
|
|
g_iSendProp_sizeof = GetRequiredOffset(gd, "SendProp::sizeof");
|
|
|
|
ConVar sv_sendtables = FindConVar("sv_sendtables");
|
|
if (!sv_sendtables)
|
|
SetFailState("Failed to find sv_sendtables");
|
|
sv_sendtables.BoolValue = true;
|
|
|
|
if (!g_bLate)
|
|
FulfillMyPurpose();
|
|
|
|
CloseHandle(call);
|
|
CloseHandle(gd);
|
|
}
|
|
|
|
public void OnMapInit(const char[] mapName)
|
|
{
|
|
if (g_bLate)
|
|
{
|
|
FulfillMyPurpose();
|
|
g_bLate = false;
|
|
}
|
|
}
|
|
|
|
void FulfillMyPurpose()
|
|
{
|
|
Address pTable = FindSendTable("DT_PlayerResource");
|
|
if (pTable == Address_Null)
|
|
SetFailState("Failed to find DT_PlayerResource");
|
|
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
char name[64];
|
|
Format(name, sizeof(name), "m_iScore.%03d", i);
|
|
Address pProp = FindSendProp(pTable, name);
|
|
if (pProp != Address_Null)
|
|
StoreToAddress(pProp + view_as<Address>(g_iSendProp_m_nBits), 32, NumberType_Int32, false);
|
|
else
|
|
SetFailState("Failed to find m_iScore.%03d", i);
|
|
}
|
|
|
|
int crc = LoadFromAddress(g_pSendTableCRC, NumberType_Int32);
|
|
StoreToAddress(g_pSendTableCRC, crc + 1, NumberType_Int32, false);
|
|
}
|
|
|
|
int GetRequiredOffset(GameData gd, const char[] name)
|
|
{
|
|
int ret = gd.GetOffset(name);
|
|
if (ret == -1)
|
|
SetFailState("Missing offset %s from gamedata file", name);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void LoadStringFromAddress(char[] buf, int bufSize, Address address)
|
|
{
|
|
for (int i = 0; i < bufSize; i++)
|
|
{
|
|
char c = LoadFromAddress(address + view_as<Address>(i), NumberType_Int8);
|
|
if (c == 0)
|
|
break;
|
|
|
|
buf[i] = c;
|
|
}
|
|
|
|
buf[bufSize - 1] = 0;
|
|
}
|
|
|
|
enum struct bazinga
|
|
{
|
|
Address pAddr;
|
|
}
|
|
|
|
Address FindSendTable(const char[] name)
|
|
{
|
|
ArrayList sendTables = new ArrayList();
|
|
for (Address pServerClass = SDKCall(g_hGetAllServerClasses, serverGameDLL);
|
|
pServerClass != Address_Null;
|
|
pServerClass = LoadFromAddress(pServerClass + view_as<Address>(g_iServerClass_m_pNext), NumberType_Int32))
|
|
{
|
|
Address pTable = LoadFromAddress(pServerClass + view_as<Address>(g_iServerClass_m_pTable), NumberType_Int32);
|
|
if (pTable != Address_Null)
|
|
{
|
|
bazinga thing;
|
|
thing.pAddr = pTable;
|
|
sendTables.PushArray(thing, sizeof(bazinga));
|
|
}
|
|
}
|
|
|
|
while (sendTables.Length > 0)
|
|
{
|
|
bazinga thing;
|
|
sendTables.GetArray(0, thing, sizeof(bazinga));
|
|
Address pTable = thing.pAddr;
|
|
sendTables.Erase(0);
|
|
char tableName[64];
|
|
Address pName = LoadFromAddress(pTable + view_as<Address>(g_iSendTable_m_pNetTableName), NumberType_Int32);
|
|
LoadStringFromAddress(tableName, sizeof(tableName), pName);
|
|
if (strcmp(tableName, name) == 0)
|
|
{
|
|
delete sendTables;
|
|
return pTable;
|
|
}
|
|
else
|
|
{
|
|
int nProps = LoadFromAddress(pTable + view_as<Address>(g_iSendTable_m_nProps), NumberType_Int32);
|
|
for (int i = 0; i < nProps; i++)
|
|
{
|
|
Address pProp = LoadFromAddress(pTable + view_as<Address>(g_iSendTable_m_pProps), NumberType_Int32) + (i * g_iSendProp_sizeof);
|
|
Address pPropTable = LoadFromAddress(pProp + view_as<Address>(g_iSendProp_m_pDataTable), NumberType_Int32);
|
|
int propType = LoadFromAddress(pProp + view_as<Address>(g_iSendProp_m_Type), NumberType_Int32);
|
|
if (propType == DPT_DataTable && pPropTable != Address_Null)
|
|
{
|
|
thing.pAddr = pPropTable;
|
|
sendTables.PushArray(thing, sizeof(bazinga));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete sendTables;
|
|
return Address_Null;
|
|
}
|
|
|
|
Address FindInSendTable(Address pTable, const char[] name, int requiredType = -1)
|
|
{
|
|
int nProps = LoadFromAddress(pTable + view_as<Address>(g_iSendTable_m_nProps), NumberType_Int32);
|
|
for (int i = 0; i < nProps; i++)
|
|
{
|
|
Address pProp = LoadFromAddress(pTable + view_as<Address>(g_iSendTable_m_pProps), NumberType_Int32) + (i * g_iSendProp_sizeof);
|
|
char propName[64];
|
|
Address pName = LoadFromAddress(pProp + view_as<Address>(g_iSendProp_m_pVarName), NumberType_Int32);
|
|
LoadStringFromAddress(propName, sizeof(propName), pName);
|
|
int propType = LoadFromAddress(pProp + view_as<Address>(g_iSendProp_m_Type), NumberType_Int32);
|
|
if (strcmp(propName, name) == 0 && (propType == requiredType || requiredType == -1))
|
|
return pProp;
|
|
}
|
|
|
|
return Address_Null;
|
|
}
|
|
|
|
Address FindSendProp(Address pTable, const char[] name, int requiredType = -1)
|
|
{
|
|
char propNames[16][64];
|
|
int nameCount = ExplodeString(name, ".", propNames, 16, 64);
|
|
Address pProp = Address_Null;
|
|
// Please don't ever reuse parameters for local variables in this stupid language again, future me.
|
|
Address pTable2 = pTable;
|
|
for (int i = 0; i < nameCount; )
|
|
{
|
|
if (pProp != Address_Null)
|
|
{
|
|
Address pPropTable = LoadFromAddress(pProp + view_as<Address>(g_iSendProp_m_pDataTable), NumberType_Int32);
|
|
if (pPropTable != Address_Null)
|
|
pTable2 = pPropTable;
|
|
}
|
|
|
|
int type = i == (nameCount - 1) ? requiredType : DPT_DataTable;
|
|
pProp = FindInSendTable(pTable2, propNames[i], type);
|
|
|
|
if (pProp == Address_Null)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
pProp = FindInSendTable(pTable2, "baseclass", DPT_DataTable);
|
|
if (pProp == Address_Null)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return pProp;
|
|
}
|