Solved.
TR_TraceHullFilterEx returns nothing because there is no collision between these points,
thus it require scaling directional vector to get point a little bit under ground before passing it to TR_TraceHullFilterEx.
PHP Code:
#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
int g_sprite;
#define PRINT_LASER 1
#define RED {255, 0, 0, 255}
#define GREEN {0, 255, 0, 255}
#define BLUE {0, 0, 255, 255}
public void OnPluginStart()
{
RegAdminCmd("sm_d", CmdDistanceDir, ADMFLAG_ROOT, "Get distance between you and end point of direction you are looking at (considering collision)");
}
public void OnMapStart()
{
g_sprite = PrecacheModel("materials/sprites/laser.vmt", true);
}
public Action CmdDistanceDir(int client, int args)
{
float vOrigin[3], vEye[3], vEnd[3], vEndNonCol[3];
float dist;
GetClientAbsOrigin(client, vOrigin);
GetClientEyePosition(client, vEye);
if (GetDirectionEndPoint(client, vEnd))
{
dist = GetVectorDistance(vOrigin, vEnd);
PrintToChat(client, "Directional end point: %f %f %f. Distance: %f", vEnd[0], vEnd[1], vEnd[2], dist);
ScaleVectorDirection(vEye, vEnd, 0.1);
if (GetNonCollideEndPoint(client, vEnd, vEndNonCol))
{
dist = GetVectorDistance(vOrigin, vEndNonCol);
PrintToChat(client, "Non-collide end point: %f %f %f. Distance: %f", vEndNonCol[0], vEndNonCol[1], vEndNonCol[2], dist);
}
else {
PrintToChat(client, "Non-collide end point doesn't found.");
}
}
else {
PrintToChat(client, "Directional end point doesn't found.");
}
return Plugin_Handled;
}
void ScaleVectorDirection(float vStart[3], float vEnd[3], float fMultiple)
{
float dir[3];
SubtractVectors(vEnd, vStart, dir);
ScaleVector(dir, fMultiple);
AddVectors(vEnd, dir, vEnd);
}
stock bool GetDirectionEndPoint(int client, float vEndPos[3])
{
float vDir[3], vPos[3];
GetClientEyePosition(client, vPos);
GetClientEyeAngles(client, vDir);
Handle hTrace = TR_TraceRayFilterEx(vPos, vDir, MASK_PLAYERSOLID, RayType_Infinite, TraceRayNoPlayers, client);
if (hTrace != INVALID_HANDLE) {
if(TR_DidHit(hTrace)) {
TR_GetEndPosition(vEndPos, hTrace);
CloseHandle(hTrace);
#if PRINT_LASER
LaserP(vPos, vEndPos, RED);
#endif
return true;
}
CloseHandle(hTrace);
}
return false;
}
stock bool GetNonCollideEndPoint(int client, float vEnd[3], float vEndNonCol[3])
{
float vMin[3], vMax[3], vStart[3];
//GetClientAbsOrigin(client, vStart);
//vStart[2] += 20.0; // if nearby area is irregular
GetClientEyePosition(client, vStart);
GetClientMins(client, vMin);
GetClientMaxs(client, vMax);
Handle hTrace = TR_TraceHullFilterEx(vStart, vEnd, vMin, vMax, MASK_PLAYERSOLID, TraceRayNoPlayers, client);
if (hTrace != INVALID_HANDLE) {
if(TR_DidHit(hTrace))
{
TR_GetEndPosition(vEndNonCol, hTrace);
CloseHandle(hTrace);
#if PRINT_LASER
LaserP(vStart, vEndNonCol, GREEN, 5.0);
#endif
return true;
}
CloseHandle(hTrace);
}
return false;
}
public bool TraceRayNoPlayers(int entity, int mask, any data)
{
if(entity == data || (entity >= 1 && entity <= MaxClients))
{
return false;
}
return true;
}
stock void LaserP(float start[3], float end[3], int color[4], float width = 3.0)
{
TE_SetupBeamPoints(start, end, g_sprite, 0, 0, 0, 10.0, width, width, 7, 0.0, color, 5);
TE_SendToAll();
}