[F.A.Q] Оптимизация SendClientMessage / SCMTA
|
|
DECODE |
Дата: Среда, 02.08.2017, 09:15 | Сообщение # 1
|
Coder
Сообщений: 189
Статус: Offline
|
Доброго времени суток, уважаемые посетители данной темы! Хотел бы вам предложить способ, который не многим известен, а именно - оптимизация двух функций SendClientMessage (вывод сообщения какому-либо игроку) и SendClientMessageToAll (вывод сообщения всему серверу). Многие в своем коде используют форматирование с помощью инициализации переменной, с последующим ее форматированием по типу:
Код new string[MAX_PLAYER_NAME + 30]; // Константа с максимальным размером имени игрока + 30 доп. символов format(string, sizeof(string), "[DBG] %s[%d] вывел сообщение %s", PlayerName(playerid), playerid, "TestText"); return SendClientMessage(playerid, -1, string);
Или
Код static const str[] = "[DBG] %s[%d] вывел сообщение %s"; // Константа с заготовленным текстом, автоматический подсчет количества символов. new string[sizeof(str) + MAX_PLAYER_NAME + 10]; // Исходя из размера константы добавляем доп. 10 ячеек для вывода аргументов. format(string, sizeof(string), str, PlayerName(playerid), playerid, "SomeText"); // Форматирование строки. return SendClientMessage(playerid, 0xFFDA03FF, string); // Вывод строки.
Второй вариант, на мой взгляд, удобнее, так как нам нужно меньше заниматься подсчетами, но опять же это не самый лучший вариант. На форуме sa-mp было предложено небольшое решение для оптимизации этих функций. Выглядит это следующим образом:
Код stock SendMes(playerid, fstring[], {Float, _}:...) { static const STATIC_ARGS = 3; new n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL; if (n) { new message[128], arg_start, arg_end; #emit CONST.alt fstring #emit LCTRL 5 #emit ADD #emit STOR.S.pri arg_start #emit LOAD.S.alt n #emit ADD #emit STOR.S.pri arg_end do { #emit LOAD.I #emit PUSH.pri arg_end -= BYTES_PER_CELL; #emit LOAD.S.pri arg_end } while (arg_end > arg_start); // Push the static format parameters. #emit PUSH.S fstring #emit PUSH.C 128 #emit PUSH.ADR message n += BYTES_PER_CELL * 3; #emit PUSH.S n #emit SYSREQ.C format n += BYTES_PER_CELL; #emit LCTRL 4 #emit LOAD.S.alt n #emit ADD #emit SCTRL 4 return SendClientMessage(playerid, 0xFFFFFF, message); } else return SendClientMessage(playerid, 0xFFFFFF, fstring); }
Код stock SendMesAll(fstring[], {Float, _}:...) { static const STATIC_ARGS = 2; new n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL; if (n) { new message[128], arg_start, arg_end; #emit CONST.alt fstring #emit LCTRL 5 #emit ADD #emit STOR.S.pri arg_start #emit LOAD.S.alt n #emit ADD #emit STOR.S.pri arg_end do { #emit LOAD.I #emit PUSH.pri arg_end -= BYTES_PER_CELL; #emit LOAD.S.pri arg_end } while (arg_end > arg_start); // Push the static format parameters. #emit PUSH.S fstring #emit PUSH.C 128 #emit PUSH.ADR message n += BYTES_PER_CELL * 3; #emit PUSH.S n #emit SYSREQ.C format n += BYTES_PER_CELL; #emit LCTRL 4 #emit LOAD.S.alt n #emit ADD #emit SCTRL 4 return SendClientMessageToAll(0xFFFFFF, message); } else return SendClientMessageToAll(0xFFFFFF, fstring); }
Есть один небольшой нюанс, ходят слухи, что может крашнуть мод, но лично я не сталкивался с такими ситуациями.
Есть второй вариант, он заключается в удобстве использования функций, не придется по сто раз проводить форматирование и т.д. Это сделает макрос, который выглядит следующим образом:
Код #define SendFormPlayer(%1,%2,%3) format(st144,144,%3),SendClientMessage(%1,%2,st144) #define SendFormAll(%1,%2) format(st144,144,%2),SendClientMessageToAll(%1,st144)
new str144[144]; // глобальная переменная
stock MyFunction(playerid) // Пробная функция для вывода сообщения. { SendFormAll(0xFFFFFFFF, "Игрок ID: %i ...", playerid); return SendFormPlayer(playerid, 0xFFFFFFFF, "Мой ID: %i", playerid); }
В принципе, вот и все. Если будут какие-то вопросы, то желательно задавать их в Вконтакте.
По первым двум способам - идет использование функций, которые обращаются напрямую к машине, с помощью ASM (Assembler).
Пример использования функций из первого способа:
Код SendMes(playerid, 0xFFDA03AA, "%s[%d] вывел сообщение %s", PlayerName(playerid), playerid, "SomeText"); SendMesAll(0xFFDA03AA, "%s[%d] вывел сообщение для всех %s", PlayerName(playerid), playerid, "SomeText"); // Представим, что кто-то ввел команду для вывода сообщения.
Краткий экскурс по ф-иям:
Код //================================== #endinput // копирует код. #emit // обращение к виртуальной машине. #pragma ctrlchar - Данная директива заменяет escape-символ. (\n) //==================================
p.s В примерах вызвана функция PlayerName(), ее в данной теме нет, это оптимизированная функция определения имени игрока.
► Оптимизация SCM / SMTA (pawn): http://cheat-master.ru/forum/117-706531-1 ► CM Smiles - Mini Chat (v1.0): http://cheat-master.ru/forum/2-706062-1 ► [Evolve-RP] - Баг на деньги (история тестера): http://cheat-master.ru/forum/282-709301-1 ► Накрутка сообщений в ВКонтакте (new): http://cheat-master.ru/forum/199-709369-1
Сообщение отредактировал DECODE - Среда, 02.08.2017, 09:51 |
|
|
|
[CM]MaddyS[CM] |
Дата: Среда, 02.08.2017, 13:54 | Сообщение # 2
|
Боец
Сообщений: 75
Статус: Offline
|
Не плохо, +сиг
|
|
|
|
DECODE |
Дата: Четверг, 03.08.2017, 15:47 | Сообщение # 3
|
Coder
Сообщений: 189
Статус: Offline
|
MbUp.
► Оптимизация SCM / SMTA (pawn): http://cheat-master.ru/forum/117-706531-1 ► CM Smiles - Mini Chat (v1.0): http://cheat-master.ru/forum/2-706062-1 ► [Evolve-RP] - Баг на деньги (история тестера): http://cheat-master.ru/forum/282-709301-1 ► Накрутка сообщений в ВКонтакте (new): http://cheat-master.ru/forum/199-709369-1
|
|
|
|
=) |
Дата: Четверг, 03.08.2017, 19:46 | Сообщение # 4
|
Боец
Сообщений: 271
Статус: Offline
|
Лучший способ.
Цитата DECODE ( ) new string[MAX_PLAYER_NAME + 30]; // Константа с максимальным размером имени игрока + 30 доп. символов format(string, sizeof(string), "[DBG] %s[%d] вывел сообщение %s", PlayerName(playerid), playerid, "TestText"); return SendClientMessage(playerid, -1, string);
Способ для ленивцев.
Цитата DECODE ( ) static const str[] = "[DBG] %s[%d] вывел сообщение %s"; // Константа с заготовленным текстом, автоматический подсчет количества символов. new string[sizeof(str) + MAX_PLAYER_NAME + 10]; // Исходя из размера константы добавляем доп. 10 ячеек для вывода аргументов. format(string, sizeof(string), str, PlayerName(playerid), playerid, "SomeText"); // Форматирование строки. return SendClientMessage(playerid, 0xFFDA03FF, string); // Вывод строки.
SendMes и подобное - сервер ляжет при онлайне. Разумеется ты не заметил этого, хотя мог бы в интернете проверить, что с этой функцией не так и сколько гневных писем, с просьбой показать, как убрать краши - ответы на которые "удалить эту функцию".
Далее, в SendMesAll используется SendClientMessageToAll которая выполняет какое количество итераций? Правильно - которое стоит по умолчанию MAX_PLAYERS в инклюде, а именно = 2048 итерации (вроде так). Что на 1048 больше, чем вообще может быть игроков онлайн.
Для таких целей используется:
Код stock SendMessageAll(color, text[]) { foreach(i:Player) { if(!PLayer[i][Online]) continue; // у кого какая проверка на авторизацию, если вообще нужна else if(!PLayer[i][gChat]) continue; // у кого какая проверка на отображение чата, если вообще нужна
SendClientMessage(i, color, text); } return 1; }
Цитата DECODE ( ) #define SendFormPlayer(%1,%2,%3) format(st144,144,%3),SendClientMessage(%1,%2,st144) #define SendFormAll(%1,%2) format(st144,144,%2),SendClientMessageToAll(%1,st144)
new str144[144]; // глобальная переменная
Ты используешь переменную для хранения 144-рех символов, но забываешь, что всегда должна быть ячейка под конец строки '/0'. То есть str144[144] должен быть str145[145].
Вот и выходит, что ты вводишь пользователей в заблуждение, оперируя дурными данными.
Сообщение отредактировал =) - Четверг, 03.08.2017, 20:02 |
|
|
|
DECODE |
Дата: Четверг, 03.08.2017, 23:14 | Сообщение # 5
|
Coder
Сообщений: 189
Статус: Offline
|
Цитата =) ( ) Ты используешь переменную для хранения 144-рех символов, но забываешь, что всегда должна быть ячейка под конец строки '/0'. То есть str144[144] должен быть str145[145].
Вот и выходит, что ты вводишь пользователей в заблуждение, оперируя дурными данными. Ладно, победил. Тут даже спорить не буду, давно отошел от разработок pawn, голова совсем не думает. О способах с функциями - предупредил сразу, насчет строки - тоже просчет, и, да, немного стыдно. Пожалуй, нужно завязывать с этой сферой.
► Оптимизация SCM / SMTA (pawn): http://cheat-master.ru/forum/117-706531-1 ► CM Smiles - Mini Chat (v1.0): http://cheat-master.ru/forum/2-706062-1 ► [Evolve-RP] - Баг на деньги (история тестера): http://cheat-master.ru/forum/282-709301-1 ► Накрутка сообщений в ВКонтакте (new): http://cheat-master.ru/forum/199-709369-1
|
|
|
|
=) |
Дата: Пятница, 04.08.2017, 09:16 | Сообщение # 6
|
Боец
Сообщений: 271
Статус: Offline
|
Цитата DECODE ( ) Ладно, победил. Тут даже спорить не буду, давно отошел от разработок pawn, голова совсем не думает. О способах с функциями - предупредил сразу, насчет строки - тоже просчет, и, да, немного стыдно. Пожалуй, нужно завязывать с этой сферой.
Да я с тобой не воевал. Такие мелочи легко запомнить и дополнить урок. Любой чего-то да не знает. А вот сдаваться при первых трудностях - вот это постыдно. Хотя, в павно конечно нет, ведь кому он нужен. Бесполезная трата времени.
Сообщение отредактировал =) - Пятница, 04.08.2017, 09:17 |
|
|
|