Skip to content

Commit

Permalink
Fix mounting ladders with many players (#117)
Browse files Browse the repository at this point in the history
* Fix mounting ladders with many players

* Change to more methodmaps.

* Update entitypatch.inc

* r_bloomtintg_nextgen was missing
Just noticed that r_bloomtint*g*_nextgen was missing, showing r_bloomtint*b*_nextgen twice.

* Simplify ladder/trace code

* Fix distance check.
- However, this is currently only set up for the top and bottom of the ladder, not anywhere in the middle. This won't affect most scenarios, and it could be changed to do so. Depends on what we want/need.

* nits

---------

Co-authored-by: Alienmario <[email protected]>
  • Loading branch information
Balimbanana and Alienmario authored May 2, 2024
1 parent c1bd1d7 commit ffed980
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 39 deletions.
1 change: 1 addition & 0 deletions scripting/include/srccoop.inc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
#define PLAYERPATCH_SERVERSIDE_RAGDOLLS
#define PLAYERPATCH_RESTORE_MP_FORCERESPAWN
#define PLAYERPATCH_OVERRIDE_DEATH_OBSMODE
#define PLAYERPATCH_FINDLADDER

#define GAMEPATCH_UTIL_GETLOCALPLAYER
#define GAMEPATCH_IS_MULTIPLAYER
Expand Down
125 changes: 87 additions & 38 deletions scripting/include/srccoop/classdef.inc
Original file line number Diff line number Diff line change
Expand Up @@ -741,33 +741,6 @@ enum struct FireOutputData
float m_flDelay;
}

methodmap CTraceRay
{
public CTraceRay(const float vecPosition[3], const float vecRayType[3], const int iFlags, const RayType rayType, const TraceEntityFilter traceFilter, const any pData)
{
return view_as<CTraceRay>(TR_TraceRayFilterEx(vecPosition, vecRayType, iFlags, rayType, traceFilter, pData));
}

public Handle GetHandle()
{
return view_as<Handle>(this);
}
public bool IsValid()
{
return view_as<bool>(this.GetHandle() != null);
}
public bool Close()
{
if (this.IsValid())
CloseHandle(this.GetHandle());
}

public CBaseEntity GetEntity()
{
return CBaseEntity(TR_GetEntityIndex(this.GetHandle()));
}
}

methodmap CBaseAnimating < CBaseEntity
{
public CBaseAnimating(const int iEntIndex = -1)
Expand Down Expand Up @@ -1315,6 +1288,10 @@ methodmap CBasePlayer < CBaseCombatCharacter
{
return GetEntProp(this.GetEntIndex(), Prop_Data, "m_afButtonReleased");
}
public int GetLastButtons()
{
return GetEntProp(this.GetEntIndex(), Prop_Data, "m_afButtonLast");
}
public bool WasPressingButton(const int iButton)
{
return view_as<bool>(this.GetOldButtons() & iButton);
Expand Down Expand Up @@ -1370,15 +1347,10 @@ methodmap CBasePlayer < CBaseCombatCharacter
this.GetEyePosition(vecEyePos);
this.GetEyeAngles(vecEyeAngles);

CTraceRay pTraceRay = CTraceRay(vecEyePos, vecEyeAngles, MASK_SHOT, RayType_Infinite, Callback_GetAimTarget, this);
if (pTraceRay.IsValid())
{
CBaseEntity pEntity = pTraceRay.GetEntity();
pTraceRay.Close();
return pEntity;
}

return NULL_CBASEENTITY;
CTraceRay pTraceRay = new CTraceRay(vecEyePos, vecEyeAngles, MASK_SHOT, RayType_Infinite, TraceEntityFilter_IgnoreData, this.entindex);
CBaseEntity pEntity = pTraceRay.GetEntity();
pTraceRay.Close();
return pEntity;
}
public void SetMaxSpeed(const float flMaxSpeed)
{
Expand Down Expand Up @@ -1523,6 +1495,18 @@ methodmap CBasePlayer < CBaseCombatCharacter
{
ForcePlayerSuicide(this.GetEntIndex());
}
public CFuncLadder GetLadder()
{
return CFuncLadder(GetEntPropEnt(this.GetEntIndex(), Prop_Data, "m_hLadder"));
}
public void SetLadder(CFuncLadder pLadder)
{
if (this.GetLadder().IsValid())
{
this.GetLadder().FireOutput("OnPlayerGotOffLadder", this.GetEntIndex());
}
SetEntPropEnt(this.GetEntIndex(), Prop_Data, "m_hLadder", pLadder.entindex);
}
}

methodmap CSprite < CBaseEntity
Expand Down Expand Up @@ -1694,6 +1678,47 @@ methodmap CParticleSystem < CBaseEntity
}
}

methodmap CFuncLadder < CBaseEntity
{
public CFuncLadder(const int iEntIndex = -1)
{
return view_as<CFuncLadder>(CBaseEntity(iEntIndex));
}
public bool IsEnabled()
{
return !GetEntProp(this.GetEntIndex(), Prop_Data, "m_bDisabled");
}
public void GetTopPosition(float vecBuffer[3])
{
GetEntPropVector(this.GetEntIndex(), Prop_Data, "m_vecPlayerMountPositionTop", vecBuffer);
float vecLocalOrigin[3];
this.GetOrigin(vecLocalOrigin);
AddVectors(vecBuffer, vecLocalOrigin, vecBuffer);

CBaseEntity pParent = this.GetParent();
if (pParent.IsValid())
{
// Technically this should be using m_rgflCoordinateFrame which is a const matrix3x4_t, but if we just add AbsOrigin, it *should* be accurate enough...
pParent.GetAbsOrigin(vecLocalOrigin);
AddVectors(vecBuffer, vecLocalOrigin, vecBuffer);
}
}
public void GetBottomPosition(float vecBuffer[3])
{
GetEntPropVector(this.GetEntIndex(), Prop_Data, "m_vecPlayerMountPositionBottom", vecBuffer);
float vecLocalOrigin[3];
this.GetOrigin(vecLocalOrigin);
AddVectors(vecBuffer, vecLocalOrigin, vecBuffer);

CBaseEntity pParent = this.GetParent();
if (pParent.IsValid())
{
pParent.GetAbsOrigin(vecLocalOrigin);
AddVectors(vecBuffer, vecLocalOrigin, vecBuffer);
}
}
}

methodmap CMultiplayRules
{
public static bool IsTeamplay()
Expand Down Expand Up @@ -1800,7 +1825,31 @@ methodmap IServerGameDLL
}
}

public bool Callback_GetAimTarget(int iEntity, int iMask, any pData)
methodmap CTraceRay < Handle
{
public CTraceRay(const float vecPosition[3], const float vecRayType[3], const int iFlags, const RayType rayType, const TraceEntityFilter traceFilter, const any pData)
{
return view_as<CTraceRay>(TR_TraceRayFilterEx(vecPosition, vecRayType, iFlags, rayType, traceFilter, pData));
}
public float GetFraction()
{
return TR_GetFraction(this);
}
public CBaseEntity GetEntity()
{
return CBaseEntity(TR_GetEntityIndex(this));
}
}

public bool TraceEntityFilter_IgnoreData(int iEntity, int iMask, any pData)
{
return !view_as<bool>(iEntity == pData);
return (iEntity != pData);
}

public bool TraceEntityFilter_IgnorePlayers(int iEntity, int iMask, any pData)
{
CBasePlayer pPlayer = CBasePlayer(iEntity);
if (pPlayer.IsValid())
return false;
return (iEntity != pData);
}
115 changes: 114 additions & 1 deletion scripting/include/srccoop/playerpatch.inc
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ public Action OnPlayerRunCmd(int iClient, int &iButtons, int &iImpulse, float fV
return Plugin_Changed;
}

#if defined PLAYERPATCH_FINDLADDER
// By using m_afButtonPressed, this is actually ignored by the game code if players mount ladders the normal way as it calls ::SwallowUseKey()
if ((GetEntProp(iClient, Prop_Data, "m_afButtonPressed") & IN_USE) && (GetEntProp(iClient, Prop_Data, "m_afButtonLast") & IN_USE) == 0)
{
Movement_FindLadder(CBasePlayer(iClient));
}
#endif

return Plugin_Continue;
}

Expand Down Expand Up @@ -361,7 +369,7 @@ public MRESReturn Hook_PlayerSpawnPost(int iClient, Handle hReturn, Handle hPara

QueryClientConVar(iClient, "r_bloomtintexponent_nextgen", QueryConVar_Bloom, 2.2);
QueryClientConVar(iClient, "r_bloomtintr_nextgen", QueryConVar_Bloom, 0.25);
QueryClientConVar(iClient, "r_bloomtintb_nextgen", QueryConVar_Bloom, 0.25);
QueryClientConVar(iClient, "r_bloomtintg_nextgen", QueryConVar_Bloom, 0.25);
QueryClientConVar(iClient, "r_bloomtintb_nextgen", QueryConVar_Bloom, 0.25);
QueryClientConVar(iClient, "gb_flashlight_intensity", QueryConVar_Bloom, 0.8);

Expand Down Expand Up @@ -679,6 +687,111 @@ public MRESReturn Hook_ForcePlayerToDropThisObject(Handle hParams)
return MRES_Supercede;
}

//------------------------------------------------------
// CHL2GameMovement::Findladder
// fix issue of FindLadder trace not passing through additional players making it difficult to use ladders with many players
//------------------------------------------------------
public void Movement_FindLadder(CBasePlayer pPlayer)
{
// If we don't have a valid player, don't run
if (!pPlayer.IsValid() || pPlayer.GetLadder().IsValid())
return;

static float flMaxDist = 64.0;
float bestDist = 16384.0; // Or MAX_COORD_INTEGER
float bestOrigin[3];
CFuncLadder bestLadder = NULL_CBASEENTITY;

//float maxdistSqr = flMaxDist * flMaxDist;
float closest[3];

// Normally this would be by static member: CFuncLadder::GetLadderCount()
ArrayList pLadders = new ArrayList();
int iEntity = -1;
while ((iEntity = FindEntityByClassname(iEntity, "func_useableladder")) != INVALID_ENT_REFERENCE)
{
pLadders.Push(CFuncLadder(iEntity));
}

float vecPlayerOrigin[3];
float vecTmp[3];
float distSqr;
pPlayer.GetAbsOrigin(vecPlayerOrigin);
pPlayer.GetMaxs(vecTmp);
float sizeZ = vecTmp[2];
pPlayer.GetMins(vecTmp);
sizeZ = (sizeZ - vecTmp[2]) * 0.5;

int len = pLadders.Length;
for (int i = 0; i < len; i++)
{
CFuncLadder pLadder = pLadders.Get(i);

if (!pLadder.IsEnabled())
continue;

float topPosition[3], bottomPosition[3];
pLadder.GetTopPosition(topPosition);
pLadder.GetBottomPosition(bottomPosition);

if ((vecPlayerOrigin[2] < bottomPosition[2]) || (vecPlayerOrigin[2] > topPosition[2]))
continue;

// Have to do both for slanted ladders, also now just checking for bottom and top instead of anywhere along ladder line,
// this could potentially be changed by setting bottomPosition[2] = vecPlayerOrigin[2] and test distance though.
float distTop = GetVectorDistance(vecPlayerOrigin, topPosition, false);
float distBot = GetVectorDistance(vecPlayerOrigin, bottomPosition, false);
if (distTop > distBot)
{
distSqr = distBot;
closest = bottomPosition;
}
else
{
distSqr = distTop;
closest = topPosition;
}

if (distSqr > flMaxDist)
continue;

// Finally the traces that need to be overridden to ignore players in the way...
CTraceRay pTraceRay = new CTraceRay(vecPlayerOrigin, closest, MASK_PLAYERSOLID, RayType_EndPoint, TraceEntityFilter_IgnorePlayers, -1);
if (pTraceRay.GetFraction() != 1.0 && pTraceRay.GetEntity() != pLadder)
{
pTraceRay.Close();

AddVectors(vecTmp, vecPlayerOrigin, vecTmp);
vecTmp[2] += sizeZ;
pTraceRay = new CTraceRay(vecTmp, closest, MASK_PLAYERSOLID, RayType_EndPoint, TraceEntityFilter_IgnorePlayers, -1);
if (pTraceRay.GetFraction() != 1.0 && pTraceRay.GetEntity() != pLadder)
{
pTraceRay.Close();
continue;
}
}
pTraceRay.Close();

// See if this is the best one so far
if (distSqr < bestDist)
{
bestDist = distSqr;
bestLadder = pLadder;
bestOrigin = closest;
}
}
pLadders.Close();

if (bestLadder != NULL_CBASEENTITY)
{
// Because there is no smoothing/adjustments, jump up to where player feet are
if (vecPlayerOrigin[2] > bestOrigin[2])
bestOrigin[2] = vecPlayerOrigin[2];
pPlayer.Teleport(bestOrigin);
pPlayer.SetLadder(bestLadder);
}
}

//------------------------------------------------------
// Item packing
// Detaches and stores player's equipped items.
Expand Down

0 comments on commit ffed980

Please sign in to comment.