←  Tutoriale

AMXX.pl: Support AMX Mod X i SourceMod

»

Natywy

  • +
  • -
R3X - zdjęcie R3X 03.02.2010

Natywy

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
No i pluginu, który będzie korzystał z dobrodziejstw biblioteki.


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ł ;P]), 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 :D



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

Załączone pliki

  • Załączony plik  Natywy.rar   1,65 KB   316 Ilość pobrań
Odpowiedz

  • +
  • -
Miczu - zdjęcie Miczu 03.02.2010

Na pewno sie przyda +
Odpowiedz

  • +
  • -
G[o]Q - zdjęcie G[o]Q 03.02.2010

rozwiales wszelkie moje watpliwosci co do natywow :D masz +

PS
powinienes wiecej poradnikow pisac :D
Odpowiedz

  • +
  • -
Owner123 - zdjęcie Owner123 07.02.2010

Można jeszcze wspomnieć o 3 argumencie funkcji register_native :F
Gdy style = 1 zamiast używać get_param można od razu zrobić taki chwyt:
public jakas_natywa(id, arg1, arg2)

I wtedy jest nawet łatwiej stwierdzić jakie są argumenty tej funkcji :F
Odpowiedz

  • +
  • -
Vertricus - zdjęcie Vertricus 07.02.2010

Info:
ważne by plugin korzystający z biblioteki był niżej w plugins.ini niż sama biblioteka.

Czy to wyklucza działanie 2 pluginów gdzie oba wymieniają się danymi? w sensie 1 z 2 i 2 z 1.
Może jaśniej
1 ma natywy z których korzysta 2
a 2 natywy z których korzysta 1.
:F
Można to zabić is_plugin_loaded?
Odpowiedz

  • +
  • -
R3X - zdjęcie R3X 07.02.2010

dla mnie ważne tylko z logicznego punkty widzenia, przyznam się, że w praktyce nigdy tego nie sprawdzałem :P
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 22.05.2011

jest możliwość aby funkcja natywna miała w sobie parametr (string) który można formatować za pomoca %s %i i tak dalej ?
dobrym przykładem jest tu funkcja client_cmd pierwszy parametr to id a potem jest formatowalna komenda chciałby uzyskać taki sam efekt
Odpowiedz

  • +
  • -
Knopers - zdjęcie Knopers 22.05.2011

Jak ustawisz "style" na 1 przy rejestracji natywu to sądzę że ten sposób : Funkcja zmiennej liczby parametrów - AMXX.pl: Support AMX Mod X powinien zadziałać.
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 22.05.2011

zrobione
Odpowiedz

  • +
  • -
R3X - zdjęcie R3X 22.05.2011

vdformat
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 22.05.2011

public text_info(id,Colors: color,const szFormat[], any:...){
	new szMessage[256];
	format_args(szMessage, charsmax(szMessage), 2);
	
	ColorChat(id,Color:color,"%s%s",gPrefix,szMessage);
}
zrobiłem to tak
nie sprawdzalem czy działa
Odpowiedz

  • +
  • -
GwynBleidD - zdjęcie GwynBleidD 31.03.2012

Chyba nikt nie zauważył, ale... to jest rozwiązanie dla amx starszego od 1.75. Od 1.75 wzwyż używa się reqlib oraz loadlib w plikach inc:
#pragma reqlib "nicto"
#if !defined AMXMODX_NOAUTOLOAD
#pragma loadlib "nicto"
#endif

Dodatkowo po użyciu tego sposobu i nazwaniu biblioteki (w register_library i w pliku inc) tak, jak nazwa pluginu-biblioteki nie musimy go umieszczać w plugins.ini, gdyż zostanie automatycznie włączony jeśli jakikolwiek inny plugin będzie go wymagał.
Użytkownik GwynBleidD edytował ten post 31.03.2012 15:01
Odpowiedz

wheypro - zdjęcie wheypro 05.02.2013

mam plugin który otwiera cele:
public cele(){
tutaj z fakemeta_util korzystam
}

i teraz robię osobny plugin o nazwie menu i w nim jest
case 1 : {
cele()
}


Jak zrobic by to menu korzystało z funkcji cele() zawartej w pierwszym pluginie?
Użytkownik benio101 edytował ten post 08.02.2013 15:56
Dodanie znacznika SMA
Odpowiedz

  • +
  • -
dasiek - zdjęcie dasiek 05.02.2013

w pierwszym
public plugin_natives()
{
	    register_native("cele", "open_cele");
}
w drugin dodajesz
native open_cele()
i możesz używać cele ako open_cele()
Odpowiedz

  • +
  • -
Pawian - zdjęcie Pawian 23.02.2013

nie wychodzi mi, moze ktos dokładnie podać te 2 pluginy? jak wheypro chciał, oraz taki plugin co włączy /boxa który korzysta z jb _extreme?
dasiek (13.03.2013 07:52):
Załóż nowy temat .
Odpowiedz

  • +
  • -
Eustachy8 - zdjęcie Eustachy8 09.08.2013

Witam, robię krok po kroku i w sma (2) - czyli w tym pluginie, który ma czytać z innego - wyskakuje mi, że nie może czytać z nicto


Użytkownik Eustachy8 edytował ten post 09.08.2013 13:42
Odpowiedz

  • +
  • -
Droso - zdjęcie Droso 10.08.2013

Wrzuć nicto.inc do include.

 

Albo sam dodawaj ręcznie natywy do .sma

 

To znaczy:


native Float:nic();

native cokolwiek(id, stan:s);

native moze_cos(id, Float:fTime, const szMessage[]);

Wklej to do pluginu (2 na początek za #include) zamiast używać biblioteki, bo to dokładnie to samo.

 

Odpowiedz

  • +
  • -
Eustachy8 - zdjęcie Eustachy8 10.08.2013

kompilacja przechodzi, ale nie działa :/

L 08/10/2013 - 22:19:15: Unhandled dynamic native error
L 08/10/2013 - 22:19:15: [AMXX] Run time error 10 (plugin "npc_sklep2.amxx") (native "buy_molotov") - debug not enabled!

Użytkownik Eustachy8 edytował ten post 10.08.2013 21:26
Odpowiedz

  • +
  • -
Droso - zdjęcie Droso 10.08.2013

Napisz w odpowiednim temacie podaj oba .sma

Poradzimy.

Odpowiedz

  • +
  • -
K!113r - zdjęcie K!113r 10.08.2013

Ja raz miałem coś podobnego, problem leżał w kolejności wpisu w plugins.ini gdyż plugin udostępniający natywy musiał być wyżej od tego co używał, bo pluginy uruchamiane są według tej kolejności i trzeba najpierw go stworzyć żeby potem użyć co chyba logiczne. Można uniknąć zachowywania kolejności, była jakaś funkcja która wykrywała natywy czy coś w tym stylu, lecz nie używałem tego, nie wiem jak działa i nie pamiętam jak to wyglądało.
Za wszelkie błędy w poście przepraszam, ale był za długi wieczór po robicie :)
Odpowiedz