Monday, June 9, 2014

How to detect if player is visible. - Làm Thế Nào Để Phát Hiện Nếu Người Chơi Có Thể Nhìn Thấy


Trước Khi Đọc.
Hướng dẫn này được thực hiện đặc biệt dành cho scripters mà biết làm thế nào để làm việc với vectơ. 
Tôi sẽ cố gắng giải thích các mã càng nhiều càng tốt để mà ngay cả người dùng biết một chút ít về họ sẽ có thể hiểu! 
Này "làm thế nào để" đã được thực hiện đặc biệt cho những người muốn thực hiện điều này trong các plugin của họ. 
Lưu ý: Đây là một phương pháp rất hiệu quả, vấn đề duy nhất là có những tình huống hiếm hoi khi bạn không nhìn thấy một cầu thủ. Nhưng điều đó sẽ không là một vấn đề. 
Lưu ý: Hướng dẫn này áp dụng đối với CS nhưng có thể được thực hiện trong mods khác! Tất cả những gì bạn cần làm là chỉ cần thay đổi các hằng số để phù hợp của bạn!

Mã và mô tả:

Trước hết chúng ta cần một số hằng số:

  • Đầu tiên chúng ta cần định nghĩa một số hằng số đó sẽ có ích!
Các hằng số được sử dụng như là hằng số nhân. Chúng tôi sử dụng chúng để tạo ra một số mảng sẽ được sử dụng khi tính toán Nếu người chơi có thể nhìn thấy!
Đây là những cái mà cần phải được sửa đổi nếu bạn không hài lòng bởi kết quả mà bạn đang nhận được!
PHP Code:
#define GENERAL_X_Y_SORROUNDING             18.5         // 16.0
#define CONSTANT_Z_CROUCH_UP                 31.25         // 32.0
#define CONSTANT_Z_CROUCH_DOWN                 17.5         // 16.0
#define CONSTANT_Z_STANDUP_UP                 34.0         // 36.0
#define CONSTANT_Z_STANDUP_DOWN             35.25         // 36.0

#define GENERAL_X_Y_SORROUNDING_HALF        9.25         // 8.0
#define GENERAL_X_Y_SORROUNDING_HALF2        12.0         // 8.0
#define CONSTANT_Z_CROUCH_UP_HALF             15.5         // 16.0
#define CONSTANT_Z_CROUCH_DOWN_HALF            8.75         // 8.0
#define CONSTANT_Z_STANDUP_UP_HALF            17.0         // 18.0
#define CONSTANT_Z_STANDUP_DOWN_HALF        17.5         // 18.0

#define ANGLE_COS_HEIGHT_CHECK                0.7071        // cos(45  degrees)  
  • Bây giờ chúng ta cần một số mảng cung cấp các plugin thứ tự của các tính toán.
PHP Code:
// Cái này dùng để xác định weapon head point 
new const Float:weapon_edge_point[CSW_P90+1] =
{
    
0.0035.50.0042.00.0035.50.0037.037.00.0035.535.532.041.032.036.041.035.541.032.037.035.542.041.044.00.0035.537.032.00.0032.0 }// Điều này được sử dụng như một mảng nhân bên

new const Float:vec_multi_lateral[] =
{
    
GENERAL_X_Y_SORROUNDING,
    -
GENERAL_X_Y_SORROUNDING,
    
GENERAL_X_Y_SORROUNDING_HALF2,
    -
GENERAL_X_Y_SORROUNDING_HALF }// This is used as height multiplicator if the user crouches! 

new const Float:vec_add_height_crouch[] =
{
    
CONSTANT_Z_CROUCH_UP,
    -
CONSTANT_Z_CROUCH_DOWN,
    
CONSTANT_Z_CROUCH_UP_HALF,
    -
CONSTANT_Z_CROUCH_DOWN_HALF }// This is used as height multiplicator if the user stands up! 

new const Float:vec_add_height_standup[] =
{
    
CONSTANT_Z_STANDUP_UP,
    -
CONSTANT_Z_STANDUP_DOWN,
    
CONSTANT_Z_STANDUP_UP_HALF,
    -
CONSTANT_Z_STANDUP_DOWN_HALF }  
Secondly we need some variables:
  • Một dấu vết xử lý để lưu các kết quả phần (đối với khả năng hiển thị điểm)
Điều này là cần thiết bởi vì chúng tôi không muốn các plugin để can thiệp với các plugin khác kết quả và ngược lại!
PHP Code:
new thldpublic plugin_init()
{
    
// We create it in plugin_init
    
thdl create_tr2()
}

public 
plugin_end()
{
    
// We free it on plugin end
    
free_tr2(thdl)
}  
  • Chúng tôi cũng cần một danh sách mà chúng ta có thể lưu các loại thực thể nếu các thực thể của chúng tôi là trong suốt hay không!
Phần này được thực hiện bằng cách sử dụng trong trường hợp này bitsums, cho thêm thông tin về họ đọc này! read this!
Điều này là cần thiết khi kiểm tra plugin của chúng tôi cho khả năng hiển thị người chơi offen!

PHP Code:
// These bitsums allow 2048 entities storage. I think that it is enough :P. 
new bs_array_transp[64]                
// BitSum, This is equal to 64*32 bools (good for quick search) 
new bs_array_solid[64]                 
// BitSum, This is equal to 64*32 bools (good for quick search)  
Để xử lý những bitsums dễ dàng Tôi đã thực hiện một số hàm vĩ mô sẽ làm cho mã dễ đọc!
PHP Code:
#define add_transparent_ent(%1)         bs_array_transp[((%1 - 1) / 32)] |= (1<<((%1 - 1) % 32))
#define del_transparent_ent(%1)         bs_array_transp[((%1 - 1) / 32)] &= ~(1<<((%1 - 1) % 32))
#define  is_transparent_ent(%1)        (bs_array_transp[((%1 - 1) / 32)] & (1<<((%1 - 1) % 32)))
#define add_solid_ent(%1)               bs_array_solid[((%1 - 1) / 32)] |= (1<<((%1 - 1) % 32))
#define del_solid_ent(%1)               bs_array_solid[((%1 - 1) / 32)] &= ~(1<<((%1 - 1) % 32))
#define  is_solid_ent(%1)              (bs_array_solid[((%1 - 1) / 32)] & (1<<((%1 - 1) % 32)))  
Thứ ba, chúng ta cần một số hàm hữu ích, sẽ được sử dụng trong các thử nghiệm của chúng tôi:
  • Các chức năng theo dõi
PHP Code:
// This function checks if a point is visible from start to point! It will ignore glass and players! Also it will ignore the ignore_ent! bool:is_point_visible(const Float:start[3], const Float:point[3], ignore_ent)
{
    
engfunc(EngFunc_TraceLinestartpointIGNORE_GLASS IGNORE_MONSTERSignore_entthdl)

    static 
Float:fraction
    get_tr2
(thdlTR_flFractionfraction)
   
    
// We will return the fraction
    // If 1.0 that means that we didn't hit anything
    
return (fraction == 1.0)
}
// This function is the same as above but will also check if the entity that we hited can be seen through bool:is_point_visible_texture(const Float:start[3], const Float:point[3], ignore_ent)
{
    
engfunc(EngFunc_TraceLinestartpointIGNORE_GLASS IGNORE_MONSTERSignore_entthdl)
   
    
// We save also the entity
    
static ent
    ent 
get_tr2(thdlTR_pHit)

    static 
Float:fraction
    get_tr2
(thdlTR_flFractionfraction)
   
    
// If we hit something start the checks
    
if (fraction != 1.0 && ent 0)
    {
        
// That means that we didn't know what we hited
        
if (!is_transparent_ent(ent) && !is_solid_ent(ent))
        {
            static 
texture_name[2]
            static 
Float:vec[3]
            
// These calculations are made for security measures
            // TraceTexture function will crash the server if used on short distances
            
xs_vec_sub(pointstartvec)
            
xs_vec_mul_scalar(vec, (5000.0 xs_vec_len(vec)), vec)
            
xs_vec_add(startvecvec)
           
            
engfunc(EngFunc_TraceTextureentstartvectexture_namecharsmax(texture_name))
           
            
// If texture_name begins with { that means that we have a trasnaparent texture,
            // if yes we will retrace and add that entity to our list as a transparent!
            // If not then we add id as solid so it will not be needed to do the checks again!
            
if (equal(texture_name"{"))
            {
                
add_transparent_ent(ent)
                
ignore_ent ent
                engfunc
(EngFunc_TraceLinestartpointIGNORE_GLASS IGNORE_MONSTERSignore_entthdl)
                
get_tr2(thdlTR_flFractionfraction)
                return (
fraction == 1.0)
            }
            else
            {
                
add_solid_ent(ent)
                return (
fraction == 1.0)
            }
        }
        
// This means that the entity is registered as solid or transparent so on with the checks
        
else
        {
            if (
is_solid_ent(ent))
            {
                return (
fraction == 1.0)
            }
            else
            {
                
ignore_ent ent
                engfunc
(EngFunc_TraceLinestartpointIGNORE_GLASS IGNORE_MONSTERSignore_entthdl)
                
get_tr2(thdlTR_flFractionfraction)
                return (
fraction == 1.0)
            }
        }
    }
   
    return (
fraction == 1.0)
}  
  • Vector functions [taken from xs.inc]
PHP Code:
// This will add two vectors stock xs_vec_add(const Float:in1[], const Float:in2[], Float:out[])
{
    
out[0] = in1[0] + in2[0];
    
out[1] = in1[1] + in2[1];
    
out[2] = in1[2] + in2[2];
}
// This will substract two vectors stock xs_vec_sub(const Float:in1[], const Float:in2[], Float:out[])
{
    
out[0] = in1[0] - in2[0];
    
out[1] = in1[1] - in2[1];
    
out[2] = in1[2] - in2[2];
}
// This will multiply a vector with a scalar stock xs_vec_mul_scalar(const Float:vec[], Float:scalarFloat:out[])
{
    
out[0] = vec[0] * scalar;
    
out[1] = vec[1] * scalar;
    
out[2] = vec[2] * scalar;
}
// This will return the vector length stock Float:xs_vec_len(const Float:vec[3])
{
    return 
floatsqroot(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
}
// This will make a scalar multiplication between two vectors stock Float:xs_vec_dot(const Float:vec[], const Float:vec2[])
{
    return (
vec[0]*vec2[0] + vec[1]*vec2[1] + vec[2]*vec2[2])
}
// This will check whether two vectors are equal bool:xs_vec_equal(const Float:vec1[], const Float:vec2[])
{
    return (
vec1[0] == vec2[0]) && (vec1[1] == vec2[1]) && (vec1[2] == vec2[2]);
}  
Fourthly we need to add some entities that we already know that can be seen through this can be done using this:
PHP Code:
public plugin_precache()
{
    
register_forward(FM_Spawn"fw_spawn"1)
}

public 
fw_spawn(ent)
{
    if (!
pev_valid(ent))
        return 
FMRES_IGNORED
   
    
static rendermodeFloat:renderamt
   
    rendermode 
pev(entpev_rendermode)
    
pev(entpev_renderamtrenderamt)
   
    
// If transparent then add it to the list!
    
if (((rendermode == kRenderTransColor || rendermode == kRenderGlow || rendermode == kRenderTransTexture) && renderamt 255.0) || (rendermode == kRenderTransAdd))
    {
        
add_transparent_ent(ent)
        return 
FMRES_IGNORED
    
}
   
    return 
FMRES_IGNORED }  
Now having all the constants, variables and functions we can get on creating the stock that will show us whether a player is visible:
PHP Code:
stock is_player_visible(visortarget)
{
    
// Declarations, bla bla
    
static Float:origin[3], Float:start[3], Float:end[3], Float:addict[3], Float:plane_vec[3], Float:normal[3], ignore_ent
   
    
// The ignore entity is our visor at first (if needed we will change it!
    // This will be used in the point tests!
    
ignore_ent visor
   
    
// First of all we check if the player is behind the visor or not
    // We get the visor origin
    
pev(visorpev_originorigin)
   
    
// We get the view angles of the visor
    
pev(visorpev_v_anglenormal)
    
// We turn the angle vector into a direction vector
    
angle_vector(normalANGLEVECTOR_FORWARDnormal)
   
    
// We get the targets origin, this will be used to deremine if it the player is behind us
    
pev(targetpev_originend)
    
// We substract the two vectors to obtain a directional vector!
    
xs_vec_sub(endoriginplane_vec)
    
// We normalize the vector so that we will be able to obtain the real angle between the vectors
    
xs_vec_mul_scalar(plane_vec,  (1.0/xs_vec_len(plane_vec)), plane_vec)
   
    
// When we multiply two vectors that are normalized (their length is 1)
    // We will obtain the cosinus of the angle between them, if this is negative then that means that the player is behind, so we return false!
    
if (xs_vec_dot(plane_vecnormal) < 0)
    {
        return 
false
    
}
   
    
// We get the view offsets and we add them to the origin to obtain the eye origin
    
pev(visorpev_view_ofsstart)
    
xs_vec_add(startoriginstart)
   
    
// Origin becomes end
    
origin end
   
    
// Until now we have 2 important vectors
    // start - that is the eye origin of the visor
    // origin - that is the target origin (usefull later)
   
    // This is used only once to update the ignore_ent
    // If point is visible then guess what, returning true!
    
if (is_point_visible_texture(startoriginignore_ent))
        return 
true
   
    
// This will get the view offsets of the target, we will add them to obtain the eye origin
    
pev(targetpev_view_ofsend)
    
xs_vec_add(endoriginend)
   
    
// If eye origin is visible return true!
    
if (is_point_visible(startendignore_ent))
        return 
true
   
    
// Check weapon point, first we need to check if it is no equal to 0
    
if (weapon_edge_point[get_user_weapon(target)] != 0.00)
    {
        
// We get the view angles and turn them in directional vectors
        
pev(targetpev_v_angleaddict)
        
angle_vector(addictANGLEVECTOR_FORWARDaddict)
        
// We multiply it to obtain the weapon headpoint
        
xs_vec_mul_scalar(addictweapon_edge_point[get_user_weapon(target)], addict)
        
// We add it to the end origin to obtain the weapon headpoint
        
xs_vec_add(endaddictend)
       
        
// If weapon head is visible true!
        
if (is_point_visible(startendignore_ent))
            return 
true
    
}
   
    
// We subtract them to obtain o directional vector that will be used in plane calculations!
    
xs_vec_sub(startoriginnormal)
   
    
// We have now an extra important vector
    // normal - a directional vector between the start vector and the target origin
   
    // This is the moment when we move on to plane checks
    // These functions will create a plane that will rotate based on player position
    // The checks will be done on points that will exist on this plane!
   
    // First of all we normalize the normal vector
    // This will be important when we have height problems.
    
xs_vec_mul_scalar(normal1.0/(xs_vec_len(normal)), normal)
    
// We turn the vector into an angle vector
    
vector_to_angle(normalplane_vec)
    
// This will create a vector that will be orthogonal/perpendicular with the normal vector!
    // This must be done to easily create the plane!
    
angle_vector(plane_vecANGLEVECTOR_RIGHTplane_vec)
   
    
// This will check if we are almost at the same level with the target
    
if (floatabs(normal[2]) <= ANGLE_COS_HEIGHT_CHECK)
    {
        
// We check whether the target crouches
        // This is important to determine what multiplicator vector to use!
        // This will create the plane
        
if (pev(targetpev_flags) & FL_DUCKING)
        {
            for (new 
i=0;i<4;i++)
            {
                if (
i<2)
                {
                    for (new 
j=0;j<2;j++)
                    {
                        
// We multiply the directional vector and add it to the origin after that we check if it is visible
                        // The same happens in the other places so this one will be the only one that will be commented!
                        
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                        
addict[2] = vec_add_height_crouch[j]
                        
xs_vec_add(originaddictend)
                       
                        if (
is_point_visible(startendignore_ent))
                            return 
true
                    
}
                }
                else
                {
                    for (new 
j=2;j<4;j++)
                    {
                        
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                        
addict[2] = vec_add_height_crouch[j]
                        
xs_vec_add(originaddictend)
                       
                        if (
is_point_visible(startendignore_ent))
                            return 
true
                    
}
                }
            }
        }
        else
        {
            for (new 
i=0;i<4;i++)
            {
                if (
i<2)
                {
                    for (new 
j=0;j<2;j++)
                    {
                        
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                        
addict[2] = vec_add_height_standup[j]
                        
xs_vec_add(originaddictend)
                       
                        if (
is_point_visible(startendignore_ent))
                            return 
true
                    
}
                }
                else
                {
                    for (new 
j=2;j<4;j++)
                    {
                        
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                        
addict[2] = vec_add_height_standup[j]
                        
xs_vec_add(originaddictend)
                       
                        if (
is_point_visible(startendignore_ent))
                            return 
true
                    
}
                }
            }
        }
    }
    else
    {
        
// This is the same as the one above
        // The only difference is that it also uses normal vector to move the points in front and in behind!
        // Here is checked if you are above the player
        
if (normal[2] > 0.0)
        {
            
normal[2] = 0.0
            xs_vec_mul_scalar
(normal1/(xs_vec_len(normal)), normal)
       
            if (
pev(targetpev_flags) & FL_DUCKING)
            {
                for (new 
i=0;i<4;i++)
                {
                    if (
i<2)
                    {
                        for (new 
j=0;j<2;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_crouch[j]
                            
xs_vec_add(originaddictend)
                            
xs_vec_mul_scalar(normal, (== 0) ? (-GENERAL_X_Y_SORROUNDING) : (GENERAL_X_Y_SORROUNDING), addict)
                            
xs_vec_add(endaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                    else
                    {
                        for (new 
j=2;j<4;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_crouch[j]
                            
xs_vec_add(originaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                }
            }
            else
            {
                for (new 
i=0;i<4;i++)
                {
                    if (
i<2)
                    {
                        for (new 
j=0;j<2;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_standup[j]
                            
xs_vec_add(originaddictend)
                            
xs_vec_mul_scalar(normal, (== 0) ? (-GENERAL_X_Y_SORROUNDING) : (GENERAL_X_Y_SORROUNDING), addict)
                            
xs_vec_add(endaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                    else
                    {
                        for (new 
j=2;j<4;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_standup[j]
                            
xs_vec_add(originaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                }
            }
        }
        else
        {
            
normal[2] = 0.0
            xs_vec_mul_scalar
(normal1/(xs_vec_len(normal)), normal)
           
            if (
pev(targetpev_flags) & FL_DUCKING)
            {
                for (new 
i=0;i<4;i++)
                {
                    if (
i<2)
                    {
                        for (new 
j=0;j<2;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_crouch[j]
                            
xs_vec_add(originaddictend)
                            
xs_vec_mul_scalar(normal, (== 0) ? GENERAL_X_Y_SORROUNDING : (-GENERAL_X_Y_SORROUNDING), addict)
                            
xs_vec_add(endaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                    else
                    {
                        for (new 
j=2;j<4;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_crouch[j]
                            
xs_vec_add(originaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                }
            }
            else
            {
                for (new 
i=0;i<4;i++)
                {
                    if (
i<2)
                    {
                        for (new 
j=0;j<2;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_standup[j]
                            
xs_vec_add(originaddictend)
                            
xs_vec_mul_scalar(normal, (== 0) ? GENERAL_X_Y_SORROUNDING : (-GENERAL_X_Y_SORROUNDING), addict)
                            
xs_vec_add(endaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                    else
                    {
                        for (new 
j=2;j<4;j++)
                        {
                            
xs_vec_mul_scalar(plane_vecvec_multi_lateral[i], addict)
                            
addict[2] = vec_add_height_standup[j]
                            
xs_vec_add(originaddictend)
                           
                            if (
is_point_visible(startendignore_ent))
                                return 
true
                        
}
                    }
                }
            }
        }
    }
   
    
// None visible?
    
return false }  
How to see the points that are tested?
Well you just need to do add this to the code in the plugin.

PHP Code:
stock spr_bombpublic plugin_precache()
{
    
spr_bomb precache_model("sprites/ledglow.spr")
}
stock bomb_led(const Float:point[3])
{
    
message_begin(MSG_BROADCASTSVC_TEMPENTITY)
    
write_byte(TE_GLOWSPRITE)
    
engfunc(EngFunc_WriteCoordpoint[0])
    
engfunc(EngFunc_WriteCoordpoint[1])
    
engfunc(EngFunc_WriteCoordpoint[2])
    
write_short(spr_bomb)
    
write_byte(1)
    
write_byte(3)
    
write_byte(255)
    
message_end()
}  
And change the functions "is_point_visible" and "is_point_visible_texture" into this:
PHP Code:
bool:is_point_visible(const Float:start[3], const Float:point[3], ignore_ent)
{
    
bomb_led(point)
    return 
false }bool:is_point_visible_texture(const Float:start[3], const Float:point[3], ignore_ent)
{
    
bomb_led(point)
    return 
false 

0 nhận xét:

Post a Comment