[SourcePawn] Урок 5 - DataPack

Zanoza

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

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

Рассмотрим их подробнее:
  • Методы для работы с DataPack
    • DataPack - Создает объект типа DataPack
    • Код:
      DataPack hPack = new DataPack();
    • Reset - Сбрасывает позицию считывания с DataPack, чтобы начать считывание/запись сначала
      Код:
      hPack.Reset();    // Сбросит позицию считывания
      hPack.Reset(true);    // Сбросит позицию считывания и очистит DataPack
      • IsReadable - Возвращает логическое значение возможно ли считать данные из DataPack
        Код:
        int iValue = 0;
        if(hPack.IsReadable(4)) // В DataPack еще есть значение для считывания
        {
        iValue = hPack.ReadCell();
        }
      • Position - Свойство, которое позволяет указывать/получать позицию для считывания.
        При этом позиция определяется количеством байт записанных данных:
        Код:
        // Напишем простой плагин:
        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 байт + 1 байт + 4 (размер)
        // Сейчас позиция = 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.Position, iValue);
        float fValue = hPack.ReadFloat();
        LogMessage("Position: %i -> %.2f", hPack.Position, fValue);
        char szBuffer[256];
        hPack.ReadString(szBuffer, sizeof(szBuffer));
        LogMessage("Position: %i -> %s", hPack.Position, szBuffer);
        iValue = hPack.ReadCell();
        LogMessage("Position: %i -> %i", hPack.Position, iValue);
        
        delete hPack;
        }
        Результат:
        Код:
        Position: 0
        Position: 9
        Position: 18
        Position: 30
        Position: 39
        // Тут сбросили позицию на 0 и начали считывать
        Position: 0
        Position: 9 -> 5
        Position: 18 -> 7.50
        Position: 30 -> string
        Position: 39 -> 1
        Визуально выглядит так:
        Код:
        Код:
        
        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-х байтовое значение)


          Код:
          hPack.WriteCell(5);
        • WriteFloat - Записывает в DataPack число с плавающей точкой (дробное)
          Код:
          hPack.WriteFloat(7.3);
        • WriteString - Записывает в DataPack строку


          Код:
          hPack.WriteString("моя строка");
        • WriteFunction - Записывает в DataPack указатель на функцию
          Код:
          function MyFunc = GetFunctionByName(null, "MyFunction");
          if(MyFunc != INVALID_FUNCTION)
          {
          hPack.WriteFunction(MyFunc);
          }
      • Методы для чтения из DataPack
        • ReadCell - Получает из DataPack ячейку
          Код:
          int iValue = hPack.ReadCell();
        • ReadFloat - Получает из DataPack число с плавающей точкой (дробное)
          Код:
          float fValue = hPack.ReadFloat();
        • ReadString - Получает из DataPack строку
          Код:
          char szBuffer[256];
          hPack.ReadString(szBuffer, sizeof(szBuffer));
        • ReadFunction - Полуачет из DataPack указатель на функцию
          Код:
          function MyFunc = hPack.ReadFunction(MyFunc);
    • Когда DataPack больше не нужен его обязательно нужно удалить:
      Код:
      delete hPack;
      Пример использования DataPack:

      Передача DataPack в таймере:
      Код:
      public void OnPluginStart()
      {
      DataPack hPack = new DataPack();
      hPack.WriteCell(5);
      hPack.WriteFloat(7.5);
      hPack.WriteString("string");
      CreateTimer(5.0, Timer_ReadDataPack, hPack);
      }
      
      public Action Timer_ReadDataPack(Handle hTimer, Handle hDataPack)
      {
      DataPack hPack = view_as<DataPack>(hDataPack); // Методы работают только с типом DataPack, а не Handle
      hPack.Reset(); // Возвращаем позицию на 0
      int iValue = hPack.ReadCell();
      LogMessage("Position: %i -> %i", hPack.Position, iValue);
      float fValue = hPack.ReadFloat();
      LogMessage("Position: %i -> %.2f", hPack.Position, fValue);
      char szBuffer[256];
      hPack.ReadString(szBuffer, sizeof(szBuffer));
      LogMessage("Position: %i -> %s", hPack.Position, szBuffer);
      delete hPack;
      }
      Результат:
      Код:
      Position: 9 -> 5
      Position: 18 -> 7.50
      Position: 30 -> string

 
Верх