[SourcePawn] Урок 5 - DataPack

Тема в разделе "Программирование / Скриптинг", создана пользователем R1KO, 2 окт 2016.

  1. R1KO

    R1KO Супер-модератор

    Сообщения:
    5.972
    Симпатии:
    2.978
    [SourcePawn] Урок 5 - DataPack

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

    DataPack - производный тип от Handle, который позволяет хранить данные различных типов.
    Часто нужно передать в функцию несколько значений или же массив (строку), а функция может получать только 1 параметр. Такое встречается при работе с таймерами, запросами в базу, другими запросами, которым в обратный вызов необходимо передать нужные значения.
    Поэтому DataPack используется чтобы записать в него данные, передать его в нужные функции, затем извлечь из него данные и уничтожить его.
    У DataPack есть особенность - данные из него нужно извлекать в той же последовательности, в которой они были записаны.

    Методы для работы с DataPack можно найти здесь DataPack · datapack · SourceMod Scripting API Reference

    Рассмотрим их подробнее:
    • Методы для работы с DataPack
      • DataPack - Создает объект типа DataPack
        PHP:
        DataPack hPack = new DataPack();
      • Reset - Сбрасывает позицию считывания с DataPack, чтобы начать считывание/запись сначала
        PHP:
        hPack.Reset();    // Сбросит позицию считывания
        hPack.Reset(true);    // Сбросит позицию считывания и очистит DataPack
      • IsReadable - Возвращает логическое значение возможно ли считать данные из DataPack
        PHP:
        int iValue 0;
        if(
        hPack.IsReadable()) // В DataPack еще есть значение для считывания
        {
            
        iValue hPack.ReadCell();
        }
      • Position - Свойство, которое позволяет указывать/получать позицию для считывания.
        При этом позиция определяется количеством байт записанных данных:
        PHP:
        // Напишем простой плагин:
        public void OnPluginStart()
        {
            
        DataPack hPack = new DataPack();
            
        LogMessage("Position: %i"hPack.Position);
            
        // Сейчас позиция = 0
            
        hPack.WriteCell(5);    // Запишет число 5.
            
        LogMessage("Position: %i"hPack.Position);
            
        // Каждый метод записи сперва записывает количество байт для записи, а затем данные
            // Значит чтобы записать число 5 (int) ему нужно 8 байт (2 раза по 4)
            // Сейчас позиция = 9 т.к. мы записали 8 байт и следующая запись будет начинаться с 9-го байта
            
        hPack.WriteFloat(7.5);
            
        LogMessage("Position: %i"hPack.Position);
            
        // Сейчас позиция = 18
            
        hPack.WriteString("string");
            
        LogMessage("Position: %i"hPack.Position);    // 6 символов по 1 байт и еще 1 нулевой, обозначающий конец строки, и того 7 символов по 1 байту = 7 байт
            // Сейчас позиция = 30
            
        hPack.WriteCell(1);
            
        LogMessage("Position: %i"hPack.Position);
            
        // Сейчас позиция = 39

            
        hPack.Reset(); // Возвращаем позицию на 0
            
        LogMessage("Position: %i"hPack.Position);
            
        int iValue hPack.ReadCell();
            
        LogMessage("Position: %i -> %i"hPack.PositioniValue);
            
        float fValue hPack.ReadFloat();
            
        LogMessage("Position: %i -> %.2f"hPack.PositionfValue);
            
        char szBuffer[256];
            
        hPack.ReadString(szBuffersizeof(szBuffer));
            
        LogMessage("Position: %i -> %s"hPack.PositionszBuffer);
            
        iValue hPack.ReadCell();
            
        LogMessage("Position: %i -> %i"hPack.PositioniValue);
            
            
        delete hPack;
        }
        Результат:
        Визуально выглядит так:
        Код:
        00 - Позиция 1
        01 --\ 
        02 ---\        Значение = 4 (указывает что хранить будем значение размером 4 байта)
        03 ---/        Размер = 4 байта (размер int)
        04 --/
        05 --\ 
        06 ---\        Значение = 5
        07 ---/        Размер = 4 байта (размер int)
        08 --/
        09 - Позиция 2
        10 --\ 
        11 ---\        Значение = 4 (указывает что хранить будем значение размером 4 байта)
        12 ---/        Размер = 4 байта (размер int)
        13 --/
        14 --\ 
        15 ---\        Значение = 7.5
        16 ---/        Размер = 4 байта (размер float)
        17 --/
        18 - Позиция 3
        19 --\ 
        20 ---\        Значение = 7 (указывает что хранить будем 7 символов по 1 байт каждый)
        21 ---/        Размер = 4 байта (размер int)
        22 --/
        23 - Символ 's'
        24 - Символ 't'
        25 - Символ 'r'
        26 - Символ 'i'
        27 - Символ 'n'
        28 - Символ 'g'
        29 - Символ '\0'
        30 - Позиция 4
        31  --\ 
        32  ---\        Значение = 4 (указывает что хранить будем значение размером 4 байта)
        33  ---/        Размер = 4 байта (размер int)
        34  --/
        35  --\ 
        36  ---\        Значение = 1
        37  ---/        Размер = 4 байта (размер float)
        38  --/
        39 - Позиция 5
        
        Числа - это количество байт
    • Методы для записи в DataPack
      • WriteCell - Записывает в DataPack ячейку (int, Handle и любое другое 4-х байтовое значение)
        PHP:
        hPack.WriteCell(5);
      • WriteFloat - Записывает в DataPack число с плавающей точкой (дробное)
        PHP:
        hPack.WriteFloat(7.3);
      • WriteString - Записывает в DataPack строку
        PHP:
        hPack.WriteString("моя строка");
      • WriteFunction - Записывает в DataPack указатель на функцию
        PHP:
        function MyFunc GetFunctionByName(null"MyFunction");
        if(
        MyFunc != INVALID_FUNCTION)
        {
            
        hPack.WriteFunction(MyFunc);
        }
    • Методы для чтения из DataPack
      • ReadCell - Получает из DataPack ячейку
        PHP:
        int iValue hPack.ReadCell();
      • ReadFloat - Получает из DataPack число с плавающей точкой (дробное)
        PHP:
        float fValue hPack.ReadFloat();
      • ReadString - Получает из DataPack строку
        PHP:
        char szBuffer[256];
        hPack.ReadString(szBuffersizeof(szBuffer));
      • ReadFunction - Полуачет из DataPack указатель на функцию
        PHP:
        function MyFunc hPack.ReadFunction(MyFunc);
    Когда DataPack больше не нужен его обязательно нужно удалить:
    PHP:
    delete hPack;
    Пример использования DataPack:

    Передача DataPack в таймере:
    PHP:
    public void OnPluginStart()
    {
        
    DataPack hPack = new DataPack();
        
    hPack.WriteCell(5);
        
    hPack.WriteFloat(7.5);
        
    hPack.WriteString("string");
        
    CreateTimer(5.0Timer_ReadDataPackhPack);
    }

    public 
    Action Timer_ReadDataPack(Handle hTimerHandle hDataPack)
    {
        
    DataPack hPack view_as<DataPack>(hDataPack);    // Методы работают только с типом DataPack, а не Handle
        
    hPack.Reset(); // Возвращаем позицию на 0
        
    int iValue hPack.ReadCell();
        
    LogMessage("Position: %i -> %i"hPack.PositioniValue);
        
    float fValue hPack.ReadFloat();
        
    LogMessage("Position: %i -> %.2f"hPack.PositionfValue);
        
    char szBuffer[256];
        
    hPack.ReadString(szBuffersizeof(szBuffer));
        
    LogMessage("Position: %i -> %s"hPack.PositionszBuffer);
        
    delete hPack;
    }
    Результат:
     
    Последнее редактирование: 3 окт 2016
    AlmazON, Someone, SAZONISCHE и 4 другим нравится это.
  2. AlmazON

    AlmazON деревянный © yand3xmail

    Сообщения:
    4.512
    Симпатии:
    1.963
    Наверное, ниже стоит сразу дополнить примером CreateDataTimer или рассказать про аналогичный флаг таймера - TIMER_DATA_HNDL_CLOSE, когда удалять ничего не нужно.
     
    CrazyHackGUT нравится это.
  3. R1KO

    R1KO Супер-модератор

    Сообщения:
    5.972
    Симпатии:
    2.978
    @AlmazON, я хочу это сделать в след. уроке (он про таймеры), в нем буду ссылаться на этот. Я потому и хотел датапаки написать до таймеров
     
    SAZONISCHE, AlmazON и CrazyHackGUT нравится это.
  4. SAZONISCHE

    SAZONISCHE

    Сообщения:
    116
    Симпатии:
    28
    Очень хорошая идея (может русскоязычные вики замутите?)
     
  5. R1KO

    R1KO Супер-модератор

    Сообщения:
    5.972
    Симпатии:
    2.978
    @SAZONISCHE, я на АМ wiki перевожу когда есть время
     
    Tallanvor и MrBoogidy нравится это.
  6. SAZONISCHE

    SAZONISCHE

    Сообщения:
    116
    Симпатии:
    28
    Респект