Склад функций SourcePawn

Kruzya

Raspberry Pi 4
Команда форума
Меценат
Сообщения
10,550
Реакции
8,726
Цикл по игрокам
Простейший define для обработки всех игроков на сервере.
C-подобный:
#define LoopPlayers(%0) for (int %0 = MaxClients; %0 != 0; --%0) if (IsClientInGame(%0))
Пример использования из реального плагина (кое-что убрал):
C-подобный:
public void OnGroupsInfoLoaded(Database hDB, DBResultSet hResults, const char[] szError, any data) {
  if (szError[0]) {
    LogError("[XenForo] Database failure when fetching groups information: %s", szError);
    return;
  }

  // ...

  if (g_bLate)
    LoopPlayers(iClient)
      if (!IsFakeClient(iClient) && IsClientAuthorized(iClient))
        LookupUserPermissions(iClient);
}
 
  • Мне нравится
Реакции: NaN

Kruzya

Raspberry Pi 4
Команда форума
Меценат
Сообщения
10,550
Реакции
8,726
Преобразование строкового сокращённого времени в секунды
На основе кода F@nt0M с одного форума по CS 1.6 сделал аналогичный конвертер строкового простейшего представления времени (1y3m, 1y2m4d5i6 и т.д.) - в секундное.
C-подобный:
stock int ParseTime(const char[] szStr) {
  static int  iTime[]   = {60,  3600, 86400, 2592000, 31104000};
  static char szTime[]  = "ihdmy";

  int iDummy, iResult;
  int iPos, iTPos;
  char cData;

  while (szStr[iPos] != EOS) {
    cData = szStr[iPos++];

    if (cData >= '0' && cData <= '9') {
      iDummy = (iDummy * 10) + (cData - '0');
      continue;
    }

    for (iTPos = 0; iTPos < sizeof(iTime); ++iTPos) {
      if (cData == szTime[iTPos]) {
        iResult += iDummy * iTime[iTPos];
        iDummy = 0;
        break;
      }
    }
  }

  iResult += iDummy;
  return iResult;
}

1593621107187.png
 
  • Мне нравится
Реакции: NaN

Grey83

Ленивая и невнимательная жопа
Сообщения
4,828
Реакции
2,837
Появилась у меня проблема с выводом в KeyHintText текста моего плагина в CSS, так чтобы другой плагин не перебивал сообщение от моего, но при этом и мой не перебивал сообщения других плагинов.
В общем решил объединить тексты от двух плагинов (точнее дописать мой текст в KeyHintText другого).

Вот такое решение получилось (это не кусок кода плагина, так тестовый код):
C-подобный:
#include <usermessages>

public OnPluginStart()
{
    // Ловим сообщения в KeyHintText от других плагинов
    HookUserMessage(GetUserMessageId("KeyHintText"), HookKeyHintText, true);
}

public Action HookKeyHintText(UserMsg msg_id, BfRead msg, const int[] players, int playersNum, bool reliable, bool init)
{
    static char txt[1024];
    BfReadByte(msg);    // Этот байт нам попросту не нужен
    BfReadString(msg, txt, sizeof(txt)); // Получаем текст сообщения

    // Дописываем свой текст, в данном случае ник игрока, которому предназначалось сообщение
    Format(txt, sizeof(txt), "%N\n%s", players[0], txt);
    // Записываем в датапак необходимые нам данные и отправляем их в каллбэк RequestFrame()
    // Это необходимор потому, что в одно и тоже время можно отсылать только одно сообщение
    DataPack data = new DataPack();
    RequestFrame(RequestFrame_Callback, data);
    data.WriteString(txt);
    data.WriteCell(players[0]);

    // Блочим вывод сообщения плагина
    return Plugin_Handled;
}

public void RequestFrame_Callback(DataPack data)
{
    // Получаем сохранённую инфу в DataPack
    ResetPack(data);
    static char txt[1024];
    data.ReadString(txt, sizeof(txt));
    int client = data.ReadCell();
    delete data;

    // И снова посылаем сообщение адресату, но уже дополненное нами
    // Флаг USERMSG_BLOCKHOOKS необходим чтобы наш плагин не хукался самим собой (правда и другие это не смогут сделать тоже)
    Handle msg = StartMessageOne("KeyHintText", client, USERMSG_BLOCKHOOKS);
    BfWriteByte(msg, 1);
    BfWriteString(msg, txt);
    EndMessage();
}
 
Последнее редактирование:
  • Мне нравится
Реакции: JDW

nyood

e-val
Сообщения
1,119
Реакции
750
Надстройка над strlen, подсчет количества символов по факту, игнорируя байтовую принадлежность:
C-подобный:
stock int numlts_stock(const char[] szSomeString)
{
    int a;
    
    for(int i, b; i < strlen(szSomeString); i++)
    {
        if((b = IsCharMB(szSomeString[i])))
            i += b-1;

        a++;
    }

    return a;
}
 

_wS_

Участник
Сообщения
335
Реакции
676
Я только сегодня осознал что SM всегда сравнивает int числа как signed int. Максимальное значение 2147483647 (19.01.2038). Если вы, например, вытащили из sql таблицы timestamp время или другое unsigned int, и оно превысило int лимит, и вы сравниваете это число с каким-то числом, то наступает полнейший фейл, например 2147483649 > 0 возвращает false.. Поэтому можете использовать эту функцию (или если вы знаете более оптимальный вариант, поделитесь).

C++:
// -1 (a < b), 0 (a == b), 1 (a > b)
int uintcmp(int a, int b)
{
    if (a == b) {
        return 0;
    }
    char a_[12], b_[12];
    FormatEx(a_, sizeof(a_), "%u", a);
    FormatEx(b_, sizeof(b_), "%u", b);
    int a_size = strlen(a_), b_size = strlen(b_);
    if (a_size > b_size) {
        return 1;
    }
    if (a_size < b_size) {
        return -1;
    }
    int i = -1;
    while (++i < a_size) {
        if (a_[i] > b_[i]) {
            return 1;
        }
        if (a_[i] < b_[i]) {
            return -1;
        }
    }
    return 0; // wtf
}

public void OnPluginStart()
{
    // max int 2147483647
    int a = 2147483649;
    int b = 1000;
    PrintToServer("%u > %u = %s", a, b, a > b ? "yes" : "no");
    PrintToServer("%u > %u = %s", a, b, uintcmp(a, b) == 1 ? "yes" : "no");
    
    // Результат:
    // 2147483649 > 1000 = no
    // 2147483649 > 1000 = yes
}
Сообщения автоматически склеены:

Есть еще такая проблема: SQL_FetchInt не знает что такое unsigned int.
У меня в таблице значение 4294967294 и вот что происходит при его извлечении:

C++:
char s1[12], s2[12];

int i = results.FetchInt(1);
FormatEx(s1, sizeof(s1), "%u", i);

results.FetchString(1, s2, sizeof(s2));
i = StringToInt(s2);
FormatEx(s2, sizeof(s2), "%u", i);

PrintToServer("%s\n%s", s1, s2);

// Результат:

// 2147483647 (omg)
// 4294967294

Спешат на помощь другие функции:

C++:
#define UINT_SIZE 12

// Преобразовать unsigned int в строку (IntToString не может) (return: Number of cells written)
stock int UIntToString(int value, char[] s, int size) {
    return FormatEx(s, size, "%u", value);
}

// Извлечь из поля unsigned int (SQL_FetchInt не может)
stock int SQL_FetchUInt(Handle results, int field, DBResult &result=DBVal_Error, int error=0)
{
    char s[UINT_SIZE];
    return SQL_FetchString(results, field, s, sizeof(s), result) && result == DBVal_Data ? StringToInt(s) : error;
}
 
Последнее редактирование:
Сверху