New plugin ScoreboardUnlocker: Increases the frags limit in the scoreboard
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user