Русское сообщество по скриптингу

Отладка плагинов AMX Mod X

Статьи или фрагменты кода для новичков и уже опытных скриптеров по AMXX.

Модератор: Chuvi

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только обучающему материалу по AMX Mod X.

Отладка плагинов AMX Mod X

Сообщение DJ_WEST » 01 сен 2009, 09:17

Отладка — этап разработки плагина, на котором обнаруживают, локализуют и устраняют ошибки. Чтобы понять, где возникла ошибка, приходится :
  • узнавать текущие значения переменных;
  • и выяснять, по какому пути выполнялась программа.

В AMX Mod X уже встроен отладчик, которого нам вполне хватит для решения наших проблем. Значение команды amx_debug должно быть 1. Режим отладки для определенного плагина включается следующим способом: в файле ../addons/amxmodx/configs/plugins.ini напротив необходимого плагина прописываем слово debug, например:
admin.amxx debug

После этого меняем карту на сервере или перезапускаем сервер (команда restart). Теперь в логах AMXX (../addons/amxmodx/logs) мы сможем подробно узнать на каком этапе возникает ошибка в работе плагина. Логи с ошибками в директории logs называются error_X.txt, где X - это дата, когда был создан данный файл.
Допустим у нас есть плагин следующего содержания, который при входе игрока на сервер записывает его имя в глобальную переменную g_Names. Также у нас зарегистрирована консольная команда amx_names_reset для обнуления этой переменной через цикл с фиксированным количеством шагов. Данный код скомпилировался без ошибок, но это еще не значит, что он будет работать, как ему полагается. После запуска данного плагина, а также использования консольной команды amx_names_reset в директории logs мы обнаружили лог с ошибками.

debug.sma:
Код: Выделить всё
#include <amxmodx>

#define PLUGIN "Example Debug Plugin"
#define VERSION "1.0"
#define AUTHOR "DJ_WEST"

new g_Names[33][32]

public plugin_init() 
{
    register_plugin(PLUGIN, VERSION, AUTHOR)
    register_concmd("amx_names_reset", "Names_Reset")
}

public client_putinserver(id)
{
    new s_Name[32]
    
    get_user_name
(id, s_Name, charsmax(s_Name))
    
    g_Names
[id] = s_Name
    
    server_print
("%s entered the game", s_Name)
}

public Names_Reset(id)
{
    for (new i = 1; i <= 33; i++)
        g_Names[i] = ""
        
    server_print
("Names reset")
}
 


Пример текста отладки из лога error_20090901.log:
L 09/01/2009 - 08:46:52: [AMXX] Displaying debug trace (plugin "debug.amxx")
L 09/01/2009 - 08:46:52: [AMXX] Run time error 4: index out of bounds
L 09/01/2009 - 08:46:52: [AMXX] [0] debug.sma::Names_Reset (line 29)

Если разобрать данный текст, то мы видим, что сначала идет дата и время возникновения ошибки, соотвественно и ее записи в лог-файл. По данной строчке Displaying debug trace (plugin "debug.amxx") мы можем понять, что идет отладка плагина debug.amxx, в котором собственно и произошла ошибка. В следующей строчке мы видим описание ошибки Run time error 4: index out of bounds, если перевести ее на русский язык, то она означает, что "какой-то индекс вышел за пределы чего-то". Вот как раз следующая строчка нам помогает найти проблему, а именно она говорит нам, что в debug.sma в строке 29 функции Names_Reset произошла данная ошибка. Ищем в нашем debug.sma 29 строчку, это:
Код: Выделить всё
g_Names[i] = "" 

Следовательно индекс в данном случае, о котором шла речь в описании ошибки - это i, а пределы за которые он вышел - это размерность массива g_Names. Теперь смотрим объявление нашей переменной:
Код: Выделить всё
new g_Names[33][32] 

Видим, что у нас двумерный массив размерностью 33 x 32. 33 (33 - 1 = 32) - это максимальное количество игроков на сервере. Именно 33, потому что индексация массива начинается с 0, но id игроков начинается с 1 до 32, следовательно массив должен быть на 1 размер выше. А 32 - максимальная длина, в нашем случае для имени игрока.

Теперь смотрим наш цикл:
Код: Выделить всё

    for 
(new i = 1; i <= 33; i++)
        g_Names[i] = ""
 

Видим, что цикл выполняется от i = 1 до i <= 33 при этом i используется в g_Names. Но если вспомнить размерность массива g_Names, то понимаем, что когда i дойдет до 33, то это будет за пределами g_Names, следовательно нам нужно исправить код на:
Код: Выделить всё

    for 
(new i = 1; i <= 32; i++)
        g_Names[i] = ""
 


Заново компилируем плагин, проверяем его снова и видим, что все работает замечательно. Помните, что это лишь пример отладки. На самом деле ошибки могут быть другими, а если плагин еще и большой, то поиск ошибки может продлится гораздо дольше.
Не пишите мне в ЛС: если вам нужна помощь на бесплатной основе. Любые вопросы на форум.
Аватара пользователя
DJ_WEST
Администратор
 
Сообщения: 3747
Зарегистрирован: 22 авг 2009, 00:38
Благодарил (а): 48 раз.
Поблагодарили: 2164 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Counter-Strike: Source
Left 4 Dead
Left 4 Dead 2

Re: Отладка плагинов AMX Mod X

Сообщение Zefir » 08 дек 2009, 16:12

Вот ключи компилятора:
Код: Выделить всё

Welcome to the AMX Mod X 1.8.1-300 Compiler.
Copyright (c) 1997-2006 ITB CompuPhase, AMX Mod X Team

Options:
        -A<num>  alignment in bytes of the data segment and the stack
        -a       output assembler code
        -C[+/-]  compact encoding for output file (default=-)
        -c<name> codepage name or number; e.g. 1252 for Windows Latin-1
        -Dpath   active directory path
        -d0      no symbolic information, no run-time checks
        -d1      [default] run-time checks, no symbolic information
        -d2      full debug information and dynamic checking
        -d3      full debug information, dynamic checking, no optimization
        -e<name> set name of error file (quiet compile)
        -H<hwnd> window handle to send a notification message on finish
        -i<name> path for include files
        -l       create list file (preprocess only)
        -o<name> set base name of output file
        -p<name> set name of "prefix" file
        -r[name] write cross reference report to console or to specified file

Как видно по умолчанию идет -d1. Потому как в compile нет ключей определяющих отладочную инфу. Если прописать параметр -d3, информации при отладке можно получить немного больше.

Если же указать -d0, то отладочной инфы не будет. Это усложнит как дизассемблирование, так и сделает невозможной отладку. Ибо если вы ее включите в настройках или добавите debug при запуске, то плагин запущен вообще не будет в отладочном режиме.

Соответственно отличаются и размеры плагинов с этими опциями. Чем больше отладочной инфы, тем "тяжелее" плагин.
Чтобы правильно задать вопрос, нужно знать более половины ответа...
Cerberus - замена amxbans и многому другому
Аватара пользователя
Zefir
 
Сообщения: 21
Зарегистрирован: 31 авг 2009, 21:06
Откуда: Kiev
Благодарил (а): 2 раз.
Поблагодарили: 13 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6

Re: Отладка плагинов AMX Mod X

Сообщение Lt.RAT » 08 дек 2009, 23:01

Доверяй, но проверяй :)
Как тут написанно, стандартный ключ идет d1, но отчего-то дизассемблеры могут просматривать symbolic information... Проведем маленький эксперимент - скомпилируем плагин стандартным "compile.exe" и собственным с разными ключами, а потом распакуем из полученных amxx файлов 32 битную часть (можно и 64, но смысла нет)...

Файлы во вложении смотреть через ХексЭдитор - кто захочет посмотреть как оно на самом деле там все выглядит :)

Видно, что "kz_scout2 Compiler.amx" и "kz_scout2 D2.amx" совпадают, поскольку "compile.exe" использует только ключ -o делаем вывод, что на самом деле дефолтным ключем является -d2, а не -d1 как написанно :)

Хотя можно внести дополнительный критерий: d2 добавляет symbolic information - в которую входит список файлов используемых при компиляции (в "kz_scout2 Compiler.amx" видно полный путь до исходника при компиляции :D ) "Строк" с их позициями, "Символов" - названий функций, переменных и их область видимости ипр, Тэгов и несовсем понятной пока мне фигни типа полей "Automat" и "State"... все это записано в самом конце файла, поэтому довольно заметно при сравнении файлов :)
Согласно этой инфы было откомпилено:
1 файл, 8 строк, 4 переменных (MYSTATIC, id, givescout, plugin_init), 15 тэгов (Float, bool, any итп), 1 "Automat", 0 "State".

Видать кто-то редактировал компилятор и лажанулся :) (Можно даже отписать им об этом "баге")

ЗЫ кстати описания опций компилятора есть в Вы должны зарегистрироваться, чтобы видеть ссылки. и там тоже можно отметить, что дефолтный ключ на самом деле другой.
Аватара пользователя
Lt.RAT
 
Сообщения: 313
Зарегистрирован: 30 сен 2009, 01:44
Благодарил (а): 4 раз.
Поблагодарили: 149 раз.
Языки программирования: Counter-Strike 1.6

Re: Отладка плагинов AMX Mod X

Сообщение navigator » 04 фев 2011, 03:14

Код: Выделить всё
L 02/04/2011 - 04:00:48: Start of error session.
L 02/04/2011 - 04:00:48: Info (map "fy_pool_day") (file "addons/amxmodx/logs/error_20110204.log")
L 02/04/2011 - 04:00:48: [AMXX] Run time error 19 (plugin "lacmenu.amxx") - debug not enabled!
L 02/04/2011 - 04:00:48: [AMXX] Function not found: (null)

компилировал lacmenu.sma по умолчанию перетаскиванием файла
amx_debag 1
в plugins.ini
Код: Выделить всё
lacmenu.amxx debug

Чёт не могу сообразить что ещё упустил, подскажите как по точнее узнать где ошибка?
Аватара пользователя
navigator
 
Сообщения: 48
Зарегистрирован: 03 фев 2011, 21:35
Откуда: Уфа.
Благодарил (а): 12 раз.
Поблагодарили: 2 раз.
Опыт программирования: Меньше месяца
Языки программирования: Counter-Strike 1.6

Re: Отладка плагинов AMX Mod X

Сообщение felicita » 04 фев 2011, 10:57

Выложи lacmenu.sma своё.
Аватара пользователя
felicita
 
Сообщения: 92
Зарегистрирован: 09 янв 2011, 03:04
Благодарил (а): 4 раз.
Поблагодарили: 28 раз.
Опыт программирования: Около года
Языки программирования: Counter-Strike 1.6

Re: Отладка плагинов AMX Mod X

Сообщение navigator » 04 фев 2011, 12:49

Вот
Код: Выделить всё
/* AMX Mod X
*/

#include <amxmodx>
#include <amxmisc>

/** skip autoloading since it's optional */
#define AMXMODX_NOAUTOLOAD
#include <cstrike>

new g_menuPosition[33]
new g_menuPlayers[33][32]
new g_menuPlayersNum[33]
new g_menuOption[33]

new g_menuSelect[33][254]
new g_menuSelectNum[33]

#define MAX_CLCMDS 24

new g_clcmdName[MAX_CLCMDS][32]
new g_clcmdCmd[MAX_CLCMDS][254]
new g_clcmdMisc[MAX_CLCMDS][2]
new g_clcmdNum

new g_coloredMenus





public plugin_natives()
{
   set_module_filter("module_filter")
   set_native_filter("native_filter")
}

public plugin_init()
{
   register_plugin("Players Menu", AMXX_VERSION_STR, "AMXX Dev Team")
   register_dictionary("common.txt")
   register_dictionary("admincmd.txt")
   register_dictionary("plmenu.txt")


   register_clcmd("amx_laccmdmenu", "cmdlaccmdmenu", ADMIN_KICK, "- displays client cmds menu")


   register_menucmd(register_menuid("Client Cmds Menu"), 1023, "actionlaccmdmenu")
   
   


   g_coloredMenus = colored_menus()

   new clcmds_ini_file[254]
   get_configsdir(clcmds_ini_file, 253)
   format(clcmds_ini_file, 253, "%s/clcmdslac.ini", clcmds_ini_file)
   load_settings(clcmds_ini_file)

   
}





/* Client cmds menu */

public actionlaccmdmenu(id, key)
{
   switch (key)
   {
      case 7:
      {
         ++g_menuOption[id]
         g_menuOption[id] %= g_menuSelectNum[id]
         displaylaccmdmenu(id, g_menuPosition[id])
      }
      case 8: displaylaccmdmenu(id, ++g_menuPosition[id])
      case 9: displaylaccmdmenu(id, --g_menuPosition[id])
      default:
      {
         new player = g_menuPlayers[id][g_menuPosition[id] * 7 + key]
         new flags = g_clcmdMisc[g_menuSelect[id][g_menuOption[id]]][1]
         
         if (is_user_connected(player))
         {
            new command[512], authid[32], name[32], userid[32]
            
            copy(command, charsmax(command), g_clcmdCmd[g_menuSelect[id][g_menuOption[id]]])
            get_user_authid(player, authid, 31)
            get_user_name(player, name, 31)
            num_to_str(get_user_userid(player), userid, 31)
            
            replace(command, charsmax(command), "%userid%", userid)
            replace(command, charsmax(command), "%authid%", authid)
            replace(command, charsmax(command), "%name%", name)
            
            if (flags & 1)
            {
               server_cmd("%s", command)
               server_exec()
            } else if (flags & 2)
               client_cmd(id, "%s", command)
            else if (flags & 4)
               client_cmd(player, "%s", command)
         }
         
         if (flags & 8)
            displaylaccmdmenu(id, g_menuPosition[id])
      }
   }
   
   return PLUGIN_HANDLED
}

displaylaccmdmenu(id, pos)
{
   if (pos < 0)
      return

   get_players(g_menuPlayers[id], g_menuPlayersNum[id])

   new menuBody[512]
   new b = 0
   new i
   new name[32]
   new start = pos * 7

   if (start >= g_menuPlayersNum[id])
      start = pos = g_menuPosition[id] = 0

   new len = format(menuBody, 511, g_coloredMenus ? "\y%L\R%d/%d^n\w^n" : "%L %d/%d^n^n", id, "CL_CMD_MENU", pos + 1, (g_menuPlayersNum[id] / 7 + ((g_menuPlayersNum[id] % 7) ? 1 : 0)))
   new end = start + 7
   new keys = MENU_KEY_0|MENU_KEY_8

   if (end > g_menuPlayersNum[id])
      end = g_menuPlayersNum[id]

   for (new a = start; a < end; ++a)
   {
      i = g_menuPlayers[id][a]
      get_user_name(i, name, 31)

      if (!g_menuSelectNum[id] || (access(i, ADMIN_IMMUNITY) && i != id))
      {
         ++b
         
         if (g_coloredMenus)
            len += format(menuBody[len], 511-len, "\d%d. %s^n\w", b, name)
         else
            len += format(menuBody[len], 511-len, "#. %s^n", name)      
      } else {
         keys |= (1<<b)
            
         if (is_user_admin(i))
            len += format(menuBody[len], 511-len, g_coloredMenus ? "%d. %s \r*^n\w" : "%d. %s *^n", ++b, name)
         else
            len += format(menuBody[len], 511-len, "%d. %s^n", ++b, name)
      }
   }

   if (g_menuSelectNum[id])
      len += format(menuBody[len], 511-len, "^n8. %s^n", g_clcmdName[g_menuSelect[id][g_menuOption[id]]])
   else
      len += format(menuBody[len], 511-len, "^n8. %L^n", id, "NO_CMDS")

   if (end != g_menuPlayersNum[id])
   {
      format(menuBody[len], 511-len, "^n9. %L...^n0. %L", id, "MORE", id, pos ? "BACK" : "EXIT")
      keys |= MENU_KEY_9
   }
   else
      format(menuBody[len], 511-len, "^n0. %L", id, pos ? "BACK" : "EXIT")

   show_menu(id, keys, menuBody, -1, "Client Cmds Menu")
}

public cmdlaccmdmenu(id, level, cid)
{
   if (!cmd_access(id, level, cid, 1))
      return PLUGIN_HANDLED

   g_menuSelectNum[id] = 0

   for (new a = 0; a < g_clcmdNum; ++a)
      if (access(id, g_clcmdMisc[a][0]))
         g_menuSelect[id][g_menuSelectNum[id]++] = a

   g_menuOption[id] = 0

   displaylaccmdmenu(id, g_menuPosition[id] = 0)

   return PLUGIN_HANDLED
}

load_settings(szFilename[])
{
   if (!file_exists(szFilename))
      return 0

   new text[256], szFlags[32], szAccess[32]
   new a, pos = 0

   while (g_clcmdNum < MAX_CLCMDS && read_file(szFilename, pos++, text, 255, a))
   {
      if (text[0] == ';') continue

      if (parse(text, g_clcmdName[g_clcmdNum], 31, g_clcmdCmd[g_clcmdNum], 253, szFlags, 31, szAccess, 31) > 3)
      {
         while (replace(g_clcmdCmd[g_clcmdNum], 253, "\'", "^""))
         {
            // do nothing
         }

         g_clcmdMisc[g_clcmdNum][1] = read_flags(szFlags)
         g_clcmdMisc[g_clcmdNum][0] = read_flags(szAccess)
         g_clcmdNum++
      }
   }

   return 1
}
Аватара пользователя
navigator
 
Сообщения: 48
Зарегистрирован: 03 фев 2011, 21:35
Откуда: Уфа.
Благодарил (а): 12 раз.
Поблагодарили: 2 раз.
Опыт программирования: Меньше месяца
Языки программирования: Counter-Strike 1.6

Re: Отладка плагинов AMX Mod X

Сообщение shut » 04 фев 2011, 21:53

Подскажите где найти список всех возможных ошибок при компиляции?
Аватара пользователя
shut
 
Сообщения: 28
Зарегистрирован: 28 янв 2011, 00:56
Благодарил (а): 1 раз.
Поблагодарили: 1 раз.
Опыт программирования: Меньше месяца
Языки программирования: CS 1.6 CSDM + War3ft

Re: Отладка плагинов AMX Mod X

Сообщение Ser_UFL » 04 фев 2011, 22:52

Запомните, всегда по жизни вас будут красить вежливость и спокойствие, а не наезды и дешевые понты ;)
Аватара пользователя
Ser_UFL
 
Сообщения: 1003
Зарегистрирован: 22 авг 2009, 19:30
Откуда: Hell
Благодарил (а): 276 раз.
Поблагодарили: 379 раз.
Языки программирования: Counter-Strike 1.6:
WebMod-scripts, little Pawn.

Re: Отладка плагинов AMX Mod X

Сообщение Lt.RAT » 05 фев 2011, 05:15

А ты уверен, что ты правильно используешь

[pawn]
public plugin_natives()
{
   
set_module_filter("module_filter")
   
set_native_filter("native_filter")
}
 
[/pawn]

Пример использования подобного : 8 пост -> Вы должны зарегистрироваться, чтобы видеть ссылки.
А вообще лучше дважды подумать, а точно ли оно вообще надо тут.
Аватара пользователя
Lt.RAT
 
Сообщения: 313
Зарегистрирован: 30 сен 2009, 01:44
Благодарил (а): 4 раз.
Поблагодарили: 149 раз.
Языки программирования: Counter-Strike 1.6

Re: Отладка плагинов AMX Mod X

Сообщение x00peR » 04 мар 2011, 20:13

А я все время голову ломал зачем нужен этот debug, знал что он для отладки, но как использовать его был вопрос :)
Автору статьи большое спасибо. Полезно многим она будет.
Аватара пользователя
x00peR
 
Сообщения: 32
Зарегистрирован: 04 мар 2011, 20:05
Благодарил (а): 9 раз.
Поблагодарили: 1 раз.


Вернуться в Статьи / фрагменты кода

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2