Не работает SDKHook_SetTransmit

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
Всем привет

Вот код:
code:
#pragma semicolon 1

#include <sdkhooks>
#include <sdktools>

#pragma newdecls required

int iSprite_ref[MAXPLAYERS+1];
int iChosen;
bool bInRange[MAXPLAYERS+1];

public void OnPluginStart(){
    HookEvent("player_spawn", OnPlayer);
    HookEvent("player_death", OnPlayer);
    RegConsoleCmd("sm_test", cmd_test);
}
public Action cmd_test(int client, int args){
    if(GetClientTeam(client) != 2) return Plugin_Continue;

    iChosen = client;

    return Plugin_Continue;
}
public void OnMapStart(){
    PrecacheDecal("nlas/sprite/wh/wh_green.vmt", true);
    AddFileToDownloadsTable("materials/nlas/sprite/wh/wh_green.vmt");
    AddFileToDownloadsTable("materials/nlas/sprite/wh/wh_green.vtf");
    CreateTimer(0.1, GlobalTimer, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}
public void OnClientDisconnect(int client){
    DeleteSprite(client);
}
public void OnPlayer(Event event, const char[] name, bool dontBroadcast){
    int client = GetClientOfUserId(event.GetInt("userid"));
    if(client > 0 && client <= MaxClients && IsClientInGame(client)){
        if(name[7] == 's'){
            if(IsPlayerAlive(client) && GetClientTeam(client) == 3)
                RequestFrame(rf_OnPlayerSpawn, client);
        }
        else {
            DeleteSprite(client);
        }
    }
}
public void rf_OnPlayerSpawn(int client){
    CreateSprite(client, false);
}

public Action GlobalTimer(Handle timer){
    if(iChosen < 1 || !IsClientInGame(iChosen)) return Plugin_Continue;

    float pos[3]; GetClientEyePosition(iChosen, pos);
    float ang[3]; GetClientEyeAngles(iChosen, ang);

    float dir[3], pos_target[3], pos_ent[3], client_dir[3], target_dir[3], temp[3];

    for(int client = 1, ent; client <= MaxClients; client++){
        if((ent = EntRefToEntIndex(iSprite_ref[client])) > 0 && IsValidEntity(ent) && IsClientInGame(client)){
            GetClientEyePosition(client, pos_target);
            if(GetVectorDistance(pos, pos_target) <= 1000.0){
                if(!bInRange[client]){
                    bInRange[client] = true;
                    CreateSprite(client, true);
                }
            }
            else{
                if(bInRange[client]){
                    bInRange[client] = false;
                    CreateSprite(client, false);
                    // if(GetEntPropEnt(ent, Prop_Send, "moveparent") != -1)
                    //     SetEntPropEnt(ent, Prop_Send, "moveparent", -1);
                }

                ang[0] = ang[2] = 0.0;
                GetAngleVectors(ang, client_dir, NULL_VECTOR, NULL_VECTOR);
                for(int x; x < 2; x++)
                    temp[x] = pos_target[x]-pos[x];
                NormalizeVector(temp, target_dir);

                if(GetVectorDotProduct(client_dir, target_dir) < 0.6) continue;


                MakeVectorFromPoints(pos, pos_target, dir);
                GetVectorAngles(dir, dir);
                GetAngleVectors(dir, dir, NULL_VECTOR, NULL_VECTOR);
                for(int x = 0; x < 2; x++)
                    pos[x] += dir[x] * 800.0;

                GetEntPropVector(ent, Prop_Send, "m_vecOrigin", pos_ent);
                if(pos[0] == pos_ent[0] && pos[1] == pos_ent[1]) continue;

                TeleportEntity(ent, pos, NULL_VECTOR, NULL_VECTOR);
            }
        }
    }
    return Plugin_Continue;
}

public void CreateSprite(int client, bool parent){
    DeleteSprite(client);
    float pos[3]; GetClientEyePosition(client, pos);
    int ent = CreateEntityByName("env_sprite");
    DispatchKeyValue(ent, "model", "nlas/sprite/wh/wh_green.vmt");
    DispatchKeyValueVector(ent, "origin", pos);
    DispatchKeyValue(ent, "rendermode", "4");
    DispatchKeyValue(ent, "scale", "0.4");
    DispatchSpawn(ent);

    if(parent){
        SetVariantString("!activator");
        AcceptEntityInput(ent, "SetParent", client);
    }

    SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit);

    iSprite_ref[client] = EntIndexToEntRef(ent);
}
public Action OnSetTransmit(int entity, int client){
    PrintToChatAll("[%.2f] Transmit", GetGameTime());
    return iChosen != client ? Plugin_Handled : Plugin_Continue;
}
stock void DeleteSprite(int client){
    int ent;
    if((ent = EntRefToEntIndex(iSprite_ref[client])) > 0 && IsValidEntity(ent))
        AcceptEntityInput(ent, "kill");
}

Пытаюсь сделать чтобы 1 игроку показывало направление где находится другой игрок спрайтом
Но есть проблема с SetTransmit

Когда спрайту устанавливается AcceptEntityInput(ent, "SetParent", client), тогда SetTransmit работает исправно, и спрайты видит только 1 игрок:
return iChosen != client ? Plugin_Handled : Plugin_Continue;

Но если не присваивать SetParent спрайту, тогда почему-то SDKHook "хукается", но не работает

В чем может быть проблема ?

 

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
перед SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit); сделай SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
У меня в Revival такая же проблема когда-то была. Так её и решил.
 

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
перед SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit); сделай SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
У меня в Revival такая же проблема когда-то была. Так её и решил.
Ничего не изменилось, хоть флаги и устанавливаются
code:
public void CreateSprite(int client, bool parent){
    DeleteSprite(client);
    float pos[3]; GetClientEyePosition(client, pos);
    int ent = CreateEntityByName("env_sprite");
    DispatchKeyValue(ent, "model", "nlas/sprite/wh/wh_green.vmt");
    DispatchKeyValueVector(ent, "origin", pos);
    DispatchKeyValue(ent, "rendermode", "4");
    DispatchKeyValue(ent, "scale", "0.4");
    SetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity", client);
    DispatchSpawn(ent);

    if(parent){
        SetVariantString("!activator");
        AcceptEntityInput(ent, "SetParent", client);
    }

    // PrintToChatAll("[0] %d %d", ent, GetEdictFlags(ent));
    SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
    // PrintToChatAll("[1] %d %d", ent, GetEdictFlags(ent));

    SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit);

    iSprite_ref[client] = EntIndexToEntRef(ent);
}
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
Кстати
NeLifeASkazka написал(а):
C-подобный:
public Action OnSetTransmit(int entity, int client){
    PrintToChatAll("[%.2f] Transmit", GetGameTime());
    return iChosen != client ? Plugin_Handled : Plugin_Continue;
}
Ты же понимаешь, что OnSetTransmit() у тебя срабатывает каждый тик для каждого спрайта и каждого клиента в на сервере?
Т.е. при 3 спрайтах и 10 игроках это будет 30 срабатываний на тик, а тиков в CS:S может быть до 66 в секунду, а в CS:GO - больше сотни.
И ты при каждом срабатывании посылаешь в чат сообщение для всех.
 

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
Это для того чтобы проверить, работает ли OnSetTransmit вообще или нет
Так то конечно оно там как минимум не нужно
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
Ещё по коду:
  • Ты создаёшь таймер, который срабатывает в секунду 10 раз и каждый раз проходит циклом по всем игрокам измеряя дистанцию и прочее. Не накладно?
  • Ещё в таймере ты при выходе игрока из зоны в 1к юнитов пересоздаёшь спрайт и пытаешься телепортировать уже удалённый. =)
    Надо бы после CreateSprite(client, false); сделать снова ent = EntRefToEntIndex(iSprite_ref[client]).
  • В цикле таймера ты делаешь проверку if((ent = EntRefToEntIndex(iSprite_ref[client])) > 0 && IsValidEntity(ent) && IsClientInGame(client)). Я бы на твоём месте сначала проверил на сервере ли игрок, а потом проверял его спрайт. Ну и если EntRefToEntIndex() вернул не INVALID_ENT_REFERENCE, то энтити должна быть валидной.
  • В отлове событий смерти/спавна ты зачем-то делаешь вот эти проверки: if(client > 0 && client <= MaxClients && IsClientInGame(client)). В принципе достаточно if(client)
Сообщения автоматически склеены:

@NeLifeASkazka, вообще попробуй после TeleportEntity(ent, pos, NULL_VECTOR, NULL_VECTOR); тоже делать SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));.
Сообщения автоматически склеены:

Мало ли, вдруг поможет
 

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
Ты создаёшь таймер, который срабатывает в секунду 10 раз и каждый раз проходит циклом по всем игрокам измеряя дистанцию и прочее. Не накладно?
Ну это для более высокой точности, но это не так важно
В цикле таймера ты делаешь проверку if((ent = EntRefToEntIndex(iSprite_ref[client])) > 0 && IsValidEntity(ent) && IsClientInGame(client)). Я бы на твоём месте сначала проверил на сервере ли игрок, а потом проверял его спрайт.
Я ведь с спрайтом работаю, а не с клиентом. С клиента мне нужна только его позиция, если он живой
То, наверное, логичнее было бы проверить есть ли вообще спрайт у клиента ? А потом уже проверить валиден ли вообще клиент


В общем вот обновленный код. К сожалению все так же без изменений:
code:
#pragma semicolon 1

#include <sdkhooks>
#include <sdktools>

#pragma newdecls required

int iSprite_ref[MAXPLAYERS+1];
int iChosen;
bool bInRange[MAXPLAYERS+1];

public void OnPluginStart(){
    HookEvent("player_spawn", OnPlayer);
    HookEvent("player_death", OnPlayer);
    RegConsoleCmd("sm_test", cmd_test);
}
public Action cmd_test(int client, int args){
    if(GetClientTeam(client) != 2) return Plugin_Continue;
    iChosen = client;
    return Plugin_Continue;
}
public void OnMapStart(){
    PrecacheDecal("nlas/sprite/wh/wh_green.vmt", true);
    AddFileToDownloadsTable("materials/nlas/sprite/wh/wh_green.vmt");
    AddFileToDownloadsTable("materials/nlas/sprite/wh/wh_green.vtf");
    CreateTimer(0.3, GlobalTimer, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}
public void OnClientDisconnect(int client){
    DeleteSprite(client);
}
public void OnPlayer(Event event, const char[] name, bool dontBroadcast){
    int client = GetClientOfUserId(event.GetInt("userid"));
    if(!client) return;
    if(name[7] == 's'){
        if(IsPlayerAlive(client) && GetClientTeam(client) == 3)
            RequestFrame(rf_OnPlayerSpawn, client);
    }
    else {
        DeleteSprite(client);
    }
}
public void rf_OnPlayerSpawn(int client){
    CreateSprite(client);
}

public Action GlobalTimer(Handle timer){
    if(iChosen < 1 || !IsClientInGame(iChosen)) return Plugin_Continue;

    float pos[3]; GetClientEyePosition(iChosen, pos);
    float ang[3]; GetClientEyeAngles(iChosen, ang);

    float dir[3], pos_target[3], pos_ent[3], client_dir[3], target_dir[3], temp[3];

    for(int client = 1, ent; client <= MaxClients; client++){
        if((ent = EntRefToEntIndex(iSprite_ref[client])) > 0 && IsClientInGame(client)){
            GetClientEyePosition(client, pos_target);
            if(GetVectorDistance(pos, pos_target) <= 1000.0){
                if(!bInRange[client]){
                    bInRange[client] = true;
                    CreateSprite(client);
                }
            }
            else{
                if(bInRange[client]){
                    bInRange[client] = false;
                    if(GetEntPropEnt(ent, Prop_Send, "moveparent") != -1)
                        SetEntPropEnt(ent, Prop_Send, "moveparent", -1);
                }

                ang[0] = ang[2] = 0.0;
                GetAngleVectors(ang, client_dir, NULL_VECTOR, NULL_VECTOR);
                for(int x; x < 2; x++)
                    temp[x] = pos_target[x]-pos[x];
                NormalizeVector(temp, target_dir);

                if(GetVectorDotProduct(client_dir, target_dir) < 0.6) continue;

                MakeVectorFromPoints(pos, pos_target, dir);
                GetVectorAngles(dir, dir);
                GetAngleVectors(dir, dir, NULL_VECTOR, NULL_VECTOR);
                for(int x = 0; x < 2; x++)
                    pos[x] += dir[x] * 800.0;

                GetEntPropVector(ent, Prop_Send, "m_vecOrigin", pos_ent);
                if(pos[0] == pos_ent[0] && pos[1] == pos_ent[1]) continue;

                TeleportEntity(ent, pos, NULL_VECTOR, NULL_VECTOR);
                SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
            }
        }
    }
    return Plugin_Continue;
}

public void CreateSprite(int client){
    DeleteSprite(client);
    float pos[3]; GetClientEyePosition(client, pos);
    int ent = CreateEntityByName("env_sprite");
    DispatchKeyValue(ent, "model", "nlas/sprite/wh/wh_green.vmt");
    DispatchKeyValueVector(ent, "origin", pos);
    DispatchKeyValue(ent, "rendermode", "4");
    DispatchKeyValue(ent, "scale", "0.4");
    DispatchSpawn(ent);

    SetVariantString("!activator");
    AcceptEntityInput(ent, "SetParent", client);

    SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));

    SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit);

    iSprite_ref[client] = EntIndexToEntRef(ent);
}
public Action OnSetTransmit(int entity, int client){
    return iChosen != client ? Plugin_Handled : Plugin_Continue;
}
stock void DeleteSprite(int client){
    int ent;
    if((ent = EntRefToEntIndex(iSprite_ref[client])) > 0)
        AcceptEntityInput(ent, "kill");
}
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
@NeLifeASkazka, тогда почему делаешь цикл по игрокам, а не спрайтам, раз уж со спрайтами работаешь? =)
 

Nebraska

Участник
Сообщения
225
Реакции
293
Ничего не изменилось, хоть флаги и устанавливаются
code:
public void CreateSprite(int client, bool parent){
    DeleteSprite(client);
    float pos[3]; GetClientEyePosition(client, pos);
    int ent = CreateEntityByName("env_sprite");
    DispatchKeyValue(ent, "model", "nlas/sprite/wh/wh_green.vmt");
    DispatchKeyValueVector(ent, "origin", pos);
    DispatchKeyValue(ent, "rendermode", "4");
    DispatchKeyValue(ent, "scale", "0.4");
    SetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity", client);
    DispatchSpawn(ent);

    if(parent){
        SetVariantString("!activator");
        AcceptEntityInput(ent, "SetParent", client);
    }

    // PrintToChatAll("[0] %d %d", ent, GetEdictFlags(ent));
    SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
    // PrintToChatAll("[1] %d %d", ent, GetEdictFlags(ent));

    SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit);

    iSprite_ref[client] = EntIndexToEntRef(ent);
}
флаги так же нужно в теле самого обработчика SDKHook_SetTransimt обновлять. просто добавь еще SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK)); в тело OnSetTransmit
 

KiKiEEKi

🏆 🥇
Сообщения
653
Реакции
513
Если надо одному игроку показать то легчи\проще установить спрайту владельца(кому показывать) при создание а в SDKHook_SetTransimt получать владельца вот и все будет работать норм как у меня на питомцах.
 

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
попробуй такой код
Все также :(
флаги так же нужно в теле самого обработчика SDKHook_SetTransimt обновлять. просто добавь еще SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK)); в тело OnSetTransmit
Проблема в том что сама функция OnSetTransit не вызывается если не установить SetParent
На видео видно по сообщению в чате

Да и куда и как я только не пихал SetEdictFlags 🙃
 

Nebraska

Участник
Сообщения
225
Реакции
293
Все также :(

Проблема в том что сама функция OnSetTransit не вызывается если не установить SetParent
На видео видно по сообщению в чате

Да и куда и как я только не пихал SetEdictFlags 🙃
сделай как тебе сказал KiKiEEKi. устанавливаешь владельца спрайту. потом в обработчике SDKHook_SetTransimt получаешь владельца по индексу спрайта и блочишь видимость для всех, кроме владельца
 

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
сделай как тебе сказал KiKiEEKi. устанавливаешь владельца спрайту. потом в обработчике SDKHook_SetTransimt получаешь владельца по индексу спрайта и блочишь видимость для всех, кроме владельца
Без изменений:

code:
public void CreateSprite(int client){
    DeleteSprite(client);

    float pos[3]; GetClientEyePosition(client, pos);
    int ent = CreateEntityByName("env_sprite");
    DispatchKeyValue(ent, "model", MARK[10]);
    DispatchKeyValueVector(ent, "origin", pos);
    DispatchKeyValue(ent, "rendermode", "4");
    DispatchKeyValue(ent, "scale", "0.4");
    DispatchSpawn(ent);

    if(bInRange[client]){
        SetVariantString("!activator");
        AcceptEntityInput(ent, "SetParent", client);
    }

    SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
    SetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity", iChosen);

    SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit);

    iSprite_ref[client] = EntIndexToEntRef(ent);
}

public Action OnSetTransmit(int entity, int client){
    // PrintToChat(iChosen, "iChosen: %d, client: %d", iChosen, client);
    SetEdictFlags(entity, GetEdictFlags(entity) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
    return GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity") != client ? Plugin_Handled : Plugin_Continue;
}
 

Nebraska

Участник
Сообщения
225
Реакции
293
Без изменений:

code:
public void CreateSprite(int client){
    DeleteSprite(client);

    float pos[3]; GetClientEyePosition(client, pos);
    int ent = CreateEntityByName("env_sprite");
    DispatchKeyValue(ent, "model", MARK[10]);
    DispatchKeyValueVector(ent, "origin", pos);
    DispatchKeyValue(ent, "rendermode", "4");
    DispatchKeyValue(ent, "scale", "0.4");
    DispatchSpawn(ent);

    if(bInRange[client]){
        SetVariantString("!activator");
        AcceptEntityInput(ent, "SetParent", client);
    }

    SetEdictFlags(ent, GetEdictFlags(ent) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
    SetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity", iChosen);

    SDKHook(ent, SDKHook_SetTransmit, OnSetTransmit);

    iSprite_ref[client] = EntIndexToEntRef(ent);
}

public Action OnSetTransmit(int entity, int client){
    // PrintToChat(iChosen, "iChosen: %d, client: %d", iChosen, client);
    SetEdictFlags(entity, GetEdictFlags(entity) & ~(FL_EDICT_ALWAYS|FL_EDICT_DONTSEND|FL_EDICT_PVSCHECK));
    return GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity") != client ? Plugin_Handled : Plugin_Continue;
}
по идее всё должно работать. попробуй так SetEdictFlags(entity, (GetEdictFlags(entity) ^ FL_EDICT_ALWAYS));
 

NeLifeASkazka

Участник
Сообщения
128
Реакции
70
по идее всё должно работать. попробуй так SetEdictFlags(entity, (GetEdictFlags(entity) ^ FL_EDICT_ALWAYS));
В таком случае, если SetEdictFlags вызывается в OnSetTransmit, тогда OnSetTransmit срабатывает 2 раза
И при этом OnSetTransmit не работает даже при SetParent

Если SetEdictFlags будет только в CreateSprite, тогда все будет без изменений 🤷‍♂️
1715434023157.png
1715434042667.png
1715434408890.png
 
Сверху Снизу