1. Opis
Funkcje natywne są dostępne dla każdego zainstalowanego pluginu AMXX. Udostępniają funkcje natywne tworzymy z naszego pluginu jakby dodatkową bibliotekę. Dzięki temu mamy możliwość podziału większego dzieła nie tylko na pliki, a na osobne pluginy. Pozwala to na dużą elastyczność kodu oraz pracę z krótszymi, mniej skomplikowanymi programami.
Krótko: Możemy korzystać z danych jednego pluginu w innym.
2. Przygotowanie
Aby to zadziałało potrzeba dwóch współgrających elementów:
- pluginu-biblioteki, który obsługuje funkcje
- pliku .inc, który pozwoli korzystać z tych funkcji w innym pluginie
Na potrzeby tego artykułu stworzę testową bibliotekę <nicto> (czyt. "nic to")
INC
Weźmy się najpierw za plik .inc. Raz dołączony plik nie będzie więcej potrzebny, więc żeby nie powodował problemów ograniczymy jego wykonywanie:
#if defined _nicto_included #endinput #endif #define _nicto_included
sprawdzamy czy stała "_nicto_included" istnieje (wymyślamy coś własnego, nazwa powinna być unikatowa)
jeśli tak to kończymy plik (#endinput)
jeśli nie to ją definiujemy, potem dołączana jest reszta pliku
dalej informujemy kompilator, że korzystamy z biblioteki nicto:
#pragma library "nicto"
i dalej nagłówki funkcji(nasze natywy lub forwardy[o nich będzie następny artykuł ]), stałe, enumeracje lub całe funkcje (stocki)
cały plik inc może wyglądać np tak:
#if defined _nicto_included #endinput #endif #define _nicto_included #pragma library "nicto" enum stan{ NIC, COS } native Float:nic(); native cokolwiek(id, stan:s); native moze_cos(id, Float:fTime, const szMessage[]);
SMA(1)
Pierwszy kod sma to będzie nasza biblioteka. Sam plugin może działać sobie po swojemu tak jak każdy inny. Kluczowym elementem jest fragment:
public plugin_natives(){ }
Po pierwsze rejestrujemy bibliotekę:
register_library("nicto");
Po drugie, trzecie i czwarte:
register_native("nic", "n_nic"); register_native("cokolwiek", "n_cokolwiek"); register_native("moze_cos", "n_moze_cos");
register_native("funkcja_biblioteki", "funkcja_pluginu");funkcja_biblioteki - to ta z inc`a, będzie wywoływana w innych pluginach
funkcja_pluginu - ona będzie odpowiedzialna za działanie tej pierwszej; jej parametry to id pluginu, w którym wywołano natyw oraz ilość argumentów, zwracany typ musi być zgodny z tym podanym dla funkcja_biblioteki w inc`u
Na tym etapie biblioteka wygląda tak:
#include <amxmodx> #include <amxmisc> #define PLUGIN "NicTo Lib" #define VERSION "1.0" #define AUTHOR "R3X" public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) } public plugin_natives(){ register_library("nicto"); register_native("nic", "n_nic"); register_native("cokolwiek", "n_cokolwiek"); register_native("moze_cos", "n_moze_cos"); } //plugin - id pluginu //params - ilość argumentów public Float:n_nic(plugin, params){ } public n_cokolwiek(plugin, params){ } public n_moze_cos(plugin, params){ }
Funkcja nic ma nagłówek: native Float:nic();
=żadnych parametrów, a zwracać ma floata
skoro 'nic', to możemy zrobić np. to:
public Float:n_nic(plugin, params){ return 0.0; }
Funkcja cokolwiek korzysta z typu danych deklarowanego w samym incu. Nic nie stoi na przeszkodzie, aby go tu dołączyć. Problemy się zaczną, gdy będziemy wywoływać własne funkcje natywne w pluginie-bibliotece. Po prostu to nie przejdzie
w n_cokolwiek oczekujemy 2 parametrów id, i s; musimy mieć pewność, że są:
public n_cokolwiek(plugin, params){ if(params < 2){ log_amx("Zbyt malo parametrow funkcji cokolwiek!"); return 0; } return 1; }
Wartość samych parametrów pobrać nam pozwolą funkcje dla danego typu danych:
get_string(param, dest[], maxlen); // tekst
get_param(param); //komórka pamięci (int, char, bool)
Float:get_param_f(param); //float
get_param_byref(param); // komórka przez referencję
Float:get_float_byref(param); //float przez referencję
get_array(param, dest[], size); //tablica komórek
get_array_f(param, Float:dest[], size); //tablica float`ów
Jako, że tablice bez ‘const’ i jawne referencje pozwalają na zmianę wartości argumentów istnieją też odpowiedniki set_*
set_string(param, dest[], maxlen);
set_param_byref(param, value);
set_float_byref(param, Float:value);
set_array(param, const source[], size);
set_array_f(param, const Float:source[], size);
W każdym przypadku param to numer parametru licząc od lewej zaczynając od 1.
Skupmy się na pobieraniu. Natyw cokolwiek przekazuje id oraz stan:s. Ich wartości w n_cokolwiek to:
new id = get_param(1); new stan:s = stan:get_param(2);
Aby zachować układ zmiennych i uniknąć ‘tag mismatch’ dokonałem rzutowania do stan:
Załóżmy, że id to index gracza, a funkcja pokazuje mu na czacie komunikat zależny od stanu COS/NIC. Biblioteka powinna teraz wyglądać tak:
#include <amxmodx> #include <amxmisc> #include <nicto> #define PLUGIN "NicTo Lib" #define VERSION "1.0" #define AUTHOR "R3X" public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) } public plugin_natives(){ register_library("nicto"); register_native("nic", "n_nic"); register_native("cokolwiek", "n_cokolwiek"); register_native("moze_cos", "n_moze_cos"); } //plugin - id pluginu //params - ilość argumentów public Float:n_nic(plugin, params){ return 0.0; } public n_cokolwiek(plugin, params){ if(params < 2){ log_amx("Zbyt malo parametrow funkcji cokolwiek!"); return 0; } new id = get_param(1); if(!is_user_connected(id)) return 0; new stan:s = stan:get_param(2); switch(s){ case NIC: client_print(id, print_chat, "NIC"); case COS: client_print(id, print_chat, "COS"); default: return 0; } return 1; } public n_moze_cos(plugin, params){ }
Do pełniejszego obrazu natywu potrzebujemy danych z tego pluginu. Utwórzmy tablicę globalną giRandom [33], i przy wejściu na serwer przypiszmy graczowi losową liczbę 0-100.
Niech funkcja może_cos zwróci wartość tablicy z podanego indeksu (id) i wrzuci do logów wartości fTime i szMessage[].
public n_moze_cos(plugin, params){ if(params < 3){ log_amx("Zbyt malo parametrow funkcji moze_cos!"); // -1 nie mieści się w przedziale 0-100, więc będzie można wychwycić błąd return -1; } new id = get_param(1); if(id < 0 || id > 32) //nie musi byc gracza, wystarczy ze jest taki indeks w tablicy return -1; new Float:fTime = get_param_f(2); new szMessage[32]; get_string(3, szMessage, 31); log_amx("fTime=%f, szMessage = %s",fTime, szMessage); return giRandom[id]; }
SMA(2)
Teraz pora na plugin, który będzie korzystał z biblioteki. Po prostu dołączamy <nicto> i używamy podanych funkcji np tak:
#include <amxmodx> #include <amxmisc> #include <nicto> #define PLUGIN "New Plug-In" #define VERSION "1.0" #define AUTHOR "R3X" public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) log_amx("Nic:%f", nic()); register_clcmd("say /cokolwiek","cmdCokolwiek"); } public cmdCokolwiek(id){ cokolwiek(id, NIC); moze_cos(id, 3.14, "Pi"); return PLUGIN_CONTINUE; }
Info:
ważne by plugin korzystający z biblioteki był niżej w plugins.ini niż sama biblioteka. W innym przypadku plugin korzystający z biblioteki musisz przefiltrować natywy:
set_native_filter