- дізнаватися поточні значення змінних;
- і з'ясовувати, яким шляхом виконувалася програма.
У AMX Mod X вже вбудований відладчик, якого нам цілком вистачить для вирішення наших проблем. Значення команди amx_debug має бути 1. Режим налагодження для певного плагіна включається в такий спосіб: в файлі. /addons/amxmodx/configs/plugins.ini навпаки необхідного плагіна прописуємо слово debug. наприклад:
Після цього міняємо карту на сервері або перезапускаємо сервер (команда restart). Тепер в логах AMXX (. / Addons / amxmodx / logs) ми зможемо детально дізнатися на якому етапі виникає помилка в роботі плагіна. Список з помилками в директорії logs називаються error_X.txt. де X - це дата, коли був створений даний файл.
Припустимо у нас є плагін такого змісту, який при вході гравця на сервер записує його ім'я в глобальну змінну g_Names. Також у нас зареєстрована консольна команда amx_names_reset для обнулення цієї змінної через цикл з фіксованою кількістю кроків. Даний код скомпілювати без помилок, але це ще не означає, що він буде працювати, як йому належить. Після запуску даного плагіна, а також використання консольної команди amx_names_reset в директорії logs ми виявили лог з помилками.
debug.sma:
Код: Виділити все #include
#define PLUGIN "Example Debug Plugin"
#define VERSION "1.0"
#define AUTHOR "DJ_WEST"
new g_Names # 91; 33 # 93; # 91; 32 # 93;
public plugin_init ()
register_plugin (PLUGIN. VERSION. AUTHOR)
register_concmd ( "amx_names_reset". "Names_Reset")
>
public client_putinserver (id)
new s_Name # 91; 32 # 93;
get_user_name (id. s_Name. charsmax (s_Name))
g_Names # 91; id # 93; = s_Name
server_print ( "% s entered the game". s_Name)
>
public Names_Reset (id)
for (new i = 1; i <= 33 ; i ++)
g_Names # 91; i # 93; = ""
server_print ( "Names reset")
>
Тепер дивимося наш цикл:
Код: Виділити все
for (new i = 1; i <= 33 ; i ++)
g_Names # 91; i # 93; = ""
Бачимо, що цикл виконується від i = 1 до i <= 33 при этом i используется в g_Names. Но если вспомнить размерность массива g_Names, то понимаем, что когда i дойдет до 33, то это будет за пределами g_Names, следовательно нам нужно исправить код на:
Код: Виділити все
for (new i = 1; i <= 32 ; i ++)
g_Names # 91; i # 93; = ""
Заново компілюємо плагін, перевіряємо його знову і бачимо, що все працює чудово. Пам'ятайте, що це лише приклад налагодження. Насправді помилки можуть бути іншими, а якщо плагін ще й великий, то пошук помилки може тривати набагато довше.
Не пишіть мені в ЛС. якщо вам потрібна допомога на безоплатній основі. Будь-які питання на форум.
Options:
-A
-a output assembler code
-C # 91; + / - # 93; compact encoding for output file (default = -)
-c
-Dpath active directory path
-d0 no symbolic information, no run-time checks
-d1 # 91; default # 93; run-time checks, no symbolic information
-d2 full debug information and dynamic checking
-d3 full debug information, dynamic checking, no optimization
-e
-H
-i
-l create list file (preprocess only)
-o
-p
-r # 91; name # 93; write cross reference report to console or to specified file
Як видно за замовчуванням йде -d1. Тому як в compile немає ключів визначають отладочную інфу. Якщо прописати параметр -d3. інформації при налагодженні можна отримати трохи більше.
Якщо ж вказати -d0. то отладочной інформації не буде. Це ускладнить як дизасемблювання, так і унеможливить налагодження. Бо якщо ви її включите в настройках або додасте debug при запуску, то плагін запущений взагалі не буде в отладочном режимі.
Відповідно відрізняються і розміри плагінів з цими опціями. Чим більше отладочной інформації, тим "важче" плагін.
Щоб правильно поставити запитання, потрібно знати більше половини відповіді.
Cerberus - заміна amxbans і багато чому іншому
Довіряй але перевіряй
Як тут написано, стандартний ключ йде 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".
Мабуть хтось редагував компілятор і лажанулся (Можна навіть відписати їм про це "баг")
ЗИ речі опису опцій компілятора є в Ви повинні зареєструватися, щоб бачити посилання. і там теж можна відзначити, що дефолтний ключ насправді інший.
#include
#include
/ ** skip autoloading since it's optional * /
#define AMXMODX_NOAUTOLOAD
#include
new g_menuPosition # 91; 33 # 93;
new g_menuPlayers # 91; 33 # 93; # 91; 32 # 93;
new g_menuPlayersNum # 91; 33 # 93;
new g_menuOption # 91; 33 # 93;
new g_menuSelect # 91; 33 # 93; # 91; 254 # 93;
new g_menuSelectNum # 91; 33 # 93;
#define MAX_CLCMDS 24
new g_clcmdName # 91; MAX_CLCMDS # 93; # 91; 32 # 93;
new g_clcmdCmd # 91; MAX_CLCMDS # 93; # 91; 254 # 93;
new g_clcmdMisc # 91; MAX_CLCMDS # 93; # 91; 2 # 93;
new g_clcmdNum
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"), 1 023, "actionlaccmdmenu")
new clcmds_ini_file # 91; 254 # 93;
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 # 91; id # 93;
g_menuOption # 91; id # 93; % = G_menuSelectNum # 91; id # 93;
displaylaccmdmenu (id, g_menuPosition # 91; id # 93;)
>
case 8: displaylaccmdmenu (id, ++ g_menuPosition # 91; id # 93;)
case 9: displaylaccmdmenu (id, --g_menuPosition # 91; id # 93;)
default:
new player = g_menuPlayers # 91; id # 93; # 91; g_menuPosition # 91; id # 93; * 7 + key # 93;
new flags = g_clcmdMisc # 91; g_menuSelect # 91; id # 93; # 91; g_menuOption # 91; id # 93; # 93; # 93; # 91; 1 # 93;
if (is_user_connected (player))
new command # 91; 512 # 93 ;, authid # 91; 32 # 93 ;, name # 91; 32 # 93 ;, userid # 91; 32 # 93;
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 # 91; id # 93;)
>
>
displaylaccmdmenu (id, pos)
if (pos <0)
return
new menuBody # 91; 512 # 93;
new b = 0
new i
new name # 91; 32 # 93;
new start = pos * 7
if (start> = g_menuPlayersNum # 91; id # 93;)
start = pos = g_menuPosition # 91; id # 93; = 0
new len = format (menuBody, 511, g_coloredMenus. "\ y% L \ R ./.^ n \ w ^ n". "% L ./.^n^n", id, "CL_CMD_MENU", pos + 1 , (g_menuPlayersNum # 91; id # 93; / 7 + ((g_menuPlayersNum # 91; id # 93;% 7). 1. 0)))
new end = start + 7
new keys = MENU_KEY_0 | MENU_KEY_8
if (end> g_menuPlayersNum # 91; id # 93;)
end = g_menuPlayersNum # 91; id # 93;
for (new a = start; a
get_user_name (i, name, 31)
if (! g_menuSelectNum # 91; id # 93; || (access (i, ADMIN_IMMUNITY) i! = id))
++b
if (g_coloredMenus)
len + = format (menuBody # 91; len # 93 ;, 511-len, "\ d ..% s ^ n \ w", b, name)
else
len + = format (menuBody # 91; len # 93 ;, 511-len, "#.% s ^ n", name)
> Else keys | = (1<
if (is_user_admin (i))
len + = format (menuBody # 91; len # 93 ;, 511-len, g_coloredMenus. "..% s \ r * ^ n \ w". "..% s * ^ n", ++ b, name)
else
len + = format (menuBody # 91; len # 93 ;, 511-len, "..% s ^ n", ++ b, name)
>
>
if (g_menuSelectNum # 91; id # 93;)
len + = format (menuBody # 91; len # 93 ;, 511-len, "^ n8.% s ^ n", g_clcmdName # 91; g_menuSelect # 91; id # 93; # 91; g_menuOption # 91; id # 93 ; # 93; # 93;)
else
len + = format (menuBody # 91; len # 93 ;, 511-len, "^ n8.% L ^ n", id, "NO_CMDS")
if (end! = g_menuPlayersNum # 91; id # 93;)
format (menuBody # 91; len # 93 ;, 511-len, "^ n9.% L. ^ n0.% L", id, "MORE", id, pos. "BACK". "EXIT")
keys | = MENU_KEY_9
>
else
format (menuBody # 91; len # 93 ;, 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
for (new a = 0; a
g_menuSelect # 91; id # 93; # 91; g_menuSelectNum # 91; id # 93; ++ # 93; = a
displaylaccmdmenu (id, g_menuPosition # 91; id # 93; = 0)
load_settings (szFilename # 91; # 93;)
if (! file_exists (szFilename))
return 0
new text # 91; 256 # 93 ;, szFlags # 91; 32 # 93 ;, szAccess # 91; 32 # 93;
new a, pos = 0
while (g_clcmdNum
if (parse (text, g_clcmdName # 91; g_clcmdNum # 93 ;, 31, g_clcmdCmd # 91; g_clcmdNum # 93 ;, 253, szFlags, 31, szAccess, 31)> 3)
while (replace (g_clcmdCmd # 91; g_clcmdNum # 93 ;, 253, "\ '", "^" "))
// do nothing
>
g_clcmdMisc # 91; g_clcmdNum # 93; # 91; 1 # 93; = Read_flags (szFlags)
g_clcmdMisc # 91; g_clcmdNum # 93; # 91; 0 # 93; = Read_flags (szAccess)
g_clcmdNum ++
>
>