You want to use a trace hull to scan a rectangular prism area for intersecting entitys before teleporting the player.
The trace hull size would be the max size of the player entity.
If something is intersecting the end point then you would want to move the endpoint away from the wall/ent you just hit by a fixed value in the inverse direction of the tracerays view angle.
Then you run the tracehull scan again until it is cleared or a max threshold of scans are reached.
If the area is then clear we would teleport the player entity or else deny it.
PHP Code:
#include <sourcemod>
#include <sdktools>
int beammdl = -1;
public void OnPluginStart()
{
beammdl = PrecacheModel("materials/sprites/laserbeam.vmt", true);
RegConsoleCmd("warpfarbot", Command_WarpFarBot);
}
public void OnMapStart()
{
beammdl = PrecacheModel("materials/sprites/laserbeam.vmt", true);
}
bool IsAreaClear(int client, float position[3])
{
//This is the players collision rectangular prism size defined by two 3D Points farthest away from each other
static float vecMins[3] = {-16.0, -16.0, 0.0};
static float vecMaxs[3] = {16.0, 16.0, 72.0};
TR_TraceHullFilter(position, position, vecMins, vecMaxs, MASK_PLAYERSOLID, Filter_LocalPlayer, client);
if(!TR_DidHit())
return true;
return false;
}
public bool Filter_LocalPlayer(int entity, int contentsMask, any client)
{
return !(entity == client)
}
public bool Filter_ExcludePlayers(int entity, int contentsMask, any data)
{
return !((entity > 0) && (entity <= MaxClients));
}
int GetFarthestBot(int client)
{
float playerPos[3];
GetClientEyePosition(client, playerPos);
float farthestDistance = 0.0;
int farthestBot = -1;
for(int bot = 1;bot<MaxClients+1;bot++)
{
if(IsValidClient(bot) && IsFakeClient(bot) && IsPlayerAlive(bot))
{
float botPos[3];
GetClientEyePosition(bot, botPos);
float dist = GetVectorDistance(playerPos, botPos);
if(dist > farthestDistance)
{
farthestDistance = dist;
farthestBot = bot;
}
}
}
return farthestBot;
}
public Action Command_WarpFarBot(int client, int args)
{
int farthestBotIndex = GetFarthestBot(client);
if(farthestBotIndex == -1)
{
PrintToChat(client, "no active bots!");
return Plugin_Handled;
}
float g_Origin[3], g_Angle[3], HitEndPoint[3];
GetClientEyePosition(client, g_Origin);
GetClientEyeAngles(client, g_Angle);
TR_TraceRayFilter(g_Origin, g_Angle, MASK_SHOT, RayType_Infinite, Filter_LocalPlayer, client);
if(!TR_DidHit(INVALID_HANDLE))
{
PrintToChat(client, "\x01\x02 \x02Trace ray did not hit anything!");
return Plugin_Handled;
}
TR_GetEndPosition(HitEndPoint);
//We can get the ground underneath the player by shooting another raytrace directly down
//This prevents players from spawning on the wall really high and causing fall damage
float down[3] = {90.0, 0.0, 0.0};
TR_TraceRayFilter(HitEndPoint, down, MASK_SHOT, RayType_Infinite, Filter_ExcludePlayers);
if(!TR_DidHit(INVALID_HANDLE))
{
PrintToChat(client, "\x01\x02 \x02Could not find ground!");
return Plugin_Handled;
}
TR_GetEndPosition(HitEndPoint);
//Elevate off the ground
HitEndPoint[2] += 10.0;
float fForwards[3];
GetAngleVectors(g_Angle, fForwards, NULL_VECTOR, NULL_VECTOR);
//Invert forwards angle to change direction to face from hitpos to client running the cmd
for(int i = 0;i < 3; i++)
fForwards[i] *= -1;
//Move 32 units from hit point on the wall
for(int i = 0;i < 3; i++)
HitEndPoint[i] = HitEndPoint[i] + (fForwards[i] * 32.0);
int iterationCount = 0;
//Check if point is clear
while(!IsAreaClear(client, HitEndPoint))
{
float HitEndPointDebug[3];
//Just create offset point for debug draw line secondary point
for(int i = 0;i < 3; i++)
HitEndPointDebug[i] = HitEndPoint[i] + 5.0;
//debug visuals
TE_SetupBeamPoints(HitEndPoint, HitEndPointDebug, beammdl, 0, 0, 0, 10.0, 1.0, 1.0, 1, 0.0, {255, 0, 0, 255}, 1);
TE_SendToAll();
iterationCount++;
if(iterationCount > 10)
{
PrintToChat(client, "\x01\x02 \x02Area is not Clear!");
return Plugin_Handled;
}
//Iterate point 32 units towards the player camera for next trace hull check
for(int i = 0;i < 3; i++)
HitEndPoint[i] = HitEndPoint[i] + (fForwards[i] * 32.0);
}
//debug message for iteration loop count
//PrintToChat(client, "\x01\x02 \x10Exit loop after %i iterations", iterationCount);
TeleportEntity(farthestBotIndex, HitEndPoint, NULL_VECTOR, NULL_VECTOR);
PrintToChat(client, "\x01\x10 \x06Teleported %N", farthestBotIndex);
return Plugin_Handled;
}
bool IsValidClient(int client)
{
if (!(1 <= client <= MaxClients) || !IsClientConnected(client) || !IsClientInGame(client) || IsClientSourceTV(client) || IsClientReplay(client))
return false;
return true;
}
Video of above plugin code