Налагодження плагінів amx mod x - російська спільнота по скриптингу amxx

Налагодження - етап розробки плагіна, на якому виявляють, локалізують і усувають помилки. Щоб зрозуміти, де виникла помилка, доводиться:
  • дізнаватися поточні значення змінних;
  • і з'ясовувати, яким шляхом виконувалася програма.

У 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 alignment in bytes of the data segment and the stack
-a output assembler code
-C # 91; + / - # 93; compact encoding for output file (default = -)
-c codepage name or number; e.g. Тисячі двісті п'ятьдесят дві for Windows Latin-1
-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 set name of error file (quiet compile)
-H window handle to send a notification message on finish
-i path for include files
-l create list file (preprocess only)
-o set base name of output file
-p set name of "prefix" file
-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 i = g_menuPlayers # 91; id # 93; # 91; a # 93;
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 if (access (id, g_clcmdMisc # 91; a # 93; # 91; 0 # 93;))
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 (text # 91; 0 # 93; == ';') continue

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 ++
>
>