[SourcePawn] Урок 14 - Работа с куками (clientprefs)

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #1
[SourcePawn] Урок 14 - Работа с куками (clientprefs)

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

Куки (Cookie) - инструмент позволяющих хранить некоторую информацию об игроках на сервере.
Внутренняя реализация куков в SourceMod реализована в виде SQLite базы. Но API не предоставляет к ней доступ.

API по кукам здесь clientprefs · SourceMod Scripting API Reference

Уровни доступа к кукам:
  • CookieAccess_Public - Видимые для пользователей и разрешены для изменения.
  • CookieAccess_Protected - Видимые для пользователей но запрещены для изменения.
  • CookieAccess_Private - Не видимые для пользователей.

Функции для работы с куками
  • RegClientCookie - Создает новые куки.
    PHP:
    Handle RegClientCookie(const char[] name, const char[] description, CookieAccess access)
    • char[] name - Уникальное имя куков.
    • char[] description - Описание.
    • CookieAccess access - Уровень доступа.
    PHP:
    Handle g_hCookie;
    public void OnPluginStart()
    {
        g_hCookie = RegClientCookie("Lesson", "cookies for a lesson", CookieAccess_Public);
    }
  • FindClientCookie - Ищет куки если они уже были созданы.
    PHP:
    Handle FindClientCookie(const char[] name)
    • char[] name - Уникальное имя куков.
    PHP:
    Handle hCookie = FindClientCookie("Lesson");
    if(hCookie != null)
    {
        // Куки найдены
    }
  • AreClientCookiesCached - Возвращает загружены ли куки игрока.
    PHP:
    bool AreClientCookiesCached(int client)
    • int client - Индекс игрока.
    PHP:
    if(AreClientCookiesCached(iClient))
    {
        // Куки игрока загружены и с ними можно работать
    }
  • GetClientCookie - Получает куки игрока.
    PHP:
    void GetClientCookie(int client, Handle cookie, char[] buffer, int maxlen)
    • int client - Индекс игрока.
    • Handle cookie - Handle куков.
    • char[] buffer - Буфер, для получения куков.
    • int maxlen - Размер буфера.
    PHP:
    char szCookie[64];
    GetClientCookie(iClient, g_hCookie, szCookie, sizeof(szCookie));
  • GetClientCookieTime - Получает время последнего обновления куков игрока (unix).
    PHP:
    int GetClientCookieTime(int client, Handle cookie)
    • int client - Индекс игрока.
    • Handle cookie - Handle куков.
    PHP:
    int iLastCookieUpdate = GetClientCookieTime(iClient, g_hCookie);
  • SetClientCookie - Устанавливает значение куков для игрока.
    PHP:
    void SetClientCookie(int client, Handle cookie, const char[] value)
    • int client - Индекс игрока.
    • Handle cookie - Handle куков.
    • char[] value - Значение.
    PHP:
    SetClientCookie(iClient, g_hCookie, "342");
  • SetAuthIdCookie - Устанавливает значение куков для игрока по SteamID.
    PHP:
    void SetAuthIdCookie(const char[] authID, Handle cookie, const char[] value)
    • char[] authID - SteamID игрока.
    • Handle cookie - Handle куков.
    • char[] value - Значение.
    PHP:
    SetAuthIdCookie("STEAM_0:0:12345678", g_hCookie, "342");
  • ShowCookieMenu - Открывает игроку меню !settings.
    PHP:
    void ShowCookieMenu(int client)
    • int client - Индекс игрока.
    PHP:
    ShowCookieMenu(iClient);
  • GetCookieAccess - Получает уровень доступа куков.
    PHP:
    CookieAccess GetCookieAccess(Handle cookie);
    • Handle cookie - Handle куков.
    PHP:
    CookieAccess iAccess = GetCookieAccess(g_hCookie);
  • SetCookieMenuItem - Добавляет пункт в меню !settings.
    PHP:
    void SetCookieMenuItem(CookieMenuHandler handler, any info, const char[] display);
    • CookieMenuHandler handler - Обратный вызов.
    • any info - Данные для передачи в обратный вызов.
    • char[] display - Текс пункта.
    PHP:
    SetCookieMenuItem(LessonPrefSelected, 0, "Lesson item");
    
    public void LessonPrefSelected(int iClient, CookieMenuAction action, any info, char[] buffer, int maxlen)
    {
        // Обратный вызов
        switch (action)
        {
        case CookieMenuAction_DisplayOption:    // Вызывается когда пункт отображается в меню
            {
                SetGlobalTransTarget(iClient);
                FormatEx(buffer, maxlen, "%t", "CookieMenu_Lesson"); // Отправим фразу из перевода
            }
        case CookieMenuAction_SelectOption:    // Вызывается когда игрок выбирает этот пункт
            {
                // Отправляем ему меню настройки
                DisplayLessonMenu(iClient);    // Ф-я придуманная и не реализована
            }
        }
    }
  • SetCookiePrefabMenu - Добавляет пункт в меню !settings, работа которого автоматическая и не требует обратного вызова.
    PHP:
    void SetCookiePrefabMenu(Handle cookie, CookieMenu type, const char[] display, CookieMenuHandler handler=INVALID_FUNCTION, any info=0);
    • Handle cookie - Handle куков.
    • CookieMenu type - Тип:
      • CookieMenu_YesNo - Да/Нет в меню и "yes"/"no" в результатах (Сохраняется в куки)
      • CookieMenu_YesNo_Int - Да/Нет в меню и 1/0 в результатах (Сохраняется в куки)
      • CookieMenu_OnOff - Вкл/Выкл в меню и "on"/"off" в результатах (Сохраняется в куки)
      • CookieMenu_OnOff_Int - Вкл/Выкл в меню и 1/0 в результатах (Сохраняется в куки)
    • char[] display - Текст пункта.
    • CookieMenuHandler handler - Обратный вызов. По умолчанию = INVALID_FUNCTION
    • any info - Данные для передачи в обратный вызов. По умолчанию = 0
    PHP:
    SetCookiePrefabMenu(g_hCookie, CookieMenu_OnOff_Int, "Уроки", LessonPrefSelected);
    
    // Или если хотим отслеживать изменение:
    public void LessonPrefSelected(int iClient, CookieMenuAction action, any info, char[] buffer, int maxlen)
    {
        // Обратный вызов
        if (action == CookieMenuAction_SelectOption)
        {
            // Статус изменился
        }
    }
  • GetCookieIterator - Получает Handle итератора куков.
    PHP:
    Handle GetCookieIterator();
  • ReadCookieIterator - Получает информацию о куках с итератора.
    PHP:
    bool ReadCookieIterator(Handle iter, char[] name, int nameLen, CookieAccess &access, char[] desc="", int descLen=0);
    • Handle iter - Handle итератора.
    • char[] name - Буфер, для получения уникального имени куков.
    • int nameLen - Размер буфера.
    • CookieAccess &access - Буфер, для получения уровня доступа куков.
    • char[] desc - Буфер, для получения описания куков. По умолчанию = ""
    • int descLen - Размер буфера. По умолчанию = 0
    PHP:
    Handle hIter = GetCookieIterator();
    
    char szCookieName[32], szCookieDesc[255];
    CookieAccess iAccess;
    
    while (ReadCookieIterator(hIter, szCookieName, sizeof(szCookieName), iAccess, szCookieDesc, sizeof(szCookieDesc)) != false)
    {
        PrintToServer("Cookie '%s' (%s), Access = %i", szCookieName, szCookieDesc, iAccess);
    }
    
    delete hIter;
  • OnClientCookiesCached - Событие, которое вызывается когда куки игрока были загружены.
    PHP:
    void OnClientCookiesCached(int client);
    • int client - Индекс игрока.

PHP:
#pragma semicolon 1

#include <sourcemod>
#include <clientprefs>

#pragma newdecls required

Handle g_hCookie;

bool g_bSettings[MAXPLAYERS+1];

public void OnPluginStart()
{
    g_hCookie = RegClientCookie("TestCookie", "Урок работы с куками", CookieAccess_Private);
    SetCookiePrefabMenu(g_hCookie, CookieMenu_OnOff_Int, "TestCookie", TestCookieHandler);
}

public void TestCookieHandler(int iClient, CookieMenuAction action, any info, char[] buffer, int maxlen)
{
    if (action == CookieMenuAction_SelectOption)
    {
        OnClientCookiesCached(iClient);
    }
}

public void OnClientCookiesCached(int iClient)
{
    char szValue[4];
    GetClientCookie(iClient, g_hCookie, szValue, sizeof(szValue));
    if(szValue[0]) // Если в куках что-то записано
    {
        // Получаем это
        g_bSettings[iClient] = view_as<bool>(StringToInt(szValue));
    }
    else // Иначе
    {
        // По умолчанию сделаем опцию включенной
        g_bSettings[iClient] = true;
    }
}
 
Последнее редактирование:

inklesspen

Не пишу модули под LSD :с
Сообщения
1,775
Реакции
966
RegClientCookie - Создает новые куки.
Забыл упомянуть, что RegClientCookie можно использовать как FindClientCookie, вернет то-же значение, если куки уже создан.

Эээ.... Возвращение значение (Перенос строки) э Ручка новая создана куки. Если куки уже существует, ручка будет "до сих пор" станет возвращена
Англ:
upload_2017-2-15_15-31-40.png

--- Добавлено позже ---
Хотя это показал на примере
--- Добавлено позже ---
Но API не предоставляет к ней доступ.
в databases.cfg можно найти данные для подключения куки. Со стороннего плагина можно изменить значение, и этим же плагином во всех других плагинах запустить OnClientCookieLoaded (Или че там)
 

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #3
Просили сделать пример работы с Cookies.
Во вложении этот самый "пример". Сделал первое, что в голову пришло.

Так же, прикладываю уже в виде текста пару функций для работы с int/float значениями куков.
PHP:
stock int GetClientIntCookie(int iClient, Handle hCookie) {
    char szBuffer[13];
    GetClientCookie(iClient, hCookie, szBuffer, sizeof(szBuffer));
    return StringToInt(szBuffer);
}

stock void SetClientIntCookie(int iClient, Handle hCookie, int iValue) {
    char szBuffer[13];
    IntToString(iValue, szBuffer, sizeof(szBuffer));
    SetClientCookie(iClient, hCookie, szBuffer);
}

stock float GetClientFloatCookie(int iClient, Handle hCookie) {
    char szBuffer[32];
    GetClientCookie(iClient, hCookie, szBuffer, sizeof(szBuffer));
    return StringToFloat(szBuffer);
}

stock void SetClientFloatCookie(int iClient, Handle hCookie, float fValue) {
    char szBuffer[32];
    FloatToString(fValue, szBuffer, sizeof(szBuffer));
    SetClientCookie(iClient, hCookie, szBuffer);
}
P.S.: bool можно приравнять к обычному int со значениями 1/0.
--- Добавлено позже ---
Со стороннего плагина можно изменить значение, и этим же плагином во всех других плагинах запустить OnClientCookieLoaded (Или че там)
Нет, нельзя.
Расширение clientprefs при коннекте игрока сохраняет все данные у себя в памяти, и при дисконнекте всё содержимое памяти отправляет в БД. Ручное редактирование значений в БД не поможет. Расширение всё равно даже не заметит, и при дисконнекте вернёт всё то, что хранило у себя в памяти.
 

Вложения

  • CookiesExample.sp
    3.9 КБ · Просмотры: 148
Последнее редактирование:

Kailo

Участник
Сообщения
194
Реакции
896
Со стороннего плагина можно изменить значение, и этим же плагином во всех других плагинах запустить OnClientCookieLoaded (Или че там)
Ну вообще можно сделать о чём ты говоришь, но это может вызвать не тот эффект что ты ожидал.
Ну во-первых о изменении значения. Зная имя cookie (посмотреть в оригинальном плагине, где это cookie используется) Функция FindClientCookie.
PHP:
Handle cookie = FindClientCookie("mycookie"); // Получаем handle cookie
if (cookie) {
    ...
    SetClientCookie(client, cookie, "new_value");
    cookie.Close();
}
Теперь о вызове OnClientCookiesCached.
Ну ты говоришь о запуске во всех, но думаю такого не стоит делать, это может привести к плохим последствиям, если на самом деле его еще рано вызывать и cookie не готовы (ты же говорил только о вызове).
PHP:
void Exec()
{
    static Handle fwd = null;
    if (!fwd)
    {
        fwd = CreateGlobalForward("OnClientCookiesCached", ET_Ignore, Param_Cell);
    }
    for (int client = 1; client <= MaxClients; client++)
    {
        if (IsClientAuthorized(client))
        {
            Call_StartForward(fwd);
            Call_PushCell(client);
            Call_Finish();
        }
    }
}
P.S. А вообще плохо так делать. :focus:
 
Последнее редактирование модератором:

Crocell

Мошенник
Сообщения
106
Реакции
42
Такой вопрос сложился, можно ли использовать куки соответственно приватные для хранения в себе какой либо информации. Если 1 сервер.
По типу: Важных чисел, номеров, или же даже банов?
И следующий вопрос, можно ли как-то обойти проверку куков? ну допустим если в куках хранится мут игрока.
 

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #6
Приветствую.

можно ли использовать куки соответственно приватные для хранения в себе какой либо информации
Можно.

можно ли как-то обойти проверку куков? ну допустим если в куках хранится мут игрока.
Куки хранятся в базе. База может быть настроена на MySQL-хранилище.
Куки загружаются из базы принудительно после авторизации игрока (OnClientAuthorized() событие). Они могут не загрузиться, только если с базой есть затруднения.
 

x330122

Участник
Сообщения
357
Реакции
152
Можно ли как-то принудительно сохранить куки игроку ? Не так что он вышел и только тогда куки сохраняются, просто бывает так что если сервер вылетел то куки не сохраняются у игрока
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
Можете скинуть код удаления из куков данных об игроке ?
Я так понимаю это надо делать через SQL запрос
PHP:
stock DeleteClientCookie(...);
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #9
Можете скинуть код удаления из куков данных об игроке ?
Я так понимаю это надо делать через SQL запрос
PHP:
stock DeleteClientCookie(...);
если очистить то "" можно сетнуть. Если именно удалить то надо создавать коннекшн и удалять запросом:
SQL:
DELETE FROM sm_cookie_cache WHERE player = 'STEAM_X:X:XXXX';
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
если очистить то "" можно сетнуть. Если именно удалить то надо создавать коннекшн и удалять запросом:
SQL:
DELETE FROM sm_cookie_cache WHERE player = 'STEAM_X:X:XXXX';
P.S. эх, придется все таки разбираться с SQLite (плохо соображаю в СУБД)
 

Dragokas

Добрая душа
Сообщения
229
Реакции
213
@Vit_ amin

Проще всего, качаешь любой офлайновый клиент. Например: DB Browser for SQLite

Забираешь с сервера: /addons/sourcemod/data/sqlite/clientprefs-sqlite.sq3
Переименовываешь в clientprefs-sqlite.sqlite

Скармливаешь его той проге (Файл, Открыть базу данных).
Вкладка "SQL", вставляешь запрос Крузи, кнопка Play.

(или тоже самое, через вкладку "Данные", Steam в фильтр, Удалить запись)

Переименовываешь, возвращаешь всё обратно.
 
  • Мне нравится
Реакции: d3v
Сверху Снизу