#pragma semicolon 1 #pragma newdecls required #include #include #include #include #include //#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(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(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(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(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); }