[SourcePawn] Урок 11 - Админ меню

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #1
[SourcePawn] Урок 11 - Админ меню

<- К содержанию


PHP:
#pragma semicolon 1
#include <sourcemod>

#undef REQUIRE_PLUGIN    // Все библиотеки подключенные ниже этого  - не обязательные для работы плагина

// Подключаем библиотеку
#include <adminmenu>

#pragma newdecls required

// Создаем переменную для админ-меню

TopMenu g_hTopMenu = null;

// При старте плагина проверяем
public void OnPluginStart()
{
    // Если библиотека есть
    if (LibraryExists("adminmenu"))
    {
        TopMenu hTopMenu;
        if ((g_hTopMenu = GetAdminTopMenu()) != null) // Если админ-меню уже создано
        {
            // Вызываем ф-ю, в которой добавляется пункт в админ-меню
            OnAdminMenuReady(hTopMenu);
        }
    }
}

// Если библиотека была отключена
public void OnLibraryRemoved(const char[] szName)
{
    if (StrEqual(szName, "adminmenu"))
    {
        g_hTopMenu = null;
    }
}

// Ф-я вызывается когда админ-меню готово к добавлению пунктов
public void OnAdminMenuReady(Handle aTopMenu)
{
    /*
    Дальше всё очень сложно, просто всё делаем так же
    */
    TopMenu hTopMenu = TopMenu.FromHandle(aTopMenu);

    if (hTopMenu == g_hTopMenu)
    {
        return;
    }

    g_hTopMenu = hTopMenu;

    /* Вот теперь можно добавлять что хотим

    Необходимо различать 2 понятия:
    1. Категория - пункт главной странице админ-меню
    2. Пункт - пункт внутри категории

    Т.е. структура админ-меню выглядит так:

    Админ-меню
    1. Категория 1
        1. Пункт 1
        2. Пункт 2
        3. Пункт 3
        4. Пункт 4
    2. Категория 2
        1. Пункт 1
        2. Пункт 2
    3. Категория 3
        1. Пункт 1
        2. Пункт 2
    4. Категория 4
        1. Пункт 1
        2. Пункт 2
        3. Пункт 3


    Дальше 2 варианта:
        a) Создать категорию и добавить в неё пункты
        b) Добавить пункты в уже существующую категорию
 
        Либо и то и то
    */

    // Вариант a
    TopMenuObject hMyCategory = g_hTopMenu.AddCategory("vip_admin_category", Handler_MenuVIPAdmin, "vip_admin", ADMFLAG_ROOT, "Моя категория 1");
    /*
    "vip_admin_category"    - уникальное имя категории
    Handler_MenuVIPAdmin    - обработчик событий
    "vip_admin"                - команда (для access overrides)
    ADMFLAG_ROOT            - Флаг доступа по умолчанию
    "Моя категория 1"        - Описание категории (опционально)
    */

    // Вариант b
    TopMenuObject hMyCategory = g_hTopMenu.FindCategory("vip_admin_category");
    // Если категории нет вернет INVALID_TOPMENUOBJEC


    if (hMyCategory != INVALID_TOPMENUOBJECT)
    {
        // Теперь можем добавить пункты
        g_hTopMenu.AddItem("vip_add_item", Handler_MenuVIPAdd, hMyCategory, "vip_add", ADMFLAG_ROOT, "Мой пункт 1");
        /*
        "vip_add_item"            - уникальное имя пункта
        Handler_MenuVIPAdd        - обработчик событий
        hMyCategory                - Объект категории в которую должен быть добавлен пункт
        "vip_add"                - команда (для access overrides)
        ADMFLAG_ROOT            - Флаг доступа по умолчанию
        "Мой пункт 1"            - Описание пункта (опционально)
        */

        g_hTopMenu.AddItem("vip_list_item",                Handler_MenuVIPList,            hMyCategory, "vip_list",            ADMFLAG_ROOT);
        g_hTopMenu.AddItem("vip_reload_players_item",    Handler_MenuVIPReloadPlayers,    hMyCategory, "vip_reload_players",    ADMFLAG_ROOT);
    }
}

// обработчик событий категории
public void Handler_MenuVIPAdmin(TopMenu hMenu, TopMenuAction action, TopMenuObject object_id, int iClient, char[] sBuffer, int maxlength)
{
    switch (action)
    {
        // Когда категория отображается пунктом на главной странице админ-меню
    case TopMenuAction_DisplayOption:
        {
            FormatEx(sBuffer, maxlength, "Управление VIP");
        }
        // Когда категория отображается заглавием меню
    case TopMenuAction_DisplayTitle:
        {
            FormatEx(sBuffer, maxlength, "Управление VIP");
        }
    }
}

// обработчик событий пункта
public void Handler_MenuVIPAdd(TopMenu hMenu, TopMenuAction action, TopMenuObject object_id, int iClient, char[] sBuffer, int maxlength)
{
    switch (action)
    {
        // Когда пункт отображается в категории
    case TopMenuAction_DisplayOption:
        {
            FormatEx(sBuffer, maxlength, "Добавить VIP-игрока");
        }
        // Когда пункт выбрали
    case TopMenuAction_SelectOption:
        {
            // открываем меню со списком игроков.
        }
    }
}

public void Handler_MenuVIPList(TopMenu hMenu, TopMenuAction action, TopMenuObject object_id, int iClient, char[] sBuffer, int maxlength)
{
    switch (action)
    {
    case TopMenuAction_DisplayOption: FormatEx(sBuffer, maxlength, "Список VIP-игроков");
    case TopMenuAction_SelectOption:
        {
            // Открываем список VIP-игроков
        }
    }
}

public void Handler_MenuVIPReloadPlayers(TopMenu hMenu, TopMenuAction action, TopMenuObject object_id, int iClient, char[] sBuffer, int maxlength)
{
    switch (action)
    {
    case TopMenuAction_DisplayOption:FormatEx(sBuffer, maxlength, "Перезагрузка VIP-игроков");
    case TopMenuAction_SelectOption:
        {
            //
        }
    }
}

Cобытия админ-меню:
  • OnAdminMenuCreated - Админ-меню готово к добавлению категорий
    PHP:
    void OnAdminMenuCreated(Handle topmenu)
  • OnAdminMenuReady - Админ-меню готово к добавлению пунктов
    PHP:
    void OnAdminMenuReady(Handle topmenu)
  • ADMINMENU_SERVERCOMMANDS или "ServerCommands" - Управление сервером
  • ADMINMENU_VOTINGCOMMANDS или "VotingCommands" - Управление голосованиями

Если вы хотите добавить пункты одну из 3-х стандартных категорий в FindCategory можно использовать:
  • ADMINMENU_PLAYERCOMMANDS или "PlayerCommands" - Управление игроками
  • ADMINMENU_SERVERCOMMANDS или "ServerCommands" - Управление сервером
  • ADMINMENU_VOTINGCOMMANDS или "VotingCommands" - Управление голосованиями

Вспомогательные функции админ-меню:
  • RedisplayAdminMenu - Повторно отображает админ-меню админу после выбора пункта.
    PHP:
    bool RedisplayAdminMenu(Handle topmenu, int client)
  • AddTargetsToMenu - Добавляет цели (игроков) в меню.
    PHP:
    int AddTargetsToMenu(Handle menu, int source_client, bool in_game_only, bool alive_only)
  • AddTargetsToMenu2 - Тоже что и AddTargetsToMenu но с использованием фильтров.
    PHP:
    int AddTargetsToMenu2(Handle menu, int source_client, int flags)

    Фильтры:
    PHP:
    #define COMMAND_FILTER_ALIVE        (1<<0)        /**< Только живые */
    #define COMMAND_FILTER_DEAD            (1<<1)        /**< Только мертвые */
    #define COMMAND_FILTER_CONNECTED    (1<<2)        /**< Разрешить игро, которые не полностью в игре (IsClientInGame) */
    #define COMMAND_FILTER_NO_IMMUNITY    (1<<3)        /**< Игнорировать правила иммунитета */
    #define COMMAND_FILTER_NO_MULTI        (1<<4)        /**< Запретить множественный выбор (Не используется для данной функции) */
    #define COMMAND_FILTER_NO_BOTS        (1<<5)        /**< Исключить ботов */

Еще обратите внимание на методы типа TopMenu · topmenus · SourceMod Scripting API Reference
Есть интересные и полезные ф-и.

Что не ясно или о чем забыл написать - пишите, дополню.
 
Последнее редактирование:

Kailo

Участник
Сообщения
194
Реакции
896
Я бы добавил информацию о OnAdminMenuCreated и зачем она нужна. Так же рассказал бы о макро-константах админ меню с именами стандартных категорий (ADMINMENU_PLAYERCOMMANDS, ADMINMENU_SERVERCOMMANDS, ADMINMENU_VOTINGCOMMANDS), и о вспомогательной функции RedisplayAdminMenu.
Оффтоп
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #3
Обновил. Дополнил немного.
 

JDW

Мы открываем бизнес
Сообщения
376
Реакции
325
В этом месте ошибка: if ((g_hTopMenu = GetAdminTopMenu()) != null) // Если админ-меню уже создано

Вместо g_hTopMenu нужно использовать hTopMenu
 

Nico Yazawa

Бывший MrChester =(
Сообщения
326
Реакции
303
Можно ли как-то открыть определенную категорию из любого участка кода?
Сообщения автоматически склеены:

@R1KO need you help
 
Последнее редактирование:

crux

Участник
Сообщения
49
Реакции
4
Я бы добавил информацию о OnAdminMenuCreated и зачем она нужна. Так же рассказал бы о макро-константах админ меню с именами стандартных категорий (ADMINMENU_PLAYERCOMMANDS, ADMINMENU_SERVERCOMMANDS, ADMINMENU_VOTINGCOMMANDS), и о вспомогательной функции RedisplayAdminMenu.
Оффтоп
А есть такая возможность, сделать пункт в админ-меню неактивным?
Например: захожу в категорию управление игроками и пункт шлепнуть игрока белый.
 

Сергей68

Неуместный юмор
Сообщения
420
Реакции
377
@crux, передать стиль пункта
  • ITEMDRAW_DEFAULT - Нормальный пункт.
  • ITEMDRAW_DISABLED - Пункт, который нельзя выбрать (белого цвета).
  • ITEMDRAW_RAWLINE - Пункт, который не имеет слота и имеет только текст
  • ITEMDRAW_NOTEXT - Пункт, без текста
  • ITEMDRAW_SPACER - Пункт, для отступа
  • ITEMDRAW_IGNORE - Пункт, будет игнорироваться (rawline + notext)
  • ITEMDRAW_CONTROL - Пункт, который имеет функцию управления (назад / далее / выход)
 

crux

Участник
Сообщения
49
Реакции
4
@crux, передать стиль пункта
  • ITEMDRAW_DEFAULT - Нормальный пункт.
  • ITEMDRAW_DISABLED - Пункт, который нельзя выбрать (белого цвета).
  • ITEMDRAW_RAWLINE - Пункт, который не имеет слота и имеет только текст
  • ITEMDRAW_NOTEXT - Пункт, без текста
  • ITEMDRAW_SPACER - Пункт, для отступа
  • ITEMDRAW_IGNORE - Пункт, будет игнорироваться (rawline + notext)
  • ITEMDRAW_CONTROL - Пункт, который имеет функцию управления (назад / далее / выход)
На счет обычного меню я в курсе, но с админ-меню такое не прокатывает, там даже нет стилей для пунктов.

g_hTopMenu.AddItem("vip_add_item", Handler_MenuVIPAdd, hMyCategory, "vip_add", ADMFLAG_ROOT, "Мой пункт 1");

Добавление в новою категорию пункта, как тут ITEMDRAW_DISABLED пристроить? Я пытался уже прописывать, видимо пункты, которые находятся в самом админ меню, не поддерживают стилизацию.
 

rgba

Участник
Сообщения
132
Реакции
14
Из-за чего в пункте нет названия?
код:
public void OnAdminMenuReady(Handle aTopMenu)
{
    TopMenu topmenu = TopMenu.FromHandle(aTopMenu);

    /* Block us from being called twice */
    if (topmenu == hTopMenu)
    {
        return;
    }
   
    /* Save the Handle */
    hTopMenu = topmenu;
   
    /* Find the "Player Commands" category */
    TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);

    if (player_commands != INVALID_TOPMENUOBJECT)
    {
        hTopMenu.AddItem("sm_cc", Handler_menuCC, player_commands, "sm_cc", ADMFLAG_SLAY, "Проверка на читы");
    }
}

public void Handler_menuCC(TopMenu hMenu, TopMenuAction action, TopMenuObject object_id, int iClient, char[] sBuffer, int maxlength)
{
    if(IsClientInGame(iClient)){
   
        FakeClientCommand(iClient, "sm_cc");
    }
}
 

Вложения

  • Безымянный.png
    Безымянный.png
    32.9 КБ · Просмотры: 22

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979
Из-за чего в пункте нет названия?
а потому что ты его не задал

Код должен был вот так выглядеть:
C-подобный:
public void OnAdminMenuReady(Handle aTopMenu)
{
    TopMenu topmenu = TopMenu.FromHandle(aTopMenu);
    /* Block us from being called twice */
    if (topmenu == hTopMenu)
    {
        return;
    }

    /* Save the Handle */
    hTopMenu = topmenu;

    /* Find the "Player Commands" category */
    TopMenuObject player_commands = hTopMenu.FindCategory(ADMINMENU_PLAYERCOMMANDS);
    if (player_commands != INVALID_TOPMENUOBJECT)
    {
        hTopMenu.AddItem("sm_cc", Handler_menuCC, player_commands, "sm_cc", ADMFLAG_SLAY);
    }
}

public void Handler_menuCC(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
    switch(action)
    {
        case TopMenuAction_DisplayOption: FormatEx(buffer, maxlength, "Проверка на читы"); // задаём имя пункта в разделе
        case TopMenuAction_SelectOption:  FakeClientCommand(param, "sm_cc"); // задаём действие при выборе пункта
    }
}
 
Сверху Снизу