summaryrefslogtreecommitdiff
path: root/sourcemod/scripting/gokz-core/triggerfix.sp
diff options
context:
space:
mode:
Diffstat (limited to 'sourcemod/scripting/gokz-core/triggerfix.sp')
-rw-r--r--sourcemod/scripting/gokz-core/triggerfix.sp622
1 files changed, 0 insertions, 622 deletions
diff --git a/sourcemod/scripting/gokz-core/triggerfix.sp b/sourcemod/scripting/gokz-core/triggerfix.sp
deleted file mode 100644
index 424928d..0000000
--- a/sourcemod/scripting/gokz-core/triggerfix.sp
+++ /dev/null
@@ -1,622 +0,0 @@
-
-
-// Credits:
-// RNGFix made by rio https://github.com/jason-e/rngfix
-
-
-// Engine constants, NOT settings (do not change)
-#define LAND_HEIGHT 2.0 // Maximum height above ground at which you can "land"
-#define MIN_STANDABLE_ZNRM 0.7 // Minimum surface normal Z component of a walkable surface
-
-static int processMovementTicks[MAXPLAYERS+1];
-static float playerFrameTime[MAXPLAYERS+1];
-
-static bool touchingTrigger[MAXPLAYERS+1][2048];
-static int triggerTouchFired[MAXPLAYERS+1][2048];
-static int lastGroundEnt[MAXPLAYERS + 1];
-static bool duckedLastTick[MAXPLAYERS + 1];
-static bool mapTeleportedSequentialTicks[MAXPLAYERS+1];
-static bool jumpBugged[MAXPLAYERS + 1];
-static float jumpBugOrigin[MAXPLAYERS + 1][3];
-
-static ConVar cvGravity;
-
-static Handle acceptInputHookPre;
-static Handle processMovementHookPre;
-static Address serverGameEnts;
-static Handle markEntitiesAsTouching;
-static Handle passesTriggerFilters;
-
-public void OnPluginStart_Triggerfix()
-{
- HookEvent("player_jump", Event_PlayerJump);
-
- cvGravity = FindConVar("sv_gravity");
- if (cvGravity == null)
- {
- SetFailState("Could not find sv_gravity");
- }
-
- GameData gamedataConf = LoadGameConfigFile("gokz-core.games");
- if (gamedataConf == null)
- {
- SetFailState("Failed to load gokz-core gamedata");
- }
-
- // PassesTriggerFilters
- StartPrepSDKCall(SDKCall_Entity);
- if (!PrepSDKCall_SetFromConf(gamedataConf, SDKConf_Virtual, "CBaseTrigger::PassesTriggerFilters"))
- {
- SetFailState("Failed to get CBaseTrigger::PassesTriggerFilters offset");
- }
- PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain);
- PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer);
- passesTriggerFilters = EndPrepSDKCall();
-
- if (passesTriggerFilters == null) SetFailState("Unable to prepare SDKCall for CBaseTrigger::PassesTriggerFilters");
-
- // CreateInterface
- // Thanks SlidyBat and ici
- StartPrepSDKCall(SDKCall_Static);
- if (!PrepSDKCall_SetFromConf(gamedataConf, SDKConf_Signature, "CreateInterface"))
- {
- SetFailState("Failed to get CreateInterface");
- }
- PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
- PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
- PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
- Handle CreateInterface = EndPrepSDKCall();
-
- if (CreateInterface == null)
- {
- SetFailState("Unable to prepare SDKCall for CreateInterface");
- }
-
- char interfaceName[64];
-
- // ProcessMovement
- if (!GameConfGetKeyValue(gamedataConf, "IGameMovement", interfaceName, sizeof(interfaceName)))
- {
- SetFailState("Failed to get IGameMovement interface name");
- }
- Address IGameMovement = SDKCall(CreateInterface, interfaceName, 0);
- if (!IGameMovement)
- {
- SetFailState("Failed to get IGameMovement pointer");
- }
-
- int offset = GameConfGetOffset(gamedataConf, "ProcessMovement");
- if (offset == -1)
- {
- SetFailState("Failed to get ProcessMovement offset");
- }
-
- processMovementHookPre = DHookCreate(offset, HookType_Raw, ReturnType_Void, ThisPointer_Ignore, DHook_ProcessMovementPre);
- DHookAddParam(processMovementHookPre, HookParamType_CBaseEntity);
- DHookAddParam(processMovementHookPre, HookParamType_ObjectPtr);
- DHookRaw(processMovementHookPre, false, IGameMovement);
-
- // MarkEntitiesAsTouching
- if (!GameConfGetKeyValue(gamedataConf, "IServerGameEnts", interfaceName, sizeof(interfaceName)))
- {
- SetFailState("Failed to get IServerGameEnts interface name");
- }
- serverGameEnts = SDKCall(CreateInterface, interfaceName, 0);
- if (!serverGameEnts)
- {
- SetFailState("Failed to get IServerGameEnts pointer");
- }
-
- StartPrepSDKCall(SDKCall_Raw);
- if (!PrepSDKCall_SetFromConf(gamedataConf, SDKConf_Virtual, "IServerGameEnts::MarkEntitiesAsTouching"))
- {
- SetFailState("Failed to get IServerGameEnts::MarkEntitiesAsTouching offset");
- }
- PrepSDKCall_AddParameter(SDKType_Edict, SDKPass_Pointer);
- PrepSDKCall_AddParameter(SDKType_Edict, SDKPass_Pointer);
- markEntitiesAsTouching = EndPrepSDKCall();
-
- if (markEntitiesAsTouching == null)
- {
- SetFailState("Unable to prepare SDKCall for IServerGameEnts::MarkEntitiesAsTouching");
- }
-
- gamedataConf = LoadGameConfigFile("sdktools.games/engine.csgo");
- offset = gamedataConf.GetOffset("AcceptInput");
- if (offset == -1)
- {
- SetFailState("Failed to get AcceptInput offset");
- }
-
- acceptInputHookPre = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, DHooks_AcceptInput);
- DHookAddParam(acceptInputHookPre, HookParamType_CharPtr);
- DHookAddParam(acceptInputHookPre, HookParamType_CBaseEntity);
- DHookAddParam(acceptInputHookPre, HookParamType_CBaseEntity);
- //varaint_t is a union of 12 (float[3]) plus two int type params 12 + 8 = 20
- DHookAddParam(acceptInputHookPre, HookParamType_Object, 20, DHookPass_ByVal|DHookPass_ODTOR|DHookPass_OCTOR|DHookPass_OASSIGNOP);
- DHookAddParam(acceptInputHookPre, HookParamType_Int);
-
- delete CreateInterface;
- delete gamedataConf;
-
- if (gB_LateLoad)
- {
- for (int client = 1; client <= MaxClients; client++)
- {
- if (IsClientInGame(client)) OnClientPutInServer(client);
- }
-
- char classname[64];
- for (int entity = MaxClients+1; entity < sizeof(touchingTrigger[]); entity++)
- {
- if (!IsValidEntity(entity)) continue;
- GetEntPropString(entity, Prop_Data, "m_iClassname", classname, sizeof(classname));
- HookTrigger(entity, classname);
- }
- }
-}
-
-public void OnEntityCreated_Triggerfix(int entity, const char[] classname)
-{
- if (entity >= sizeof(touchingTrigger[]))
- {
- return;
- }
- HookTrigger(entity, classname);
-}
-
-public void OnClientConnected_Triggerfix(int client)
-{
- processMovementTicks[client] = 0;
- for (int i = 0; i < sizeof(touchingTrigger[]); i++)
- {
- touchingTrigger[client][i] = false;
- triggerTouchFired[client][i] = 0;
- }
-}
-
-public void OnClientPutInServer_Triggerfix(int client)
-{
- SDKHook(client, SDKHook_PostThink, Hook_PlayerPostThink);
- DHookEntity(acceptInputHookPre, false, client);
-}
-
-public void OnGameFrame_Triggerfix()
-{
- // Loop through all the players and make sure that triggers that are supposed to be fired but weren't now
- // get fired properly.
- // This must be run OUTSIDE of usercmd, because sometimes usercmd gets delayed heavily.
- for (int client = 1; client <= MaxClients; client++)
- {
- if (IsValidClient(client) && IsPlayerAlive(client) && !CheckWater(client) &&
- (GetEntityMoveType(client) == MOVETYPE_WALK || GetEntityMoveType(client) == MOVETYPE_LADDER))
- {
- DoTriggerFix(client);
-
- // Reset the Touch tracking.
- // We save a bit of performance by putting this inside the loop
- // Even if triggerTouchFired is not correct, touchingTrigger still is.
- // That should prevent DoTriggerFix from activating the wrong triggers.
- // Plus, players respawn where they previously are as well with a timer on,
- // so this should not be a big problem.
- for (int trigger = 0; trigger < sizeof(triggerTouchFired[]); trigger++)
- {
- triggerTouchFired[client][trigger] = 0;
- }
- }
- }
-}
-
-void OnPlayerRunCmd_Triggerfix(int client)
-{
- // Reset the Touch tracking.
- // While this is mostly unnecessary, it can also happen that the server runs multiple ticks of player movement at once,
- // therefore the triggers need to be checked again.
- for (int trigger = 0; trigger < sizeof(triggerTouchFired[]); trigger++)
- {
- triggerTouchFired[client][trigger] = 0;
- }
-}
-
-static void Event_PlayerJump(Event event, const char[] name, bool dontBroadcast)
-{
- int client = GetClientOfUserId(event.GetInt("userid"));
-
- jumpBugged[client] = !!lastGroundEnt[client];
- if (jumpBugged[client])
- {
- GetClientAbsOrigin(client, jumpBugOrigin[client]);
- // if player's origin is still in the ducking position then adjust for that.
- if (duckedLastTick[client] && !Movement_GetDucking(client))
- {
- jumpBugOrigin[client][2] -= 9.0;
- }
- }
-}
-
-static Action Hook_TriggerStartTouch(int entity, int other)
-{
- if (1 <= other <= MaxClients)
- {
- touchingTrigger[other][entity] = true;
- }
-
- return Plugin_Continue;
-}
-
-static Action Hook_TriggerEndTouch(int entity, int other)
-{
- if (1 <= other <= MaxClients)
- {
- touchingTrigger[other][entity] = false;
- }
- return Plugin_Continue;
-}
-
-static Action Hook_TriggerTouch(int entity, int other)
-{
- if (1 <= other <= MaxClients)
- {
- triggerTouchFired[other][entity]++;
- }
- return Plugin_Continue;
-}
-
-static MRESReturn DHook_ProcessMovementPre(Handle hParams)
-{
- int client = DHookGetParam(hParams, 1);
-
- processMovementTicks[client]++;
- playerFrameTime[client] = GetTickInterval() * GetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue");
- mapTeleportedSequentialTicks[client] = false;
-
- if (IsPlayerAlive(client))
- {
- if (GetEntityMoveType(client) == MOVETYPE_WALK
- && !CheckWater(client))
- {
- lastGroundEnt[client] = GetEntPropEnt(client, Prop_Data, "m_hGroundEntity");
- }
- duckedLastTick[client] = Movement_GetDucking(client);
- }
-
- return MRES_Ignored;
-}
-
-static MRESReturn DHooks_AcceptInput(int client, DHookReturn hReturn, DHookParam hParams)
-{
- if (!IsValidClient(client) || !IsPlayerAlive(client) || CheckWater(client) ||
- (GetEntityMoveType(client) != MOVETYPE_WALK && GetEntityMoveType(client) != MOVETYPE_LADDER))
- {
- return MRES_Ignored;
- }
-
- // Get args
- static char param[64];
- static char command[64];
- DHookGetParamString(hParams, 1, command, sizeof(command));
- if (StrEqual(command, "AddOutput"))
- {
- DHookGetParamObjectPtrString(hParams, 4, 0, ObjectValueType_String, param, sizeof(param));
- char kv[16];
- SplitString(param, " ", kv, sizeof(kv));
- // KVs are case insensitive.
- // Any of these inputs can change the filter behavior.
- if (StrEqual(kv[0], "targetname", false) || StrEqual(kv[0], "teamnumber", false) || StrEqual(kv[0], "classname", false) || StrEqual(command, "ResponseContext", false))
- {
- DoTriggerFix(client, true);
- }
- }
- else if (StrEqual(command, "AddContext") || StrEqual(command, "RemoveContext") || StrEqual(command, "ClearContext"))
- {
- DoTriggerFix(client, true);
- }
- return MRES_Ignored;
-}
-
-static bool DoTriggerFix(int client, bool filterFix = false)
-{
- // Adapted from DoTriggerjumpFix right below.
- float landingMins[3], landingMaxs[3];
- float origin[3];
-
- GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", origin);
- GetEntPropVector(client, Prop_Data, "m_vecMins", landingMins);
- GetEntPropVector(client, Prop_Data, "m_vecMaxs", landingMaxs);
-
- ArrayList triggers = new ArrayList();
- // Get a list of triggers that we are touching now.
-
- TR_EnumerateEntitiesHull(origin, origin, landingMins, landingMaxs, true, AddTrigger, triggers);
-
- bool didSomething = false;
-
- for (int i = 0; i < triggers.Length; i++)
- {
- int trigger = triggers.Get(i);
- if (!touchingTrigger[client][trigger])
- {
- // Normally this wouldn't happen, because the trigger should be colliding with the player's hull if it gets here.
- continue;
- }
- char className[64];
- GetEntityClassname(trigger, className, sizeof(className));
- if (StrEqual(className, "trigger_push"))
- {
- // Completely ignore push triggers.
- continue;
- }
- if (filterFix && SDKCall(passesTriggerFilters, trigger, client) && triggerTouchFired[client][trigger] < GOKZ_MAX_RETOUCH_TRIGGER_COUNT)
- {
- // MarkEntitiesAsTouching always fires the Touch function even if it was already fired this tick.
- SDKCall(markEntitiesAsTouching, serverGameEnts, client, trigger);
-
- // Player properties might be changed right after this so it will need to be triggered again.
- // Triggers changing this filter will loop onto itself infintely so we need to avoid that.
- triggerTouchFired[client][trigger]++;
- didSomething = true;
- }
- else if (!triggerTouchFired[client][trigger])
- {
- // If the player is still touching the trigger on this tick, and Touch was not called for whatever reason
- // in the last tick, we make sure that it is called now.
- SDKCall(markEntitiesAsTouching, serverGameEnts, client, trigger);
- triggerTouchFired[client][trigger]++;
- didSomething = true;
- }
- }
-
- delete triggers;
-
- return didSomething;
-}
-
-static bool DoTriggerjumpFix(int client, const float landingPoint[3], const float landingMins[3], const float landingMaxs[3])
-{
- // It's possible to land above a trigger but also in another trigger_teleport, have the teleport move you to
- // another location, and then the trigger jumping fix wouldn't fire the other trigger you technically landed above,
- // but I can't imagine a mapper would ever actually stack triggers like that.
-
- float origin[3];
- GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", origin);
-
- float landingMaxsBelow[3];
- landingMaxsBelow[0] = landingMaxs[0];
- landingMaxsBelow[1] = landingMaxs[1];
- landingMaxsBelow[2] = origin[2] - landingPoint[2];
-
- ArrayList triggers = new ArrayList();
-
- // Find triggers that are between us and the ground (using the bounding box quadrant we landed with if applicable).
- // This will fail on triggers thinner than 0.03125 unit thick, but it's highly unlikely that a mapper would put a trigger that thin.
- TR_EnumerateEntitiesHull(landingPoint, landingPoint, landingMins, landingMaxsBelow, true, AddTrigger, triggers);
-
- bool didSomething = false;
-
- for (int i = 0; i < triggers.Length; i++)
- {
- int trigger = triggers.Get(i);
-
- // MarkEntitiesAsTouching always fires the Touch function even if it was already fired this tick.
- // In case that could cause side-effects, manually keep track of triggers we are actually touching
- // and don't re-touch them.
- if (touchingTrigger[client][trigger])
- {
- continue;
- }
-
- SDKCall(markEntitiesAsTouching, serverGameEnts, client, trigger);
- didSomething = true;
- }
-
- delete triggers;
-
- return didSomething;
-}
-
-// PostThink works a little better than a ProcessMovement post hook because we need to wait for ProcessImpacts (trigger activation)
-static void Hook_PlayerPostThink(int client)
-{
- if (!IsPlayerAlive(client)
- || GetEntityMoveType(client) != MOVETYPE_WALK
- || CheckWater(client))
- {
- return;
- }
-
- bool landed = (GetEntPropEnt(client, Prop_Data, "m_hGroundEntity") != -1
- && lastGroundEnt[client] == -1)
- || jumpBugged[client];
-
- float landingMins[3], landingMaxs[3], landingPoint[3];
-
- // Get info about the ground we landed on (if we need to do landing fixes).
- if (landed)
- {
- float origin[3], nrm[3], velocity[3];
- GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", origin);
- GetEntPropVector(client, Prop_Data, "m_vecVelocity", velocity);
-
- if (jumpBugged[client])
- {
- origin = jumpBugOrigin[client];
- }
-
- GetEntPropVector(client, Prop_Data, "m_vecMins", landingMins);
- GetEntPropVector(client, Prop_Data, "m_vecMaxs", landingMaxs);
-
- float originBelow[3];
- originBelow[0] = origin[0];
- originBelow[1] = origin[1];
- originBelow[2] = origin[2] - LAND_HEIGHT;
-
- TR_TraceHullFilter(origin, originBelow, landingMins, landingMaxs, MASK_PLAYERSOLID, PlayerFilter);
-
- if (!TR_DidHit())
- {
- // This should never happen, since we know we are on the ground.
- landed = false;
- }
- else
- {
- TR_GetPlaneNormal(null, nrm);
-
- if (nrm[2] < MIN_STANDABLE_ZNRM)
- {
- // This is rare, and how the incline fix should behave isn't entirely clear because maybe we should
- // collide with multiple faces at once in this case, but let's just get the ground we officially
- // landed on and use that for our ground normal.
-
- // landingMins and landingMaxs will contain the final values used to find the ground after returning.
- if (TracePlayerBBoxForGround(origin, originBelow, landingMins, landingMaxs))
- {
- TR_GetPlaneNormal(null, nrm);
- }
- else
- {
- // This should also never happen.
- landed = false;
- }
- }
-
- TR_GetEndPosition(landingPoint);
- }
- }
-
- // reset it here because we don't need it again
- jumpBugged[client] = false;
-
- // Must use TR_DidHit because if the unduck origin is closer than 0.03125 units from the ground,
- // the trace fraction would return 0.0.
- if (landed && TR_DidHit())
- {
- DoTriggerjumpFix(client, landingPoint, landingMins, landingMaxs);
- // Check if a trigger we just touched put us in the air (probably due to a teleport).
- if (GetEntityFlags(client) & FL_ONGROUND == 0)
- {
- landed = false;
- }
- }
-}
-
-static bool PlayerFilter(int entity, int mask)
-{
- return !(1 <= entity <= MaxClients);
-}
-
-static void HookTrigger(int entity, const char[] classname)
-{
- if (StrContains(classname, "trigger_") != -1)
- {
- SDKHook(entity, SDKHook_StartTouchPost, Hook_TriggerStartTouch);
- SDKHook(entity, SDKHook_EndTouchPost, Hook_TriggerEndTouch);
- SDKHook(entity, SDKHook_TouchPost, Hook_TriggerTouch);
- }
-}
-
-static bool CheckWater(int client)
-{
- // The cached water level is updated multiple times per tick, including after movement happens,
- // so we can just check the cached value here.
- return GetEntProp(client, Prop_Data, "m_nWaterLevel") > 1;
-}
-
-public bool AddTrigger(int entity, ArrayList triggers)
-{
- TR_ClipCurrentRayToEntity(MASK_ALL, entity);
- if (TR_DidHit())
- {
- triggers.Push(entity);
- }
-
- return true;
-}
-
-static bool TracePlayerBBoxForGround(const float origin[3], const float originBelow[3], float mins[3], float maxs[3])
-{
- // See CGameMovement::TracePlayerBBoxForGround()
-
- float origMins[3], origMaxs[3];
- origMins = mins;
- origMaxs = maxs;
-
- float nrm[3];
-
- mins = origMins;
-
- // -x -y
- maxs[0] = origMaxs[0] > 0.0 ? 0.0 : origMaxs[0];
- maxs[1] = origMaxs[1] > 0.0 ? 0.0 : origMaxs[1];
- maxs[2] = origMaxs[2];
-
- TR_TraceHullFilter(origin, originBelow, mins, maxs, MASK_PLAYERSOLID, PlayerFilter);
-
- if (TR_DidHit())
- {
- TR_GetPlaneNormal(null, nrm);
- if (nrm[2] >= MIN_STANDABLE_ZNRM)
- {
- return true;
- }
- }
-
- // +x +y
- mins[0] = origMins[0] < 0.0 ? 0.0 : origMins[0];
- mins[1] = origMins[1] < 0.0 ? 0.0 : origMins[1];
- mins[2] = origMins[2];
-
- maxs = origMaxs;
-
- TR_TraceHullFilter(origin, originBelow, mins, maxs, MASK_PLAYERSOLID, PlayerFilter);
-
- if (TR_DidHit())
- {
- TR_GetPlaneNormal(null, nrm);
- if (nrm[2] >= MIN_STANDABLE_ZNRM)
- {
- return true;
- }
- }
-
- // -x +y
- mins[0] = origMins[0];
- mins[1] = origMins[1] < 0.0 ? 0.0 : origMins[1];
- mins[2] = origMins[2];
-
- maxs[0] = origMaxs[0] > 0.0 ? 0.0 : origMaxs[0];
- maxs[1] = origMaxs[1];
- maxs[2] = origMaxs[2];
-
- TR_TraceHullFilter(origin, originBelow, mins, maxs, MASK_PLAYERSOLID, PlayerFilter);
-
- if (TR_DidHit())
- {
- TR_GetPlaneNormal(null, nrm);
- if (nrm[2] >= MIN_STANDABLE_ZNRM)
- {
- return true;
- }
- }
-
- // +x -y
- mins[0] = origMins[0] < 0.0 ? 0.0 : origMins[0];
- mins[1] = origMins[1];
- mins[2] = origMins[2];
-
- maxs[0] = origMaxs[0];
- maxs[1] = origMaxs[1] > 0.0 ? 0.0 : origMaxs[1];
- maxs[2] = origMaxs[2];
-
- TR_TraceHullFilter(origin, originBelow, mins, maxs, MASK_PLAYERSOLID, PlayerFilter);
-
- if (TR_DidHit())
- {
- TR_GetPlaneNormal(null, nrm);
- if (nrm[2] >= MIN_STANDABLE_ZNRM)
- {
- return true;
- }
- }
-
- return false;
-}