View Single Post
cravenge
Veteran Member
Join Date: Nov 2015
Location: Chocolate Factory
Old 11-07-2021 , 13:17   Re: [L4D2] Collision Hook
Reply With Quote #22

I just did some more research and I happened to find something quite interesting.

Originally, from the SDK:
PHP Code:
bool PassServerEntityFilter( const IHandleEntity *pTouch, const IHandleEntity *pPass 
{
    if ( !
pPass )
        return 
true;

    if ( 
pTouch == pPass )
        return 
false;

    const 
CBaseEntity *pEntTouch EntityFromEntityHandlepTouch );
    const 
CBaseEntity *pEntPass EntityFromEntityHandlepPass );
    if ( !
pEntTouch || !pEntPass )
        return 
true;

    
// don't clip against own missiles
    
if ( pEntTouch->GetOwnerEntity() == pEntPass )
        return 
false;
    
    
// don't clip against owner
    
if ( pEntPass->GetOwnerEntity() == pEntTouch )
        return 
false;    


    return 
true;

By simply looking at this, it would seem that returning true will allow the entity from passing through the other. Otherwise, block it from happening.

Translating this into a plugin will result to:
PHP Code:
public MRESReturn PassServerEntityFilter(DHookReturn hReturnDHookParam hParams)
{
    
int pTouch hParams.Get(1);
    
int pPass hParams.Get(2);
    
    if (!
pPass)
    {
        
hReturn.Value false;
        return 
MRES_Supercede;
    }
    
    if (
pTouch != pPass)
    {
        
// From what I've gathered from Ghidra's decompiler, it would seem that either one of these
        // entity handle pointers can be null when passed as a parameter onto an SDKCall since the
        // result will always be true but only on Linux. Windows, however, does not allow this and
        // will most likely result in a crash.
        
if (IsStaticProp(pTouch) || IsStaticProp(pPass))
        {
            
// This should be false but let's just hope it will prevent entities from phasing through
            // walls and falling into an endless void then crashing the server after some time :p
            
hReturn.Value true;
            return 
MRES_Supercede;
        }
        
        
int pEntTouch GetBaseEntity(pTouch);
        
int pEntPass GetBaseEntity(pPass);
        
        if (
pEntTouch != -&& pEntPass != -1)
        {
            
// Windows: 0x20c -> 524
            // Linux: 0x220 -> 544
            // Both offsets point to "m_hOwnerEntity" property
            
if (GetEntPropEnt(pEntTouchProp_Data"m_hOwnerEntity") == pEntPass || GetEntPropEnt(pEntPassProp_Data"m_hOwnerEntity") == pEntTouch)
            {
                
hReturn.Value true;
                return 
MRES_Supercede;
            }
            
            
// ...
        
}
        else
        {
            
hReturn.Value false;
        }
    }
    else
    {
        
hReturn.Value true;
    }
    return 
MRES_Supercede;

After detouring the function, the logic is somehow inverted for some unknown reason. At least that's what I concluded from how I've seen plugins change the result through the forward.

It really was quite a head scratcher while analyzing this thoroughly. Of course, you can correct me if I made any mistakes. That would help me understand it better and ease the headache I got from this alone.

Last edited by cravenge; 11-07-2021 at 13:33.
cravenge is offline