View Single Post
dcx2
Senior Member
Join Date: Sep 2011
Old 01-02-2012 , 23:47   Re: Player-Teleport (sm_goto, sm_bring)
Reply With Quote #30

Hi HyperKiLLeR,

Thank you for your teleportation plugin. Yours is the only version with a goto, which is a feature I wanted. It mostly works for L4D2. I say mostly because if you aim at a wall or a ceiling they will become stuck.

I had an idea. Get the collision point, and then do a bounds check with the client mins/maxs. If the player would become stuck, walk the ray backwards a little bit and try it again, until you collide with yourself or you've taken 100 steps. If you can't succeed, try again from the feet; this allows you to hit the ceiling. If that fails too, then they teleport to you, much like sm_goto.

I also wanted to change to a MASK_SHOT filter for collision, so I can teleport through fences and stuff like that. And I wanted ProcessTargetString support.

So I made these modifications and tested them and they work for me on my L4D2 server. I am sharing them with you in case you wish to add them to your plugin.

I think the backwards-ray-tracing with slightly inflated bounding box idea is cool enough that I'll share that bit in-line so that forum searches can find it. It might help some other people trying to teleport stuff without letting it get stuck.

PHP Code:
// Traces forward from a client's eye or foot position until the ray hits MASK_SHOT
// Then checks for the possibility to get stuck.  If teleportee would get stuck,
// walk the ray backwards little by little until they won't get stuck anymore
// If we get too close to the client's position, or we take 100 steps, fail with client pos
stock bool:GetCollisionPoint(clientFloat:pos[3], bool:eyes=true)
{
    
decl Float:vOrigin[3], Float:vAngles[3], Float:vBackwards[3];
    new 
bool:failed false;
    new 
loopLimit 100;    // only check 100 times, as a precaution against runaway loops

    
if (eyes)
    {
        
GetClientEyePosition(clientvOrigin);
    }
    else
    {
        
// if eyes is false, fall back to the AbsOrigin ( = feet)
        
GetClientAbsOrigin(clientvOrigin);
    }
    
    
GetClientEyeAngles(clientvAngles);
    
GetAngleVectors(vAnglesvBackwardsNULL_VECTORNULL_VECTOR);
    
NormalizeVector(vBackwardsvBackwards);
    
ScaleVector(vBackwards10.0);    // TODO: percentage of distance from endpoint to eyes instead of fixed distance?
    
    
new Handle:trace TR_TraceRayFilterEx(vOriginvAnglesMASK_SHOTRayType_InfiniteTraceEntityFilterPlayer);
        
    if (
TR_DidHit(trace))
    {    
        
TR_GetEndPosition(postrace);
        
//PrintToChat(client, "endpos %f %f %f", pos[0], pos[1], pos[2]);
        
        
while (IsPlayerStuck(posclient) && !failed)    // iteratively check if they would become stuck
        
{
            
SubtractVectors(posvBackwardspos);        // if they would, subtract backwards from the position
            //PrintToChat(client, "endpos %f %f %f", pos[0], pos[1], pos[2]);
            
if (GetVectorDistance(posvOrigin) < 10 || loopLimit-- < 1)
            {
                
                
failed true;    // If we get all the way back to the origin without colliding, we have failed
                //PrintToChat(client, "failed to find endpos");
                
pos vOrigin;    // Use the client position as a fallback
            
}
        }
    }
    
    
CloseHandle(trace);
    return !
failed;        // If we have not failed, return true to let the caller know pos has teleport coordinates
}

#define BOUNDINGBOX_INFLATION_OFFSET 3

// Checks to see if a player would collide with MASK_SOLID (i.e. they would be stuck)
// Inflates player mins/maxs a little bit for better protection against sticking
// Thanks to andersso for the basis of this function
stock bool:IsPlayerStuck(Float:pos[3], client)
{
    new 
Float:mins[3];
    new 
Float:maxs[3];

    
GetClientMins(clientmins);
    
GetClientMaxs(clientmaxs);
    
    
// inflate the sizes just a little bit
    
for (new i=0i<sizeof(mins); i++)
    {
        
mins[i] -= BOUNDINGBOX_INFLATION_OFFSET;
        
maxs[i] += BOUNDINGBOX_INFLATION_OFFSET;
    }

    
TR_TraceHullFilter(posposminsmaxsMASK_SOLIDTraceEntityFilterPlayerclient);

    return 
TR_DidHit();
}  

// filter out players, since we can't get stuck on them
public bool:TraceEntityFilterPlayer(entitycontentsMask)
{
    return 
entity <= || entity MaxClients;

Attached Files
File Type: sp Get Plugin or Get Source (sm_gotoRevA.sp - 921 views - 6.6 KB)

Last edited by dcx2; 01-02-2012 at 23:49. Reason: forgot to attach script
dcx2 is offline