Всем привет.
Как вы могли догадаться по названию темы, в ней будут обсуждаться командные процессоры.
Но я не собираюсь советовать вам тот или иной командный движок - вместо этого я приведу несколько фактов и оставлю возможность выбора вам.
Итак, начнём.
Одной из основных проблем в обработке команд является линейная зависимость времени отклика от названия команды или её расположения в коде.
Что представляет из себя эта зависимость:
- Без командного процессора производятся лишние вызовы strcmp, чтобы найти нужную команду.
Пример:
Самое малое время отклика будет у команды "/command1", т.к. она реализована в OnPlayerCommandText самой первой и при её вызове будет совершён всего 1 вызов функции strcmp.PHP код:
public OnPlayerCommandText(playerid, cmdtext[])
{
if (0 == strcmp(cmdtext, "/command1"))
{
return SendClientMessage(playerid, -1, "Вызвана 1-я команда.");
}
if (0 == strcmp(cmdtext, "/command2"))
{
return SendClientMessage(playerid, -1, "Вызвана 2-я команда.");
}
if (0 == strcmp(cmdtext, "/command3"))
{
return SendClientMessage(playerid, -1, "Вызвана 3-я команда.");
}
return SendClientMessage(playerid, -1, "Ошибка: Неизвестная команда.");
}
В то же время, команда "/command3" находится в самом невыгодном положении, т.к. при её вызове строка в cmdtext будет сравниваться сначала с "/command1" и "/command2", и только потом с "/command3", т.е. произойдут 2 лишних вызова strcmp.
В итоге чем больше команд находится перед вызванной командой, тем больше будет "холостых" срабатываний strcmp и тем больше времени уйдёт на поиск. Это и есть линейная зависимость времени отклика команды от её расположения в OPCT.
- Во многих командных движках наподобие ZCMD тоже есть линейная зависимость, но только от названия команды.
Команды в них реализуются в виде public-функций. В скомпилированном скрипте (*.amx) названия таких функций сохраняются в таблице экспортируемых функций, чтобы их можно было найти и вызвать извне (т.е. со стороны сервера, а не только из кода на Pawn).
Пример:
При раскрытии макроса "CMD:" к названию public-функции добавляется префикс "cmd_". Например, для "CMD:abc" функция будет называться "cmd_abc".PHP код:
CMD:abc(playerid, params[])
{
return SendClientMessage(playerid, -1, "abc");
}
CMD:def(playerid, params[])
{
return SendClientMessage(playerid, -1, "def");
}
CMD:ghi(playerid, params[])
{
return SendClientMessage(playerid, -1, "ghi");
}
CMD:jkl(playerid, params[])
{
return SendClientMessage(playerid, -1, "jkl");
}
Без префикса командный процессор мог бы вызвать любую public-функцию. Например, любой игрок мог бы ввести "/OnGameModeInit", инициировать "перезагрузку" сервера - загрузку домов, бизнесов и всего прочего, без сохранения того, что было у игроков до перезагрузки.
Записи в таблице экспортируемых функций будут располагаться в алфавитном порядке:
Чтобы вызвать функцию на Pawn по её имени, нужно сначала найти её ID, т.е. её порядковый номер в таблице функций.Код:abc
def
ghi
jkl
Эта задача осуществляется с помощью amx_FindNative, если для обработки команд используется плагин, или funcidx на стороне Pawn (она сама вызывает amx_FindNative).
Функция amx_FindNative производит линейный поиск по таблице экспортируемых функций, поочерёдно сравнивая указанное имя с каждым именем в таблице, пока не найдёт совпадение.
При таком поиске название abc попадётся самым первым, а для jkl будут совершены 3 лишних сравнения с предыдущими именами в таблице.
Как результат, время отклика при такой схеме зависит от названия самой команды.
В теории наличие линейной зависимости во времени отклика открывает для злоумышленников вектор атаки: флудить вызовом команды, которая либо самая последняя по алфавиту (например, что-нибудь на букву Z), либо реализована самой последней в OnPlayerCommandText (это можно узнать из слитых исходников или исходников паблик-мода, на котором основан мод сервера).
Если на сервере достаточно много команд и атакующий удачно подобрал команду для флуда, он сможет спровоцировать максимальное использование ресурсов и, возможно, отключение сервера хостером, чтобы не влиять на работу других серверов, находящихся на той же машине.
В DC_CMD для обработки команд используется хеш-таблица.
Во время запуска сервера плагин просматривает таблицу public-функций и для тех функций, названия которых начинаются с "cmd_", вычисляет из названия хеш-сумму, находит ID функции и полученные пары "хеш-ID" сохраняет в хеш-таблице.
При вводе команды от названия вычисляется хеш и по нему в таблице находится ID соответствующей public-функции. При такой схеме отсутствует линейная зависимость от названия функции, т.к. время поиска по хеш-таблице примерно равно для каждого элемента.
По такому же принципу работает плагин Pawn.CMD и движок y_commands.
Значительным недостатком y_commands является то, что он использует несколько других инклудов из YSI, состоящих из грязных хаков на основе багов Pawn 3.0, не говоря уже о реализации хеш-таблицы в YSI: вместо динамической аллокации памяти под её элементы используется очень большой массив, который всё время занимает место в памяти сервера. И хотя память не является особой проблемой, используемые в YSI практики только поощряют расточительство и использование багов вместо того, чтобы сделать адекватную реализацию через плагин.
Про минусы Pawn.CMD можно прочесть здесь. Также есть информация, что под Linux этот плагин приводит к падению сервера с JIT, но эта информация пока что не подтверждена (буду очень благодарен, если кто-нибудь найдёт время, чтобы её подтвердить/опровергнуть).
Среди преимуществ Pawn.CMD и y_commands можно отметить поддержку отдельных реализаций команд для справки об аргументах команды и для разных групп игроков, но без этого синтаксического сахара можно легко обойтись, больше никаких проблем они не решают.
Как я уже сказал ранее, я не буду навязывать вам выбор. Это было бы неэтично с моей стороны, т.к. я, как разработчик DC_CMD, могу быть заинтересованным лицом (хоть я уже и несколькько лет практически не притрагивался к исходникам плагина).
Моей задачей в этой статье было всего лишь привести факты, т.к. я не видел, чтобы о них хоть где-то упоминали ранее.
Выбирайте с умом. Или без. Всё в ваших руках.
Статью подготовил: Daniel_Cortez
Специально для Pro-Pawn.ruКопирование данной статьи на других ресурсах без разрешения автора запрещено!