FüggvényekA függvények rejtelmeibe vezetlek be benneteket. Mire jók, miért szeretjük, hogyan használjuk? (A tutort a komolyabb fogalomzavarban szenvedőknek ajánlom, akik nem tudják mi a fene a stock.... ez elég gáz. Gondolok erre: "stockot a végére s kész".)
Még sok mindent le lehetne írni, de ezt maximum a hszek alapján fogom megtenni, (tehát felmerült kérdések esetén bővítem)
Az előbbiekkel ellentétben ez nem annyira referenciásnak készült.
BevezetésMikor kódot írunk, akkor egy nagyobb feladat megoldása is nehézkes, és átláthatatlan, ha az alap belépési ponthoz rendelt (jelen esetben plugin_init) függvénybe írnánk. Képzeljünk el egy több ezer soros kódot, aminek minden egyes sora plugin_initben van! Kezelhetetlen (meg a scriptelők esetében felfoghatatlan, hiszen az csak az alap változó értékek beállítására és az eseményekre való feliratkozásra + parancsok létrehozására használjuk)
A kód tisztává tételére definiálhatunk függvényeket, amik sok esetben könnyebbé teszik a kódolást. Ezeket több fajta kulcsszóval is el tudunk látni s ezáltal kiterjeszthetjük a funkcionalitásukat. Ilyen a public, native és a stock. Ezekről a fejezet végén olvashattok.
SzintaxisMindegyiknek megvan a maga szerepe a nyelvben. Mielőtt sorra vennénk, vegyük a függvény szintaxisát (általános, az alap Pawn kicsit többet tud, de az itt nem lényeges, itt nincs minden funkció kivezetve).
[public|native|stock] functionName( [param_1, param_2, ....] ) {
...
[return [X1]]
...
[return [X2]]
...
[return [XN]]
}
Ahol param_x paraméterek skalárok, vagy tömbök vagy ezek egy kombinációja, míg az X1, X2, ..., XN a függvény visszatérési értéke. Ezek mind opcionálisak (maga a visszatérési érték is!).
Maga a függvény pozíciója, a helye a kódban teljesen irreleváns: Bárhova beírhatjuk a kódunkat, nem kell előre definiálni a létét, mint C++ban.
PéldákEgy nagyon egyszerű "Hello World!" loggoló függvény:
show()
{
log_amx("Hello World!");
}
Természetesen paramétereket is átadhatunk neki:
show(count)
{
new i = 0;
while (i < count) {
log_amx("Hello World!")
i++;
}
}
Ez a paraméterben megadott mennyiségű üzenetet log-gol majd.
Eljárás vagy függvény?Amennyiben nincs return megadva, akkor eljárásnak hívjuk a "függvényt". Ez matek: A függvény visszaad egy értéket. itt is erről van szó. Ha nem ad vissza, akkor az már nem függvény
Ennek ellenére a filozófia csak függvényként hivatkozik rá, azaz "minden függvény".
A legtöbb programozási nyelvekben ez máshogy van kezelve:
1) vagy van hozzá megfelelő kulcsszó (pl, Delphi, Pascal, Ada, VB: PROCEDURE és FUNCTION kulcsszavak)
2) vagy a visszatérési érték típusával azonosítjuk, hogy függvény-e (pl C, C++, C#, Java: void fgv() <- procedure, [int, byte, char, short, ...] fgv <- function).
Amennyiben a Pawnban a függvényt taggel látjuk el (pl Float:), akkor megadtunk neki egy visszatérési értéktípust, tehát ez már függvényként fog működni.
A Pawn fordító ezt kezeli is: Amennyiben van legalább egy return kulcsszó, akkor függvényként regisztrálja be, és visszajelez, ha nem minden ágban tér vissza. Ez a szokásos warning. Hibát nem okoz, csak akkor okozhat, ha függvényként használjuk.
Példapublic mokas(i) {
if (i)
return i;
}
Az is megeshet, hogy egy függvény futását csak megszakítani akarjuk s nem is várunk értéket vissza a függvénytől. Ezt megtehetjük a return kulcsszó megadásával:
byebye(i)
{
if (i)
return;
else
log_amx("Byebye");
}
FüggvényhívásAmikor megírtunk egy függvényt, akkor használni is szeretnénk. Ehhez csupán meg kell adni a függvény nevét, (amit hívni akarunk), és zárójelben a paramétereit.
Példák// Példa 1:
show(10); // Kiírja 10-szer, hogy "Hello World!"
// Példa 2:
new k = mokas(10); // Visszaadja kb a 10-et.
Kérdések, nektek, mint Házi feladat (
):
- Mi van akkor, ha new k = mokas(0) -át írunk be?
- Mi van akkor, ha csak ennyit írunk: mokas(10)
ParaméterezésA függvényben alapértelmezetten a paraméterek érték szerint adódnak át, azaz a híváskor lemásolódnak az értékeik újra, s a függvény futása végén ezt törli. Az eredeti értékek sosem változnak meg.
Példaswap(a, b) {
new tmp = a;
a = b;
b = tmp;
}
new a = 10;
new b = 20;
swap(a, b);
log_amx("a: %d, b: %d", a, b); // Eredmény: a: 10, b: 20
Erre megoldásként használható a referenciajel, amivel referencia (cím szerinti) értékadás fog történni. Nem foglal le a memóriában új helyet a paraméterben megadott változóknak, s nem másolja át a tartalmát. Egyszerűen a memóriabeli címét adja át, s az memóriacímre mutató értéket változtatja.
Előző kód "javítása":swap(&a, &b) {
new tmp = a;
a = b;
b = tmp;
}
new a = 10;
new b = 20;
swap(a, b);
log_amx("a: %d, b: %d", a, b); // Eredmény: a: 20, b: 10
Tömb paraméterekLehetőség van tömböt is átadni paraméterül, viszont ezek mindig referencia szerint adódnak át. Ennek oka igen egyszerű: nem lehet tudni, hogy mekkora a tömb mérete, s nem feltétlen biztos az, hoyg lesz elég hely a híváskor. Emiatt adódik át cím szerint a cucc:
duplicateNums(num[], size) {
new i = 0;
while (i < size) {
num[i:7q0wa6te] *= 2;
++i;
}
}
new num[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
duplicateNums(num, sizeof(num));
Ha ezt el akarjuk kerülni, akkor a jól ismert const kulcsszóval tudjuk ezt jelölni, s ekkor fordítási időben jelzi felénk a hibát.
További kulcsszavakMire is vannak a korábban említett (public, native, stock) kulcsszavak (amiket használni nem kötelező)? Mindenekelőtt kicsit mélyedjünk el abban, hogy mi van a függvények mögött.
BevezetésAz AmxModX egy absztrakt (inkább virtuális) gép, ami beállítástól függően több különböző plugint tölt be. A pluginok többsége regisztrálhat parancsokat, mint például a /rank, /me, stb.
Ezek többségét a register_clcmd-vel tehetjük meg, (használhatunk register_concmd-t is, s akkor szerver konzolból is kiadható a móka).
Feliratkozhatunk eseményekre is (event, pl DeathMessage, Player[Pre/Post]Think, Spawn, LogeventRound, stb), amik az adott esemény triggelerése esetén futnak le.
PublicEzen függvények megírásakor maga a motor hív be a pluginba, s keresi meg a lefordított plugin által küldött szimbólumtáblán a parancshoz/eseményhez rendelt függvényt. Ebben a táblában csakis a publikus függvények vannak jelen, ezek érhetőek el. innen adódik, hogy minden eseményre feliratkozni kívánt függvénynek publikusnak kell lennie (azaz publicnak). NEM BAJ, ha minden függvényünk publikus, csupán több néven kell átlábalnia.
StockEz fordítási időben lényeges. Amennyiben van egy függvényünk (vagy változónk), amit nem használunk, akkor warningot dob rá a fordító. Hibát nem okoz, csupán bennehagytunk vaalmi szemetet.
Amennyiben a függvény/globális változó létrehozásakor stock-ot írunk (globális változó esetén: new helyett stock), akkor a tárgykódba csak akkor fog belefordulni, ha használva is van)
NativeEnnek segítségével teremthetünk kapcsolatot pluginjaink között. Alapesetben a pluginok nem látnak át a másik plugin függvényeibe (de elvileg public-cal deklarált globális változókat látnak, de ezzel nem foglalkozunk. Ki lehet próbálni). Ehhez lehet használni segítségül a native kulcsszót. Ez beregisztrál egy parancsot a magba, aminek meghívásakor a nativehoz rendlet PUBLIKUS függvényt fogja lefuttatni. Ez olyan, mintha magunk írnánk egy saját eseményt, amit egy másik pluginból hívunk.
A függvényt a gazda pluginban kell létrehozni, és ott kell felküldeni a magnak is. A hívó pluginban csupán jelölni kell, hogy létezni fog ilyen függvény. Ezeket szokás elhelyezni az inlcude (inc) állományokba. Természetesen az alap kódba is beírhatjuk, ha az kényelmesebb. (Hiszen tudjuk - ugye - hogy a fordító sem csinál mást)
Példa (full példák, nézzétek meg bátran)://///
// GOLLAM.sma
/////
#include <amxmodx>
public plugin_init() {
register_plugin("Gollam","1.0","Metal")
}
// Natives
public plugin_natives() {
register_native("gollam_valaszol", "native_gollam_valaszol");
}
// Natives functions implementations
public native_gollam_valaszol(plugin_id, num_params) {
new id = get_param(1);
if (!is_user_connected(id))
{
log_error(AMX_ERR_NATIVE, "[GOLLAM] Invalid Player (%d)", id);
return;
}
client_print(id, print_chat, "Nincs nalam a dlagaszak! Elloptak tolunk!!");
}
/////
// SZARUMAN.sma
/////
#include <amxmodx>
native gollam_valaszol(id);
public plugin_init() {
register_plugin("Szaruman","1.0","Metal");
register_clcmd("holagyuru", "HolaGyuru");
}
public HolaGyuru(id) {
gollam_valaszol(id);
}
UtószóKérésem lenne felétek: Akinek van ideje, nyugodtan tesztelje le, s jelezzen vissza, ha valami nem jó. Röpke 1 óra alatt tákoltam össze, tesztelni nem tudtam, de - ha minden igaz -, mindent jól írtam le.
Kérdéseket és a kekszeket várom
Üdv,
Metal