sm-plugins/FixGameUI/scripting/FixGameUI.sp

158 lines
3.6 KiB
SourcePawn

#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdkhooks>
#include <sdktools>
#include <dhooks>
public Plugin myinfo =
{
name = "FixGameUI",
author = "hlstriker + GoD-Tony",
description = "Fixes game_ui entity bug and blocks DMG_CRUSH.",
version = "1.0",
url = ""
}
Handle g_hAcceptInput;
ArrayList g_hAttachedClients;
public void OnPluginStart()
{
HookEvent("player_death", Event_PlayerDeath, EventHookMode_Post);
HookEntityOutput("game_ui", "PlayerOn", GameUI_PlayerOn);
HookEntityOutput("game_ui", "PlayerOff", GameUI_PlayerOff);
g_hAttachedClients = new ArrayList();
// Gamedata.
Handle hConfig = LoadGameConfigFile("sdktools.games");
if (hConfig == INVALID_HANDLE)
SetFailState("Couldn't load sdktools game config!");
int offset = GameConfGetOffset(hConfig, "AcceptInput");
if (offset == -1)
SetFailState("Failed to find AcceptInput offset");
delete hConfig;
// DHooks.
g_hAcceptInput = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_AcceptInput);
DHookAddParam(g_hAcceptInput, HookParamType_CharPtr);
DHookAddParam(g_hAcceptInput, HookParamType_CBaseEntity);
DHookAddParam(g_hAcceptInput, HookParamType_CBaseEntity);
DHookAddParam(g_hAcceptInput, HookParamType_Object, 20); //varaint_t is a union of 12 (float[3]) plus two int type params 12 + 8 = 20
DHookAddParam(g_hAcceptInput, HookParamType_Int);
}
public Action Event_PlayerDeath(Handle hEvent, const char[] szName, bool bDontBroadcast)
{
int client = GetClientOfUserId(GetEventInt(hEvent, "userid"));
RemoveFromGameUI(client);
SetClientViewEntity(client, client);
int iFlags = GetEntityFlags(client);
iFlags &= ~FL_ONTRAIN;
iFlags &= ~FL_FROZEN;
iFlags &= ~FL_ATCONTROLS;
SetEntityFlags(client, iFlags);
}
public void OnClientDisconnect(int client)
{
RemoveFromGameUI(client);
}
public void GameUI_PlayerOn(const char[] szOutput, int iCaller, int iActivator, float fDelay)
{
if(!(1 <= iActivator <= MaxClients))
return;
int GameUIArray[2];
GameUIArray[0] = iCaller;
GameUIArray[1] = iActivator;
g_hAttachedClients.PushArray(GameUIArray);
}
public void GameUI_PlayerOff(const char[] szOutput, int iCaller, int iActivator, float fDelay)
{
if(!(1 <= iActivator <= MaxClients))
return;
for(int i; i < g_hAttachedClients.Length; i++)
{
int GameUIArray[2];
g_hAttachedClients.GetArray(i, GameUIArray);
if (GameUIArray[0] == iCaller)
{
g_hAttachedClients.Erase(i);
break;
}
}
}
public void OnEntityDestroyed(int entity)
{
for(int i; i < g_hAttachedClients.Length; i++)
{
int GameUIArray[2];
g_hAttachedClients.GetArray(i, GameUIArray);
if (GameUIArray[0] == entity)
{
g_hAttachedClients.Erase(i);
break;
}
}
}
void RemoveFromGameUI(int client)
{
for(int i; i < g_hAttachedClients.Length; i++)
{
int GameUIArray[2];
g_hAttachedClients.GetArray(i, GameUIArray);
if (GameUIArray[1] == client)
{
AcceptEntityInput(GameUIArray[0], "Deactivate", GameUIArray[1], GameUIArray[0]);
g_hAttachedClients.Erase(i);
}
}
}
public void OnEntityCreated(int entity, const char[] classname)
{
if (StrEqual(classname, "game_ui"))
{
DHookEntity(g_hAcceptInput, false, entity);
}
}
public MRESReturn Hook_AcceptInput(int thisptr, Handle hReturn, Handle hParams)
{
char sCommand[128];
DHookGetParamString(hParams, 1, sCommand, sizeof(sCommand));
if (StrEqual(sCommand, "Deactivate", false))
{
int pPlayer = GetEntPropEnt(thisptr, Prop_Data, "m_player");
if (pPlayer == -1)
{
// Manually disable think.
SetEntProp(thisptr, Prop_Data, "m_nNextThinkTick", -1);
DHookSetReturn(hReturn, false);
return MRES_Supercede;
}
}
DHookSetReturn(hReturn, true);
return MRES_Ignored;
}