441 lines
14 KiB
SourcePawn
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);
|
||
|
}
|