SourcePawn [SourcePawn] Урок 3 - События (Events)

Pushistik↯❤

Команда форума
Регистрация
6 Июл 2017
Сообщения
393
Реакции
97
Баллы
28
[SourcePawn] Урок 3 - События (Events)
<= К содержанию
В SourceMod есть встроенные события:
  • OnMapStart (старт карты)
  • OnMapEnd (конец карты)
  • OnPluginStart (запуск плагина)
  • OnPluginEnd (остановка плагина)
  • OnClientConnected (игрок подключился)
  • OnClientDisconnect (игрок отключился)
  • и много других
Но существуют еще события самого игрового сервера, которые возможно отловить, изменить или отправить.

  • Отлов событий
    Чтобы отловить событие необходимо знать его имя. Его можно узнать здесь Game Events (Source) - AlliedModders Wiki
    Существует 3 режима отлова событий:
    1. EventHookMode_Pre - Обратный вызов происходит до того, как событие произойдет
    2. EventHookMode_Post - Обратный вызов происходит после того как, событие произошло (Используется по умолчанию)
    3. EventHookMode_PostNoCopy - Обратный вызов происходит после того как, событие произошло, но данные события не копируются. Используется для оптимизации, например, когда нужно знать что событие произошло, но не нужно получать его параметры

    Есть 2 функции для отлова событий.
    Синтаксис:
    PHP:
    void HookEvent(const char[] name, EventHook callback, EventHookMode mode);
    [/LIST]
    bool HookEventEx(const char[] name, EventHook callback, EventHookMode mode);
    • name - Имя события
    • callback - Имя функции обратного вызова
    • mode - Режим отлова (см. выше)
    Отличие функций HookEvent и HookEventEx заключается в том что если событие не существует то функция HookEvent сообщит об этом в error лог, а HookEventEx просто вернет false. При этом отлов не будет выполнен.

    Функции обратных вызовов для событий бывают 2-х видов:
    • Для EventHookMode_Post и EventHookMode_PostNoCopy:
      PHP:
      function void(Event event, const char[] name, bool dontBroadcast)
    Параметры:
    • event - Объект типа Event, который содержит данные о событии (для EventHookMode_PostNoCopy равен null, но в действительности это не работает)
    • name - Имя события
    • dontBroadcast - Было ли передано событие клиентам (true если не было, противном случае - false)
    • Для EventHookMode_Pre:
      PHP:
      function Action(Event event, const char[] name, bool dontBroadcast)
    С параметрами всё тоже самое, разница только в типе данных функции.
    Тип Action может иметь значения:
    • Plugin_Continue - Разрешает продолжение события без изменений
    • Plugin_Changed - Разрешает продолжение события с изменениями
    • Plugin_Handled - Запрещает выполнение события, разрешая обрабатывать остальные вызовы
    • Plugin_Stop - Запрещает выполнение события и обработку остальных вызовов
    Для Event возврат Plugin_Continue или Plugin_Changed разрешит событию произойти, а возврат Plugin_Handled запретит вывод события.
    Сами события запретить нельзя, можно лишь запретить вывод уведомлений о них (сообщения об убийстве справа вверху, сообщение в чат при подключении/отключении игроков)
    Тип Event является дочерним от типа Handle
    Его свойства и методы для работы с ним можно посмотреть здесь: Event · events · SourceMod Scripting API Reference
    Примеры работы с событиями:
    PHP:
    #pragma semicolon 1
    #include <sourcemod>
    #pragma newdecls required
    
    public void OnPluginStart()
    {
        HookEvent("player_death", Event_PlayerDeath);    // Ловим событие с именем player_death
        // Event_PlayerDeath это имя функции, которая будет вызвана когда на сервере произойдет это событие
        // Мы не указали режим отлова, это значит что по умолчанию он будет EventHookMode_Post
    }
    
    public void Event_PlayerDeath(Event hEvent, const char[] sEvName, bool bDontBroadcast)    // Функция будет вызвана когда на сервере произойдет событие player_death
    {
        // Параметры события: https://wiki.alliedmods.net/Counter-Strike:_Source_Events#player_death
        int iUserID = hEvent.GetInt("userid");                    // userid жертвы
        PrintToServer("userid: %i", iUserID);
        int iAttackerUserID = hEvent.GetInt("attacker");        // userid убийцы
        PrintToServer("attacker: %i", iAttackerUserID);
        char szWeapon[34];
        hEvent.GetString("weapon", szWeapon, sizeof(szWeapon));    // название оружия
        PrintToServer("weapon: %s", szWeapon);
        int bHS = hEvent.GetBool("headshot");                    // В голову ли (true - да, иначе - false)
        PrintToServer("headshot: %b", bHS);
    }
    PHP:
    public void OnPluginStart()
    {
        HookEvent("player_spawn", Event_PlayerSpawn);    // Ловим событие с именем player_spawn
        // Event_PlayerSpawn это имя функции, которая будет вызвана когда на сервере произойдет это событие
        // Мы не указали режим отлова, это значит что по умолчанию он будет EventHookMode_Post
    }
    
    public void Event_PlayerSpawn(Event hEvent, const char[] sEvName, bool bDontBroadcast)    // Функция будет вызвана когда на сервере произойдет событие player_spawn
    {
        int iUserID = hEvent.GetInt("userid");        // *1
        int iClient = GetClientOfUserId(iUserID);    // *2
        if(iClient)    // Аналогично if(iClient != 0)        *3
        {
            PrintToChat(iClient, "Вы возродились!");    // *4
        }
    }
    *Номер - Указатель на строку. Нужен для объяснений.

    Находим наше событие на wiki Generic Source Events - AlliedModders Wiki
    Смотрим его параметры:
    upload_2016-9-6_0-45-4.png
    У нашего события всего 1 параметр типа short. В SourcePawn он приводится к типу int
    Параметр имеет имя userid
    userid это уникальный идентификатор игрока на сервере.
    При запуске сервера первый вошедший игрок получает userid - 1, второй - 2, третий - 3
    Если первый игрок перезайдет он получит userid - 4.
    И так будет происходить до тех пор пока не произойдет перезапус сервера и всё начнется сначала.
    У сервера userid всегда 0

    В строке *1 мы получаем параметр userid
    • iUserID - имя нашей перменной
    • hEvent - имя объекта типа Event, который был передан в функции
    • GetInt - метод для типа Event, который получает целочисленное значения параметра переданого его как аргумент
    • userid - это имя параметра
    Допустим мы получили число 1437
    Все функции для работы с игроками требуют как аргумент индекс игрока.
    Индекс - это номер игрока на сервере.
    Он может быть от 1 до MaxClients. MaxClients это константа, которая хранит количество слотов на сервере.
    Следовательно индекс игрока может быть от 1 до количества слотов.
    У сервера индекс всегда 0.
    Значит нам нужно получить индекс игрока.
    Для работы с userid есть 2 фукнции:
    • Возвращает userid игрока, из его индекса (его передаем как аргумент)
      PHP:
      int GetClientUserId(int client)
    • Возвращает индекс игрока, из его userid (его передаем как аргумент)
      PHP:
      int GetClientOfUserId(int userid)
    В случае если игрока уже нет на сервере, т. е. userid уже не существует функция вернет 0.
    У нас есть userid, а нужен индекс, значит используем вторую функцию (строка *2)
    Помним что если userid не существует функция вернет 0, поэтому проверяем получили ли мы индекс игрока (строка *3)
    Если условие истинно - наш игрок появился на карте (спавнился).
    Строки *1 и *2 можно объединить в одну:
    PHP:
    int iClient = GetClientOfUserId(hEvent.GetInt("userid"));
    Далее выполним с ним какие-то действия.
    Например, сообщим ему что он возродился с помощью функции PrintToChat (строка *4)
    Пример 2:
    PHP:
    #pragma semicolon 1
    
    #include <sourcemod>
    
    #pragma newdecls required
    
    public void OnPluginStart()
    {
        HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre);
    }
    
    public Action Event_PlayerDeath(Event hEvent, const char[] sEvName, bool bDontBroadcast)
    {
        // Параметры: https://wiki.alliedmods.net/Counter-Strike:_Source_Events#player_death
        if (hEvent.GetBool("headshot"))
        {
            return Plugin_Handled;
        }
    
        return Plugin_Continue;
    }
    Событие player_death
    upload_2016-9-6_0-46-36.png

    Этот код будет блокировать вывод сообщения об убийстве (справа вверху) если убийство было произведено в голову.

    Пример 3:
    PHP:
    #pragma semicolon 1
    
    #include <sourcemod>
    
    #pragma newdecls required
    
    public void OnPluginStart()
    {
        HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre);
    }
    
    public Action Event_PlayerDeath(Event hEvent, const char[] sEvName, bool bDontBroadcast)
    {
        hEvent.SetBool("headshot", true);
        return Plugin_Changed;
    }
    Этот код будет изменять вывод сообщений об убийстве (справа вверху), отображая что все убийства происходят в голову.
    • Отправка событий
      PHP:
      void SendDeathMessage(int iAttacker, int iVictim, const char[] sWeapon, bool bHeadShot)
      {
          Event hEvent = CreateEvent("player_death");    // Имя события
          if (hEvent != null)
          {
              hEvent.SetInt("userid", GetClientUserId(iVictim));    // userid жертвы
              hEvent.SetInt("attacker", GetClientUserId(iAttacker));    // userid убийцы
              hEvent.SetString("weapon", sWeapon);    // Название оружия
              hEvent.SetBool("headshot", bHeadShot);    // В голову ли
              hEvent.Fire(true);    // true - отправит сообщение игрокам
          }
      }
    Эта функция отправляет событие смерти игрока.
<= К содержанию
 
Последнее редактирование:
Сверху Снизу