Целесообразна ли проверка IsClientInGame, после получения GetClientOfUserId(GetEventInt(event, "userid"));

gameuser425

Участник
Сообщения
30
Реакции
3
Здравствуйте)
Я хочу раз и навсегда разобраться с HookEvent
А точнее с public Action
Вот к примеру паблик, срабатывающий когда игрок вступает в команду.

1649390379091.png


Сталкивался с ситуацией в других случаях, когда GetClientOfUserId возвращал 0, это говорит о том что игрока уже не существует на сервере.
Нужна ли в данном паблике проверка IsClientInGame?
Нужна ли проверка if(client) на идентификатор 0 в данном паблике? С её помощью, я могу узнать, существует ли игрок, но есть ещё вопрос...
GetClientOfUserId ИМЕННО В ДАННОМ ПАБЛИКЕ Может вернуть идентификатор уже не существующего игрока на сервере? Надо проверять if(client) ?

ИМЕННО ДАННЫЙ ПАБЛИК я отношу ко всем пабликам работающим с помощью HookEvent

Хочу знать это точно и писать правильно! Что-бы ни когда, ни каких нареканий с этим не было 😊

Теоретически в данном паблике, я проверяю кто убил игрока.
Если это был НЕ сервер, и если убийца на сервере, так как он мог бросить гранату и выйти с сервера...
Это я делаю правильно?
В данном случае нужно проверять убитого на индекс 0, а так же на присутствие на сервере с помощью IsClientInGame?

1649392302345.png
 
Последнее редактирование:

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
Время доброе, у вас в голове есть некая путаница, а конкретно. Называть данное событие "пабликом", не очень приемлемо со стороны программирования. Ведь паблик - это модификатор видимости функции, то бишь, она видна во всем файле. Называть функцию - модификатором, ну такое себе... Поверьте мне на слово, но не везде этот модификатор уместен и лучше называйте отныне такие колбеки - ивентами, так будет проще и вернее.
Что касается вашего первого вопроса:
Нужна ли в данном паблике проверка IsClientInGame?
Нет, хотя есть тривиальное правило связанное с проверками: "Лучше написать больше, чем меньше.", теперь давай попробуем разложить это по полочкам. Сейчас меня могут поправить другие скриптеры, но из логики вещей событие срабатывает, когда игрок умирает, оно в принципе так и называется "player_death" и это говорит о том, что мы точно знаем идентификатор убитого игрока, но не факт, что игрок который убил еще на сервере и другие частности, которые я не буду касаться, но как задание, поразмышляйте на досуге поэтому поводу. Поэтому проверка на убитого игрока - нецелесообразна, хотя я не исключаю того факта, что это событие может сработать от смерти какой-либо сущности, правда уже запамятовал 😅 .
Что касается второго вопроса:
Нужна ли проверка if(client) на идентификатор 0 в данном паблике?
Тут все проще, функция GetClientOfUserId вернет 0, только в том случае, если уникального идентификатора уже нет на сервере, то бишь userId, который присваивается, как только игрок подключился - уже нет.
Следовательно, проверкой if (client), вы проверяете есть ли игрок на сервере (то есть исключаете случай, когда индекс равен 0), проверкой IsClientInGame, есть ли на сервере конкретный игрок под индексом в интервале от 1 до MaxClients.

В целом скажу так, для идеальной проверки на наличие игрока на сервере, можете воспользоваться вот такой самописной функцией:
SourcePawn:
bool IsValidClient(int client) {
    if (client > 0 && client <= MaxClients && IsClientInGame(client)) {
        return true;
    }

    return false;
}
В нее можете добавить еще свои проверки, но в целом она используется в 99.999998% случаев.
 
Последнее редактирование:

romeo7

Участник
Сообщения
189
Реакции
93
Так хватает:
public Action Event_PlayerTeam(Event event, const char[] name, bool dontBroadcast)
{
    int client = GetClientOfUserId(event.GetInt("userid"));
  
    if(client && !IsFakeClient(client))
    {
        // your code
    
    }
   
    return Plugin_Continue;
}
   


public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)
{
    int client = GetClientOfUserId(event.GetInt("userid"));
    int attacker = GetClientOfUserId(event.GetInt("attacker"));
  
    if(client && attacker)
    {
        // your code
    
    }
   
    return Plugin_Continue;
}
 
Последнее редактирование:

gameuser425

Участник
Сообщения
30
Реакции
3
Тема к этому не относится.
Я не знаю. Спросите у автора. В примере Action стоит. Может быть, он хочет заблокировать event.
Ну когда не требуется блокировать event приходится писать public void что-бы не возвращать значений.
 

gameuser425

Участник
Сообщения
30
Реакции
3
Время доброе, у вас в голове есть некая путаница, а конкретно. Называть данное событие "пабликом", не очень приемлемо со стороны программирования. Ведь паблик - это модификатор видимости функции, то бишь, она видна во всем файле. Называть функцию - модификатором, ну такое себе... Поверьте мне на слово, но не везде этот модификатор уместен и лучше называйте отныне такие колбеки - ивентами, так будет проще и вернее.
Что касается вашего первого вопроса:

Нет, хотя есть тривиальное правило связанное с проверками: "Лучше написать больше, чем меньше.", теперь давай попробуем разложить это по полочкам. Сейчас меня могут поправить другие скриптеры, но из логики вещей событие срабатывает, когда игрок умирает, оно в принципе так и называется "player_death" и это говорит о том, что мы точно знаем идентификатор убитого игрока, но не факт, что игрок который убил еще на сервере и другие частности, которые я не буду касаться, но как задание, поразмышляйте на досуге поэтому поводу. Поэтому проверка на убитого игрока - нецелесообразна, хотя я не исключаю того факта, что это событие может сработать от смерти какой-либо сущности, правда уже запамятовал 😅 .
Что касается второго вопроса:

Тут все проще, функция GetClientOfUserId вернет 0, только в том случае, если уникального идентификатора уже нет на сервере, то бишь userId, который присваивается, как только игрок подключился - уже нет.
Следовательно, проверкой if (client), вы проверяете есть ли игрок на сервере (то есть исключаете случай, когда индекс равен 0), проверкой IsClientInGame, есть ли на сервере конкретный игрок под индексом в интервале от 1 до MaxClients.

В целом скажу так, для идеальной проверки на наличие игрока на сервере, можете воспользоваться вот такой самописной функцией:
SourcePawn:
bool IsValidClient(int client) {
    if (client > 0 && client <= MaxClients && IsClientInGame(client)) {
        return true;
    }

    return false;
}
В нее можете добавить еще свои проверки, но в целом она используется в 99.999998% случаев.
Благодарю за столь тщательный ответ ☺️ Мои сомнения теперь развиты. По счёт bool IsValidClient(int client) Я всегда сомниваюсь. Стоит ли. Слышал, что возвращение значений это плохо, по этому задействую подобную функцию, только когда в плагине их набирается довольно много. Спасибо!
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
Слышал, что возвращение значений это плохо
интересно, где такое писали?
потому что я за всё время, что пишу/модифицирую плагины, ни разу не встречал такой информации
Сообщения автоматически склеены:

Кстати, а почему в коде мешанина нового и старого синтаксиса?
Сообщения автоматически склеены:

Кроме того событие "player_team" вызывается и при входе/выходе игрока.
Достаточно посмотреть все поля события. Есть, например, параметр «disconnect», который будет равен 1 при выходе игрока с сервера.
 

gameuser425

Участник
Сообщения
30
Реакции
3
интересно, где такое писали?
потому что я за всё время, что пишу/модифицирую плагины, ни разу не встречал такой информации
Сообщения автоматически склеены:

Кстати, а почему в коде мешанина нового и старого синтаксиса?
Сообщения автоматически склеены:

Кроме того событие "player_team" вызывается и при входе/выходе игрока.
Достаточно посмотреть все поля события. Есть, например, параметр «disconnect», который будет равен 1 при выходе игрока с сервера.
Научите новому синтаксису, буду рад 😀 Как умею так и печатаю, вернее даже как считаю правильным. На данный момент считаю так. Может быть кто-то покажет и переубедит.
 

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
Научите новому синтаксису, буду рад 😀 Как умею так и печатаю, вернее даже как считаю правильным. На данный момент считаю так. Может быть кто-то покажет и переубедит.
Ссылка намбер ван: Из оф.документации.
Ссылка намбер ту: Рассуждения какого-то пьяного пользователя о том, как следовало бы писать код на SourcePawn.
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
@L A R S S O N, посмотри исходники дефолтных плагинов
или почитай вики соурсмода
Сообщения автоматически склеены:

можете воспользоваться вот такой самописной функцией
Этот код можно сократить до вот этого варианта:
C-подобный:
stock bool IsValidClient(int client)
{
    return 0 < client && client <= MaxClients && IsClientInGame(client);
}
 
Последнее редактирование:

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #13
Здравствуйте)
Я хочу раз и навсегда разобраться с HookEvent
А точнее с public Action
Вот к примеру паблик, срабатывающий когда игрок вступает в команду.

Посмотреть вложение 94479

Сталкивался с ситуацией в других случаях, когда GetClientOfUserId возвращал 0, это говорит о том что игрока уже не существует на сервере.
Нужна ли в данном паблике проверка IsClientInGame?
Нужна ли проверка if(client) на идентификатор 0 в данном паблике? С её помощью, я могу узнать, существует ли игрок, но есть ещё вопрос...
GetClientOfUserId ИМЕННО В ДАННОМ ПАБЛИКЕ Может вернуть идентификатор уже не существующего игрока на сервере? Надо проверять if(client) ?

ИМЕННО ДАННЫЙ ПАБЛИК я отношу ко всем пабликам работающим с помощью HookEvent

Хочу знать это точно и писать правильно! Что-бы ни когда, ни каких нареканий с этим не было 😊

Теоретически в данном паблике, я проверяю кто убил игрока.
Если это был НЕ сервер, и если убийца на сервере, так как он мог бросить гранату и выйти с сервера...
Это я делаю правильно?
В данном случае нужно проверять убитого на индекс 0, а так же на присутствие на сервере с помощью IsClientInGame?

Посмотреть вложение 94480
вообще я сталкивался с ситуациями когда "моя любимая" ксго возвращала в GetClientOfUserId корректный индекс игрока, хотя его уже не было на сервере и приходилось всё таки добавлять IsClientInGame.
Поэтому я склоняюсь к такому подходу:
  1. Если вероятность что значение может быть не таким как я ожидаю выше 0 (а в ксго это почти всегда так) - я делаю проверку. Лучше проверить лишний раз, чем ловить потом ошибки и выкатывать обновление и еще год объяснять всем что просто нужно обновить плагин
  2. Стараюсь делать проверку как можно раньше и ставлю самые часто "ложные" проверки в начале дабы уменьшить кол-во выполняемого кода. Возможно это экономия на спичках, но стараюсь не упарываться в это.

Слышал, что возвращение значений это плохо
Плохо для кого? чем конкретно плохо?
Стоит всё же проверять информацию, которую где-то "слышали".
 

GoDtm666

Участник
Сообщения
580
Реакции
589
Если затрудняешься в работе функции от SM, то можно посмотреть его исходники sourcemod/PlayerManager.cpp at master · alliedmodders/sourcemod этой функции и увидеть как она получает или передает значение, и какие проверки после нужно еще использовать в плагине для других функций.
 

rejchev

менеджер клоунов
Сообщения
1,669
Реакции
1,291
@GoDtm666, Вы предлагаете заглянуть в исходники человеку, который не понимает что он делает.. .
 

_wS_

Участник
Сообщения
383
Реакции
760
Нужна ли в данном паблике проверка IsClientInGame?
В "событии".

Доступ к userid игрока (от 1 до 65535) у нас есть, наверно начиная с "public bool OnClientConnect", когда игрок в процессе подключения к серверу. IsClientConnected уже возвращает true. Если не было "return false", вызывается OnClientConnected (игрок успешно подключился) и начинается его авторизация и вызов других событий. При этом он всё ещё не в игре (IsClientInGame вернёт false).

Есть нативы, требующие чтобы игрок был в игре (IsClientInGame), например, GetClientTeam.
И есть те, которым достаточно, чтобы игрок был подключен (IsClientConnected), например, IsFakeClient.
IsClientInGame может вернуть true, начиная с OnClientPutInServer.

Если функция требует, чтобы игрок был в игре, и есть шанс, что событие (где используется функция) вызовется до OnClientPutInServer, то стоит добавить IsClientInGame.

IsClientInGame и другое можно заменить на битовые флаги:

PHP:
// true, если в флагах %0 есть все флаги %1.
#define HAS_FLAGS(%0,%1) (((%0) & (%1)) == (%1))

#define FL_IN_GAME (1 << 0)

int g_Flags[MAXPLAYERS + 1] = {0, ...};

public void OnClientPutInServer(int client)
{
    g_Flags[client] |= FL_IN_GAME;
}

public void OnClientDisconnect(int client)
{
    g_Flags[client] &= ~FL_IN_GAME;
}

if (HAS_FLAGS(g_Flags[client], FL_IN_GAME))
{
    // В игре. Эта проверка "легче", чем IsClientInGame.
    // Стоит так делать или нет, наверно зависит от кол-ва/частоты этих IsClientInGame проверок.
}

Нужна ли проверка if(client) на идентификатор 0
Раз какая-то функция может вернуть false/error, то по логике всегда стоит проверять не вернулся ли этот error. И события же могут быть "фейковыми" не от игры, а от любого plugin'а (CreateEvent, FireEvent). Кто-то мог неверные переменные передать и начнутся error'ы.

Можно почти никогда не писать. В основном требуется только для глобальных форвардов, как OnClientPutInServer и других On.. (в api в разделах Forwards). Т.е. можно писать просто:

PHP:
// static, чтобы вдруг не было конфликта имени с чем-то ещё.
static Action Event_PlayerDeath(Event event..
                                
// Или:
Action Event_PlayerDeath(Event event..
Возможно, это даже оптимизация, т.к. чем меньше public'ов, тем меньшие циклы будут.
 

GoDtm666

Участник
Сообщения
580
Реакции
589
@GoDtm666, Вы предлагаете заглянуть в исходники человеку, который не понимает что он делает.. .
Я не вижу ни какой трудности в понятии кода с/с++, когда человек пишет скрипт на языке Pawn.
Человек учится и у него возникают вопросы. Мы кто проходили всякое в программировании этим делимся опытом. Все мы с ноля начинали и искали решения узнав по статьям, у кого-то или изучая коды функций.
Не вижу смысла в Вашем сообщении.
Я преподнес пример, не уверен как работает? Глянул код функции = вопрос решен.
 
Последнее редактирование:

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #18
Можно почти никогда не писать. В основном требуется только для глобальных форвардов, как OnClientPutInServer и других On.. (в api в разделах Forwards).
Писать нужно чтобы понимать может ли эта функция вызываться из-вне. Особенно для того кто потом будет читать этот код. Экономии и оптимизации в этом нет, а дурной тон - есть
Возможно, это даже оптимизация, т.к. чем меньше public'ов, тем меньшие циклы будут.
Какие циклы? Если каллбек зарегистрирован то не важно стоит ли там паблик - он есть списке и итерация по нему будет и его вызов произойдет.

Насколько я помню public никак не влияет на вызовы из ядра SM (но лучше писать для очевидности, как я писал выше), но GetFunctionByName · functions · SourceMod Scripting API Reference не сможет найти функцию без public
 
  • Вау
Реакции: _wS_

_wS_

Участник
Сообщения
383
Реакции
760
Писать нужно чтобы понимать может ли эта функция вызываться из-вне. Особенно для того кто потом будет читать этот код.
Ну если код передается другим, то наверно ты прав, и то, зависит от кол-во кода. Я вот не так давно узнал, что public можно и не писать, и был только рад, вот и поделился, для таких же наверно помешанных на оптимизации.

Экономии и оптимизации в этом нет
Прям 100% да? Не согласен. Тот же упомянутый тобой ниже GetFunctionByName, там цикл идёт по public функциям и strcmp сравнение имён:


А значит, чем меньше таких имён в списке, тем лучше, не?

а дурной тон - есть
А для меня дурной тон, это позволять левым plugin'ам вызывать функции в моем приватном plugine, пусть это даже HookEvent callback. Вызвать все равно можно кнеш, но кое-кто споткнется.
 
Сверху Снизу