csgo-plugins/CSGOPushFix/scripting/CSGOPushFix.sp
2020-03-25 20:09:12 +02:00

441 lines
14 KiB
SourcePawn

#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <cstrike>
#include <basic>
//#define Debug
methodmap CPlayer < Basic {
public CPlayer(int client) {
Basic myclass = new Basic();
myclass.SetInt("iClient", client);
myclass.SetHandle("hEntities", new ArrayList(1));
myclass.SetBool("bForceRise", false);
return view_as<CPlayer>(myclass);
}
property int iClient {
public get() {
return this.GetInt("iClient");
}
public set(int value) {
this.SetInt("iClient", value);
}
}
property ArrayList hEntities {
public get() {
return view_as<ArrayList>(this.GetHandle("hEntities"));
}
public set(ArrayList value) {
this.SetHandle("hEntities", value);
}
}
property bool bForceRise {
public get() {
return this.GetBool("bForceRise");
}
public set(bool value) {
this.SetBool("bForceRise", value);
}
}
public void Dispose(bool disposemembers = true) {
if (disposemembers) {
ArrayList hEntities = this.hEntities;
delete hEntities;
}
delete this;
}
}
enum {
SF_TRIGGER_ALLOW_CLIENTS = 0x01, // Players can fire this trigger
SF_TRIGGER_ALLOW_NPCS = 0x02, // NPCS can fire this trigger
SF_TRIGGER_ALLOW_PUSHABLES = 0x04, // Pushables can fire this trigger
SF_TRIGGER_ALLOW_PHYSICS = 0x08, // Physics objects can fire this trigger
SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS = 0x10, // *if* NPCs can fire this trigger, this flag means only player allies do so
SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES = 0x20, // *if* Players can fire this trigger, this flag means only players inside vehicles can
SF_TRIGGER_ALLOW_ALL = 0x40, // Everything can fire this trigger EXCEPT DEBRIS!
SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES = 0x200, // *if* Players can fire this trigger, this flag means only players outside vehicles can
SF_TRIG_PUSH_ONCE = 0x80, // trigger_push removes itself after firing once
SF_TRIG_PUSH_AFFECT_PLAYER_ON_LADDER = 0x100, // if pushed object is player on a ladder, then this disengages them from the ladder (HL2only)
SF_TRIG_TOUCH_DEBRIS = 0x400, // Will touch physics debris objects
SF_TRIGGER_ONLY_NPCS_IN_VEHICLES = 0x800, // *if* NPCs can fire this trigger, only NPCs in vehicles do so (respects player ally flag too)
SF_TRIGGER_PUSH_USE_MASS = 0x1000, // Correctly account for an entity's mass (CTriggerPush::Touch used to assume 100Kg)
};
Handle hTriggerPushPassesTriggerFilters;
ConVar g_hTriggerPushGround_Scale;
ConVar g_hTriggerPushRising_Scale;
ConVar g_hTriggerPushLagFixEnable;
float g_fTriggerPushGround_Scale;
float g_fTriggerPushRising_Scale;
bool g_bTriggerPushLagFixEnable;
int iOffsVelocity;
int iOffsAbsVel;
int iOffsBaseVel;
CPlayer g_aPlayers[MAXPLAYERS+1];
bool bLateLoad = false;
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
RegPluginLibrary("CSGOPushFix");
bLateLoad = late;
return APLRes_Success;
}
public Plugin myinfo = {
name = "Trigger_push Fix",
author = "uuz + PŠΣ™ SHUFEN + Based from Mev, George, & Blacky | Slidy & rio Edit",
description = "Removes lag from trigger_push and fixes of velocity bug",
version = "4.2",
url = "http://bbs.zombieden.cn/ & https://possession.jp & http://steamcommunity.com/id/mevv/ & http://steamcommunity.com/profiles/76561197975854215/ & http://steamcommunity.com/id/blaackyy/"
}
public void OnPluginStart() {
iOffsVelocity = FindSendPropInfo("CBasePlayer", "m_vecVelocity[0]");
if (iOffsVelocity == -1) {
SetFailState("[Trigger_push Fix] Could not find CBasePlayer::m_vecVelocity[0]");
}
Handle hGameConf = LoadGameConfigFile("CSGOPushFix.games");
StartPrepSDKCall(SDKCall_Entity);
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Virtual, "CBaseTrigger::PassesTriggerFilters");
PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain);
PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer);
hTriggerPushPassesTriggerFilters = EndPrepSDKCall();
delete hGameConf;
g_hTriggerPushGround_Scale = CreateConVar("triggerpushfix_ground_scale", "1.0", "Scale trigger_push Ground.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
g_hTriggerPushRising_Scale = CreateConVar("triggerpushfix_ground_rising", "1.0", "Scale trigger_push Rising.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
g_hTriggerPushLagFixEnable = CreateConVar("triggerpushlagfix_enable", "1", "Enables trigger push fix.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
g_hTriggerPushGround_Scale.AddChangeHook(OnConVarChanged);
g_hTriggerPushRising_Scale.AddChangeHook(OnConVarChanged);
g_hTriggerPushLagFixEnable.AddChangeHook(OnConVarChanged);
if (bLateLoad) {
for (int client = 1; client <= MaxClients; client++) {
if (IsClientConnected(client)) {
if (IsClientInGame(client))
OnClientPutInServer(client);
}
}
int entity = INVALID_ENT_REFERENCE;
while ((entity = FindEntityByClassname(entity, "trigger_push")) != INVALID_ENT_REFERENCE) {
OnEntityCreated(entity, "trigger_push");
}
}
}
public void OnConfigsExecuted() {
iOffsAbsVel = FindDataMapInfo(0, "m_vecAbsVelocity");
if (iOffsAbsVel == -1)
SetFailState("[Trigger_push Fix] Could not find m_vecAbsVelocity");
iOffsBaseVel = FindDataMapInfo(0, "m_vecBaseVelocity");
if (iOffsBaseVel == -1)
SetFailState("[Trigger_push Fix] Could not find m_vecBaseVelocity");
g_fTriggerPushGround_Scale = g_hTriggerPushGround_Scale.FloatValue;
g_fTriggerPushRising_Scale = g_hTriggerPushRising_Scale.FloatValue;
g_bTriggerPushLagFixEnable = g_hTriggerPushLagFixEnable.BoolValue;
}
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) {
if (convar == g_hTriggerPushGround_Scale)
g_fTriggerPushGround_Scale = StringToFloat(newValue);
else if (convar == g_hTriggerPushRising_Scale)
g_fTriggerPushRising_Scale = StringToFloat(newValue);
else if (convar == g_hTriggerPushLagFixEnable)
g_bTriggerPushLagFixEnable = view_as<bool>(StringToInt(newValue));
}
public void OnClientPutInServer(int client) {
if (!g_aPlayers[client])
g_aPlayers[client] = new CPlayer(client);
}
public void OnClientDisconnect(int client) {
if (g_aPlayers[client]) {
g_aPlayers[client].Dispose();
g_aPlayers[client] = null;
}
}
public void OnEntityCreated(int entity, const char[] classname) {
if (StrEqual(classname, "trigger_push", false)) {
SDKHook(entity, SDKHook_SpawnPost, OnEntitySpawn_Post);
} else {
for (int i = 1; i <= MaxClients; i++)
if (g_aPlayers[i]) {
ArrayList hEntities = g_aPlayers[i].hEntities;
int index = hEntities.FindValue(entity);
if (index > -1)
hEntities.Erase(index);
}
}
}
public void OnEntityDestroyed(int entity) {
for (int i = 1; i <= MaxClients; i++)
if (g_aPlayers[i]) {
ArrayList hEntities = g_aPlayers[i].hEntities;
int index = hEntities.FindValue(entity);
if (index > -1)
hEntities.Erase(index);
}
}
public void OnEntitySpawn_Post(int entity) {
float m_vecPushDir[3];
GetEntPropVector(entity, Prop_Data, "m_vecPushDir", m_vecPushDir);
float fPushSpeed = GetEntPropFloat(entity, Prop_Data, "m_flSpeed");
if (fPushSpeed > 250) {
if (RoundToNearest(m_vecPushDir[2]) != 0) {
if (g_fTriggerPushRising_Scale != 1.0)
SetEntPropFloat(entity, Prop_Data, "m_flSpeed", fPushSpeed * g_fTriggerPushRising_Scale);
} else {
if (g_fTriggerPushGround_Scale != 1.0)
SetEntPropFloat(entity, Prop_Data, "m_flSpeed", fPushSpeed * g_fTriggerPushGround_Scale);
}
}
SDKHook(entity, SDKHook_Touch, OnTouch);
SDKHook(entity, SDKHook_StartTouch, StartTouch);
SDKHook(entity, SDKHook_EndTouch, EndTouch);
}
public Action OnTouch(int entity, int other) {
if (g_bTriggerPushLagFixEnable && 0 < other <= MaxClients) {
if (!PassesTriggerFilters(entity, other)) {
#if defined Debug
PrintToChatAll("push not pass: %i => Client %N", entity, other);
#endif
return Plugin_Handled;
}
bool bDisabled = view_as<bool>(GetEntProp(entity, Prop_Data, "m_bDisabled"));
int iSpawnflags = GetEntProp(entity, Prop_Data, "m_spawnflags");
// dont move player if they're on ladder
if (GetEntityMoveType(other) == MOVETYPE_LADDER && !(iSpawnflags & SF_TRIG_PUSH_AFFECT_PLAYER_ON_LADDER)) {
return Plugin_Handled;
}
if (iSpawnflags == 1 && !bDisabled) {
#if defined Debug
float fGameTime = GetGameTime();
PrintToChatAll("push pass: %i => Client %N @%.2f", entity, other, fGameTime);
#endif
DoPush(other, (iSpawnflags & SF_TRIG_PUSH_ONCE) ? entity : -1);
return Plugin_Handled;
}
}
return Plugin_Continue;
}
public Action StartTouch(int entity, int other) {
if (g_bTriggerPushLagFixEnable && 0 < other <= MaxClients && PassesTriggerFilters(entity, other)) {
if (g_aPlayers[other]) {
if (IsClientOnObject(other))
g_aPlayers[other].bForceRise = true;
ArrayList hEntities = g_aPlayers[other].hEntities;
int index = hEntities.FindValue(entity);
if (index == -1)
hEntities.Push(entity);
}
#if defined Debug
PrintToChatAll("start touch: %i => Client %N [HammerID: %i]", entity, other, GetHammerIdOfEntity(entity));
#endif
}
return Plugin_Continue;
}
public Action EndTouch(int entity, int other) {
if (g_bTriggerPushLagFixEnable && 0 < other <= MaxClients && PassesTriggerFilters(entity, other)) {
if (g_aPlayers[other]) {
ArrayList hEntities = g_aPlayers[other].hEntities;
int index = hEntities.FindValue(entity);
if (index > -1)
hEntities.Erase(index);
}
#if defined Debug
PrintToChatAll("end touch: %i => Client %N [HammerID: %i]", entity, other, GetHammerIdOfEntity(entity));
#endif
}
return Plugin_Continue;
}
void DoPush(int other, int onceent = -1) {
float vecAbsDirTotal[3];
if (g_aPlayers[other]) {
ArrayList hEntities = g_aPlayers[other].hEntities;
for (int i = 0; i < hEntities.Length; i++) {
int entity = hEntities.Get(i);
float m_vecPushDir[3], angRotation[3], fPushSpeed;
fPushSpeed = GetEntPropFloat(entity, Prop_Data, "m_flSpeed");
GetEntPropVector(entity, Prop_Data, "m_vecPushDir", m_vecPushDir);
FindEntityParent_Main(entity, angRotation, false);
// Rotate vector according to world
float sr, sp, sy, cr, cp, cy;
float matrix[3][4];
SinCos(DegToRad(angRotation[1]), sy, cy);
SinCos(DegToRad(angRotation[0]), sp, cp);
SinCos(DegToRad(angRotation[2]), sr, cr);
matrix[0][0] = cp*cy;
matrix[1][0] = cp*sy;
matrix[2][0] = -sp;
float crcy = cr*cy;
float crsy = cr*sy;
float srcy = sr*cy;
float srsy = sr*sy;
matrix[0][1] = sp*srcy-crsy;
matrix[1][1] = sp*srsy+crcy;
matrix[2][1] = sr*cp;
matrix[0][2] = (sp*crcy+srsy);
matrix[1][2] = (sp*crsy-srcy);
matrix[2][2] = cr*cp;
matrix[0][3] = angRotation[0];
matrix[1][3] = angRotation[1];
matrix[2][3] = angRotation[2];
float vecAbsDir[3];
vecAbsDir[0] = m_vecPushDir[0]*matrix[0][0] + m_vecPushDir[1]*matrix[0][1] + m_vecPushDir[2]*matrix[0][2];
vecAbsDir[1] = m_vecPushDir[0]*matrix[1][0] + m_vecPushDir[1]*matrix[1][1] + m_vecPushDir[2]*matrix[1][2];
vecAbsDir[2] = m_vecPushDir[0]*matrix[2][0] + m_vecPushDir[1]*matrix[2][1] + m_vecPushDir[2]*matrix[2][2];
ScaleVector(vecAbsDir, fPushSpeed);
AddVectors(vecAbsDirTotal, vecAbsDir, vecAbsDirTotal);
}
}
float newVelocity[3];
if (onceent != -1) {
for (int x = 0; x < 3; x++) {
newVelocity[x] = GetEntDataFloat(other, iOffsVelocity + (x * 4));
}
AddVectors(newVelocity, vecAbsDirTotal, newVelocity);
SetEntDataVector(other, iOffsAbsVel, newVelocity);
SetEntDataVector(other, iOffsBaseVel, NULL_VECTOR);
if (vecAbsDirTotal[2] > 0.0) {
SetEntPropEnt(other, Prop_Data, "m_hGroundEntity", -1);
}
AcceptEntityInput(onceent, "Kill"); // remove the trigger so it only applies once
return;
}
// Apply the base velocity directly to abs velocity
for (int x = 0; x < 3; x++) {
newVelocity[x] = GetEntDataFloat(other, iOffsVelocity + (x * 4));
}
newVelocity[2] += vecAbsDirTotal[2] * GetTickInterval() * GetEntPropFloat(other, Prop_Data, "m_flLaggedMovementValue"); // frametime = tick_interval * laggedmovementvalue
if (g_aPlayers[other].bForceRise) {
if (IsClientOnObject(other) && 0.0 < newVelocity[2] <= 250.0) {
newVelocity[2] = 250.1;
#if defined Debug
PrintToChatAll("force rise: Client %N", other);
#endif
}
g_aPlayers[other].bForceRise = false;
}
SetEntDataVector(other, iOffsAbsVel, newVelocity);
SetEntDataVector(other, iOffsBaseVel, NULL_VECTOR);
// apply x, y as a base velocity so we travel at constant speed on conveyors
// Remove the base velocity z height so abs velocity can do it and add old base velocity if there is any
vecAbsDirTotal[2] = 0.0;
if (GetEntityFlags(other) & FL_BASEVELOCITY) {
float vecBaseVel[3];
GetEntDataVector(other, iOffsBaseVel, vecBaseVel);
AddVectors(vecAbsDirTotal, vecBaseVel, vecAbsDirTotal);
}
SetEntDataVector(other, iOffsBaseVel, vecAbsDirTotal);
SetEntityFlags(other, GetEntityFlags(other) | FL_BASEVELOCITY);
}
stock int FindEntityParent_Main(int entity, float Ang[3], bool inloop) {
int TempEntity;
float TempAng[3];
if (!inloop)
GetEntPropVector(entity, Prop_Data, "m_angRotation", Ang);
TempEntity = GetEntPropEnt(entity, Prop_Data, "m_hParent");
if (TempEntity == -1) {
if (!inloop)
return -1;
else
return entity;
}
GetEntPropVector(TempEntity, Prop_Data, "m_angRotation", TempAng);
AddVectors(Ang, TempAng, Ang);
if (Ang[1] > 360.0)
Ang[1] -= 360.0;
return FindEntityParent_Main(TempEntity, Ang, true);
}
stock void SinCos(float radians, float &sine, float &cosine) {
sine = Sine(radians);
cosine = Cosine(radians);
}
/**
* Return whether a client is standing on an object
*
* @param Client index
* @return True if client is standing on an object. False otherwise.
*/
stock bool IsClientOnObject(int client) {
return GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") > -1 ? true : false;
}
stock int GetHammerIdOfEntity(int entity) {
if (IsValidEntity(entity)) {
return GetEntProp(entity, Prop_Data, "m_iHammerID");
}
return -1;
}
stock bool PassesTriggerFilters(int entity, int client) {
return SDKCall(hTriggerPushPassesTriggerFilters, entity, client);
}