←  Tutoriale

AMXX.pl: Support AMX Mod X i SourceMod

»

Forwardy

  • +
  • -
R3X - zdjęcie R3X 14.07.2010

Forwardy1. Opis
Działają odwrotnie do natywów. Funkcja natywna jest udostępniana innym pluginom. Forwardy to abstrakcyjne funkcje, które biblioteka próbuje wywołać. Wykonując forward dajemy sygnał, że nastąpiło jakieś zdarzenie i plugin może na nie zareagować. Można to lepiej zrozumieć biorąc pod uwagę forwardy samego AMXX, takie jak:
forward plugin_init();
forward client_putinserver(id);
stąd powinieneś się domyślić je rozpowszechniać.

W pliku .inc podajemy nagłówek
forward nazwa(Float:para, met, ry[]);
a w pliku .sma
public nazwa(Float:para, met, ry[]){
	//nasz kod
}
Dalej tę funkcji publiczną nazywam 'funkcją oczekującą'.

O tym jak zaprojektować czytaj dalej ->

2. Tworzenie
Po pierwsze musimy zarejestrować forward.

MultiForward
Gdy użyjemy poniższej, oczekująca funkcja będzie wywoływana w każdym pluginie, który z niej korzysta.
/**
* Rejestruje forward dostępny dla wszystkich pluginów
*
* @param name[] Nazwa publicznej funkcji
* @param stop_type Typ zatrzymania
* @param ... Parametry
* @return Uchwyt (liczba całkowita)
*/
CreateMultiForward ( const name[], stop_type, ... )


Jako name[] podajemy nazwę, Typ zatrzymania określa sposób realizacji:
#define ET_IGNORE		0	//ignoruj zwracaną wartość
#define ET_STOP			1	//zatrzymuje przy PLUGIN_HANDLED
#define ET_STOP2		2	//to samo,tylko nie zwraca największej wartości
#define ET_CONTINUE		3	//bez stopu, zwraca największą wartość
forward z typem ingore i continue będzie wywołany zawsze we wszystkich pluginach
opcje stopu (STOP i STOP2) zatrzymują rozsyłanie forwardu po otrzymaniu PLUGIN_HANDLED

Jeśli na tym skończymy to powstaje forward bez parametrów, jak:
//sma biblioteki
CreateMultiForward ( "nic_sie_nie_stalo", ET_IGNORE);

//w pliku .inc
forward nic_sie_nie_stalo();


Aby dodać jakieś argumenty trzeba rozwinąć rejestrowanie o dodatkowe wartości. Do określenia typu parametru służą stałe (nazwy są sugestywne)
#define FP_CELL			0
#define FP_FLOAT		1
#define FP_STRING		2
#define FP_ARRAY		4
Dodanie argumentu forwardu polega na dopisniu jego typu po przecinku
//sma biblioteki
CreateMultiForward ( "nic_sie_nie_stalo", ET_IGNORE, FP_CELL, FP_FLOAT);

//w pliku .inc
forward nic_sie_nie_stalo(id, Float:fTime);


MultiForwardEx
Jest to wersja kompatybilna z pluginami AMX. Nie będę się tym zajmował, szczegóły w pliku amxmodx.inc.

OneForward
Druga możliwość to forward przeznaczony wyłącznie dla jednego pluginu.
/**
* Rejestruje forward dostępny dla pojedynczego pluginu
*
* @param plugin_id Id pluginu
* @param name[] Nazwa publicznej funkcji
* @param ... Parametry
* @return uchwyt (liczba całkowita)
*/
CreateOneForward ( plugin_id, const name[], ... )

Nie ma tu opcji stopu, bo tylko jeden, konkretny plugin może wykonać forward i zwróci on równie konkretną wartość.

plugin_id to id zwrócone przez funkcję
find_plugin_byfile(const pname[]);
albo....

Ciekawym rozwiązaniem jest połączenie funkcji natywnej z forwardem w ten sposób. Wyobraźmy sobie rdzeń modu, który pozwala dodawać itemy w osobnych pluginach. Rdzeń ten udostępnia natywną funkcję
register_item( /*parametry*/)
, która zapisuje informacje i tworzy właśnie pojedynczy forward powiedzmy:
forward get_item(id)
ten osobny plugin będzie czekał na sygnał, gdy gracz zdobędzie ten przedmiot. Wygodne prawda? Zwłaszcza, że id pluginu to jeden z parametrów funkcji obsługującej natyw.

Parametry jak przy MultiForward↵

3. Wywołanie
Pora wysłać sygnał wywołania forwardu.
/**
* Wywołuje wskazany forward
*
* @param forward_handle Wartość zwrócona przez Create(One|Multi)Forward
* @param &ret Wartość zwrócona przez wywołane forwardy przekazana przez referencję
* @param ... Dokładnie tyle parametrów i takich typów jak podaliśmy przy tworzeniu
* Dane zostaną przekazane do funkcji oczekujących na forward
* @return 1 jeśli wywołano jakąś funkcję oczekującą, 0 jeśli nie
*/
ExecuteForward ( forward_handle, &ret, ... )


Przykład:
new gFW;
public plugin_init(){
	gFW = CreateMultiForward("jakies_zdarzenie", ET_CONTINUE, FP_FLOAT, FP_CELL, FP_STRING);
}
public plugin_cfg(){
	new iRet;
	ExecuteForward(gFW, iRet, 3.14, -5, "Pi");
}
Tak podane parametry są jak najbardziej w porządku. Inaczej ma się sprawa z type FP_ARRAY. Nie podajemy bezpośrednio tablicy, ale rezultat funkcji
/**
* Przygotowuje tablicę do przekazania do forwardu
*
* @param array[] Tablica wejściowa
* @param size Ilość komórek
* @param copyback Czy tablica zmieniona przez funkcje oczekującą ma wrócić
*/
PrepareArray(array[], size, copyback=0 )


Ostatni parametr jest dosyć ciekawy. Wynika z niego, że oprócz podania danych do forwardu możemy także z niego uzyskać. Ustawiając 0 mamy normalne przekazanie, podając 1 funkcje oczekujące będą pracować niejako na tej tablicy.
 
new gFW;
public plugin_init(){
	gFW = CreateMultiForward("jakies_zdarzenie", ET_CONTINUE, FP_CELL, FP_ARRAY);
}
public plugin_cfg(){
	new data[2];
	data[0] = 0;
	data[1] = 1;	

	new iRet;
	ExecuteForward(gFW, iRet, 0, PrepareArray(data, 2, 1));
	
	//data[0] == 0? możliwe, że już nie!
}
4. Przykłady
w załączniku xD
plik udostępniający i korzystający z forwardu w jednym pliku odzielone kreskami

ex1 - tylko wywołanie
ex2 - z analizą z wyniku (istotne co funkcje oczekujące zwracają)
ex3 - przekazywanie tablicy
ex4 - przekazywanie tablicy i powrót wyniku

Załączone pliki

  • Załączony plik  ex.rar   2,48 KB   335 Ilość pobrań

Użytkownik glut edytował ten post 25.02.2014 21:56
Mutli na Multi
Odpowiedz

  • +
  • -
Miczu - zdjęcie Miczu 14.07.2010

R3X, ja robiłem jakiś czas temu test, że nie trzeba nic oprócz CreateMutliForward i można wywołać dowolną funkcje "public" dowolnego pluga, bez .inc czy coś :F

Poza tym się zastanawiam, czy wszystkie funkcje typu set_task... co maja nazwę funkcji w " " nie używają w jakiś sposób forwarda... Co ty na to? :&
Odpowiedz

  • +
  • -
R3X - zdjęcie R3X 14.07.2010

Testowałeś callfunc`em czy jak? Nie sądzę, żeby kompilator tolerował takie wybiegi wprost
funkcja(parametry);
:)

Budowę set_task można sprawdzić w źródłach amxmodx i się okaże co za bajery ma, to co mówisz wydaje się rozsądne.
Odpowiedz

  • +
  • -
Miczu - zdjęcie Miczu 14.07.2010

Spoiler

i
Spoiler


Działa jak natura chciała :F

Nazwa pluga nie ma znaczenia, robiłem szybkie testy dla siebie :F
Użytkownik benio101 edytował ten post 05.12.2012 13:55
Dodanie znacznika SMA
Odpowiedz

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

czyli miczu wystarczy
mutliforward z nazwa funkcji z innego pluginu i potem execute uchwytu do forwardu i funkcja sie wykona tak :?:
Odpowiedz

  • +
  • -
Miczu - zdjęcie Miczu 14.07.2010

Tak, np tak się można włamać do każdego publika, np. zrobiłem test z kopaniem piłki w SJ i działa :)
Odpowiedz

  • +
  • -
R3X - zdjęcie R3X 15.07.2010

Z tego co Miczu piszesz wynika, że deklaracja forward funkcja(); rzeczywiście nie jest konieczna do działania. Fajna sprawa :)

Sprawdziłem i set_task rzeczywiście używa forwardu, ale w sposób OneForward. Tak samo funkcje sortujące z callbackiem czy query_client_cvar i pewnie cała reszta. Nie ma więc obawy, że 2 takie same set_taski w 2 różnych pluginach się pogryzą.
Odpowiedz

  • +
  • -
Miczu - zdjęcie Miczu 15.07.2010

Dobrze wiedzieć, że moja intuicja nie zawodzi :)

Może zbadasz ten callback bo używanie innych plugów i dostawać wynik z nich jest bardzo interesujące, a może nawet przydatne :)
Odpowiedz

  • +
  • -
R3X - zdjęcie R3X 15.07.2010

Można dostać wynik z powrotem z typem array tylko, tak jak pisałem. Pewnie wygląda na przypuszczenie bo dałem '?' na końcu, ale to dotyczy wątpliwości czy funkcja oczekująca zmienia tablicę. W załączniku ex4.txt dotyczy właśnie powracania kopii array`a.

tylko przekazanie
PrepareArray(array, size)

przekazanie + kopia wraca
PrepareArray(array, size, 1 )

FP_STRING jest zawsze tylko przekazywane, ale przecież można użyć także typu FP_ARRAY dla tekstów :D
Odpowiedz

  • +
  • -
Fili:P - zdjęcie Fili:P 19.01.2012

Jest literówka mała:

gFW = CreateMutliForward("jakies_zdarzenie", ET_CONTINUE, FP_FLOAT, FP_CELL, FP_STRING);

Powinno być:

gFW = CreateMultiForward("jakies_zdarzenie", ET_CONTINUE, FP_FLOAT, FP_CELL, FP_STRING);

Chodzi że było Mutli zamiast Multi.
Odpowiedz

  • +
  • -
dasisdas - zdjęcie dasisdas 19.01.2012

Fajny poradnik,dużo ciekawych rzeczy można się z niego dowiedzieć
Odpowiedz