Files
sm-plugins/ScoreboardUnlocker/scripting/ScoreboardUnlocker.sp
T

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;
}