Üzenetek megjelenítése

Ez a szekció lehetővé teszi a felhasználó által írt összes hozzászólás megtekintését. Vedd figyelembe, hogy csak azokba a fórumokba írt hozzászólásokat látod, amelyekhez hozzáférésed van.


Témák - KovaNovik

Oldalak: [1]
1
Off Telep / "IRL sem ezt tennéd"
« Dátum: 2016. Augusztus 20. - 00:07:55 »
\"4EIqFUN.jpg\"

2
SA-MP: Szerverfejlesztés / Bejárat rendszer
« Dátum: 2015. Január 09. - 21:43:16 »
Ez a script a mysql táblában megadott pozíciókon lévő be- illetve kijáratok közül megkeresi a hozzád legközelebb álló, veled egy virtualworldben és egy interiorban lévőt, majd annak párjára teleportál. Ez hasznos lehet pl. ahol dinamikus rendszerre van szükség eleve meglévő interioros, vagy saját mappolású helyekre, pl. benzinkút.
A táblából élőben keresi az ajtókat, így azok menet közben is szerkeszthetőek anélkül, hogy újra kéne indítani a szervert, igaz, ez egy normális scriptnél alapfeltétel kell, hogy legyen.
Próbáltam minél erőforrás kímélőbbre tervezni, nyugodtan szóljatok, ha láttok lehetőséget optimalizálásra.
Az eredetiben, amit feltettem, egyben volt a /enter és a /exit parancs.
Íme a javított változat:
PAWN forráskód:
 

YCMD:enter(playerid, params[], help) {
if(help) return Msg(playerid, X11_LIGHTBLUE, \"Ezzel a paranccsal tudsz bemenni valamennyi lehelyezett bejáraton.\");
mysql_tquery(sqlconn, \"SELECT * FROM entries\", \"SQL_entr_enter\", \"i\", playerid);
return 1;
}
function SQL_entr_enter(playerid) {
new Float:dist, pint = GetPlayerInterior(playerid), pvw = GetPlayerVirtualWorld(playerid), Float:nst = 2.5, nstid = -1, dint, dvw;
for(new i = 0; i < cache_num_rows(); i++) {
dint = cache_get_field_content_int(i, \"intout\");
if(dint != pint) continue;
dvw = cache_get_field_content_int(i, \"vwout\");
if(dvw != pvw) continue;
dist = GetPlayerDistanceFromPoint(playerid, cache_get_field_content_float(i, \"xout\"), cache_get_field_content_float(i, \"yout\"), cache_get_field_content_float(i, \"zout\"));
if(dist <= nst) {
   nst = dist;
   nstid = i;
        }
}
if(nstid == -1) return Msg(playerid, X11_RED, \"Nincsen bejárat a közeledben!\");
SetPlayerInterior(playerid, cache_get_field_content_int(nstid, \"intin\"));
SetPlayerVirtualWorld(playerid, cache_get_field_content_int(nstid, \"vwin\"));
SetPlayerPos(playerid, cache_get_field_content_float(nstid, \"xin\"), cache_get_field_content_float(nstid, \"yin\"), cache_get_field_content_float(nstid, \"zin\"));
SetPlayerFacingAngle(playerid, cache_get_field_content_float(nstid, \"ain\"));
new capt[32];
cache_get_field_content(nstid, \"namein\", capt);
GameTextForPlayer(playerid, capt, 4500, 1);
return 1;
}
YCMD:exit(playerid, params[], help) {
if(help) return Msg(playerid, X11_LIGHTBLUE, \"Ezzel a paranccsal tudsz kimenni valamennyi lehelyezett kijáraton.\");
mysql_tquery(sqlconn, \"SELECT * FROM entries\", \"SQL_entr_exit\", \"i\", playerid);
return 1;
}
function SQL_entr_exit(playerid) {
new Float:dist, pint = GetPlayerInterior(playerid), pvw = GetPlayerVirtualWorld(playerid), Float:nst = 2.5, nstid = -1, dint, dvw;
for(new i = 0; i < cache_num_rows(); i++) {
dint = cache_get_field_content_int(i, \"intin\");
if(dint != pint) continue;
dvw = cache_get_field_content_int(i, \"vwin\");
if(dvw != pvw) continue;
dist = GetPlayerDistanceFromPoint(playerid, cache_get_field_content_float(i, \"xin\"), cache_get_field_content_float(i, \"yin\"), cache_get_field_content_float(i, \"zin\"));
if(dist <= nst) {
   nst = dist;
   nstid = i;
        }
}
if(nstid == -1) return Msg(playerid, X11_RED, \"Nincsen kijárat a közeledben!\");
SetPlayerInterior(playerid, cache_get_field_content_int(nstid, \"intout\"));
SetPlayerVirtualWorld(playerid, cache_get_field_content_int(nstid, \"vwout\"));
SetPlayerPos(playerid, cache_get_field_content_float(nstid, \"xout\"), cache_get_field_content_float(nstid, \"yout\"), cache_get_field_content_float(nstid, \"zout\"));
SetPlayerFacingAngle(playerid, cache_get_field_content_float(nstid, \"aout\"));
new capt[32];
cache_get_field_content(nstid, \"nameout\", capt);
GameTextForPlayer(playerid, capt, 4500, 1);
return 1;
}

 
Az SQL tábla szerkezete:
 
CREATE TABLE IF NOT EXISTS `entries` (
`id` int(11) NOT NULL,
  `namein` varchar(32) NOT NULL,
  `intin` int(11) NOT NULL,
  `vwin` int(11) NOT NULL,
  `xin` float NOT NULL,
  `yin` float NOT NULL,
  `zin` float NOT NULL,
  `ain` float NOT NULL,
  `nameout` varchar(32) NOT NULL,
  `intout` int(11) NOT NULL,
  `vwout` int(11) NOT NULL,
  `xout` float NOT NULL,
  `yout` float NOT NULL,
  `zout` float NOT NULL,
  `aout` float NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

 
Egy példa, melynek segítségével akár egy IG bejárat hozzáadás parancsot is létre lehet hozni:
 

INSERT INTO entries (namein, intin, vwin, xin, xin, zin, ain, nameout, intout, vwout, xout, yout, zout, aout) VALUES
(\'Planning deptartment\', 3, 0, 384.809, 173.805, 1008.38, 0, \'San Fierro\', 0, 0, -2280.12, 829.479, 53.7535, 261.864);

 
Linkek:
.pwn: [mediafire] [pastebin]
.sql: [mediafire] [pastebin]
A megadott példák alapján lehet tetszőlegesen 3dtext-eket letenni a bejáratokhoz, pickupokat, gombnyomásra aktiválást, szinte bármit.

3
Leírások/Útmutatók / MySQL R39-2, avagy mi is az threaded query?
« Dátum: 2014. Június 28. - 13:19:59 »
BlueG MySQL R39-2 ~ Tudnivalók, haszna, kezelése
Üdv mindenkinek!
Mostanában nagyon sok embert látok kérdezõsködni mindenfelé afelõl, hogy igazából hogy is kell használni ezt a plugint. Milyen kóddal tölt be adatokat, milyen kóddal ment le, mit mivel kell csinálni, egyátalán hol tudjuk külsõleg módosítani. Ezek mind-mind olyan kérdések, melyeknek jó része nem ettõl a plugintól, sokkal inkább az SQL nyelvtõl függ, hogy abban mit hogy kell csinálni. Nyilván ezt csak azután tehetjük meg, miután megtettük a szükséges elõkészületeket.
Sokan azt mondják az R39 nehéz; pedig nem. Az R6-hoz képest nagyon szokatlan (és igen, rossz is) volt az R7, de az R33-tól sokat könnyítettek a mûködésen a készítõk, így bátran tudom ajánlani azoknak, akik már a fájlkezelésû mentéssel megszenvedtek, vagy már valamennyire tapasztaltak pawn scriptelés terén.
Elõkészületek
Egy MySQL plugint használó scripthez nem elég maga a plugin és az include fájl; kell még hozzá egy SQL szerver is, melynek elküldjük a queryket (lekéréseket), de errõl majd késõbb.
MySQL szervert a legkönnyebben az XAMPP nevû programmal tudsz beüzemelni.
Windowsra ezen a linken töltheted le ezt az igen hasznos kis programot. A csomag tartalmazza az Apache szervert, a MySQL szervert és még pár, számodra felesleges dolgot. Miután letöltötted, tulajdonképpen csak párszor megnyomjuk a tovább gombot, és már települ is. Viszonylag sok idõt (~5-10 percet) vesz igénybe a telepítés.
Amíg várakozol, elkezdheted letölteni a a mysql plugint. Errõl az oldalról a legfelsõ \"Latest release\" (azaz legújabb kiadás) címkével rendelkezõ csomagok közül a windows-os változatot kell, hogy letöltsd. Kattints a \"mysql-r39-2-win.zip\" feliratú gombra a letöltéshez. Szokás szerint a plugins mappa tartalmát a plugins, a pawno/include mappa tartalmát a pawno/include mappába kell, hogy tedd. A server.cfg fájlod plugins sorába a \"mysql\", a modod elejére (az a_samp include után természetesen) pedig a \"#include a_mysql\" szót kell, hogy illeszd.
Sokaknak problémát okoz az, hogy a szerverük az MSVCP_100.dll fájl hiányára hivatkozva leáll, amikor beteszik a mysql plugint és includeot. Igen. Ennek elkerülésére innen kell leszedned a \"Download\" gombra kattintva az x86-os, 64-bites operációs rendszer esetében az x64-es verziójú csomagot, melyet a tõle balra, vele egy sorban lévõ pipa bepipálásával, majd a next gombra kattintással tehetsz meg. Ha kéri, hogy szedd le valamelyik másik ámulatbaejtõ terméküket, tiszta szívvel küldd el a fenébe a \"No thanks, take me to the download\" gomb használatával. Ezt a csomagot rendszergazdaként kell futtatni, szokásos (next-next-next-next) technikával feltelepíteni, majd örülni.
Minden bizonnyal már feltelepült az XAMPP programcsomag. A telepítés végén hagyjuk bepipálva azt a mezõt, hogy indítsa el az XAMPP Control Panelt, majd a \"Finish\" gombra kattintva fejezzük be a telepítést. Ezután megnyílik az XAMPP control panel.
Itt az Apache és a MySQL melletti Start gombot kell megnyomni. Ha \"kizöldül\" a két felirat, jól csináltuk a dolgokat. A Skype fontos, hogy be legyen zárva, és semmi más ne is foglalja ezen portokat! Így kell, kinézzen:
[hs width=368 height=233]http://i.imgur.com/bsmN9ii.png[/hs]
Query-k készítése:
Aki már PHP-ban, vagy valahol csinált queryket, az ezt átugorhatja nyugodtan!
Általánosan 4 fõ fajtája van:
 
  • INSERT: a táblába egy új sort ilesztünk be, melyen bármely értéket tetszõlegesen megadhatjuk. Ha nem adjuk meg az alapérrtelmezett értéke lesz betéve, ami alapból 0, de a phpMyAdmin-ban ezt is módosíthatjuk.

  • SELECT: a táblából megadott kritériumok szerint kiválasztunk sorokat. Ezért szuper a mysql. Egy sorral kiválaszthatsz minden rendõrt, akinek infernusa van, a tankja több mint 3/4-edig van, legalább két kulcsa van és 6 millió forintja. Képzeld el ezt fájlkezelõvel kikeresni :D

  • UPDATE: a táblában egy már meglévõ sor tartalmát frissíti, persze a megadott kritériumok szerinti sorokban.

  • DELETE: megadott kritériumok szerinti sorokat töröl a táblából. Ha csak annyit írsz, hogy DELETE jatekosok, mindent töröl!


Kezdetek
A legelsõ lépés az, hogy létrehozzuk az adatbázist, benne a táblá(ka)t, azokban az oszlopokat, melyeknek az értékei megadhatóak soronként. SQL parancsokkal közvetlenül is tehetnénk ezt, de sokkal egyszerûbb és átláthatóbb grafikus felületen keresztül tenni mindezt.
Nem fontos, de ajánlott megadni az SQL szerverünknek egy jelszót. Ezt úgy tehetjük meg, hogy felmegyünk a 127.0.0.1 (localhost) oldalra, ez igazából csak nekünk látható, mert a gépünkön fut, de természetesen ha nyitva van a 80-as port, mások is elérhetik.Ki kell választani az angol (english) nyelvet, majd a baloldalt kiválasztandó security menüpontban a \"http://localhost/security/xamppsecurity.php\" linkre kattintva elõjövõ oldalon kettõször megadni a jelszavunkat, legyen ez most \"tesztjelszo\".
Ezután menjünk fel a 127.0.0.1/phpmyadmin webhelyre. Itt felül válaszd a magyar nyelvet, felhasználónévnek írjuk be, hogy root (ez az alap felhasználó), jelszónak pedig az általunk elõbb megadott jelszót: \"tesztjelszo\". Ezután egy ilyesmi kezelõfelület fog fogadni:
[hs width=639 height=411]http://i.imgur.com/q2MK7bh.png[/hs]
Kattintsunk az adatbázisok menüpontra, itt most létrehozzuk az adatbázist. Az \"adatbázis neve\" mezõbe írjunk be neki egy nevet (pl. teszt-adatb), majd kattintsunk a létrehozás gombra. Baloldalt megjelenik amint létrehozta, kattintsunk is rá. Rögtön fel is ajánlja nekünk, hogy készítsünk egy táblát. Ezt meg is tesszük. Tábla nevének írjunk be valami egyértelmû, de nem túl hosszú, ékezetmentes nevet, pl. jatekosok. Emellett meg kell adnunk, hány mezõre lesz szükségünk. Legyen egyelõre négy. Üssünk entert. Most meg kell adnunk a mezõket, tulajdonságaikat, speciális opcióikat.
Nézzük csak:
 
  • ID: ez a mysql-nél nagyon fontos. Erre egy egyszerû indoklás van; a megkülönböztetést. Egy hiba folytán elõfordulhat kettõ egyforma név, mindenféle hiba nélkül két egyforma pénzû, frakciójú, rangú, vagy bármilyen játékosok, DE egyforma ID-jû NEM LEHET, ugyanis kicsit jobbra tekerve bepipáljuk az A_I-t (Auto Increment, azaz automatikus növelés, vagy számláló rövidítése), amivel minden létrehozott játékosnál eggyel több lesz. Ha kitörlünk egyet, akkor is megy fel és fel. INT típusúnak nyugodtan meghagyhatjuk, hiszen ez egész szám.

  • Nev: amit pawnban stringnek, itt varcharnak hívjuk. Maximális hosszt itt is meg kell adni. Ez ugye a sampban 24, de én 25-öt szoktam megadni, hogy biztosan jó legyen.

  • Jelszo: Ezt titkosítva (SHA1-el) fogjuk tárolni, ezért bármekkora hosszú is lesz, az SHA1 titkosító 40 karaktereset generál. 40 karakter hosszú VARCHAR legyen.

  • Penz: Ez lesz az elsõ változó, ami ténylegesen csinál is valamit, nem csak azonosításra és védelemre szolgál. Ezen mutatom be majd, hogy kell betölteni. Ez természetesen maradhat INT, bár gondolom aki picit is foglalkozott samp scripteléssel, az ezt már tudja.

  • X, Y, és Z: ezek egyértelmûen float típusúak lesznek, itt fogjuk majd tárolni a kilépési koordinátáit a játékosainknak.

Késõbb ugyanitt, a teszt-adatb-n belül a jatekosok táblába navigálva módosíthatjuk a szerkesztés gombra kattintva a tábla szerkezetét. Vigyázz! A modban gyarkan el lesz rontva egy-egy query, így az exportálás menüben mindig csinálj róla visszaállítást, és ha baj van, az importálás menüben pár kattintással visszaállíthatod az eredeti állapotba!
Vágjunk is bele a pawnba!
A gamemode-unkba már a dolog elején includeoltuk (beszúrtuk) az a_mysql includeot, a server.cfg-be mysql plugint, és a megfelelõ mappákba a megfelelõ fájlokat.
Elsõ soron hozzuk létre a szükséges változókat. Nem sokra lesz szükségünk.
 
  • enum eJatekosInfo {Nev[25], Penz, Float:X, Float:Y, Float:Z}
    new JatekosInfo[MAX_PLAYERS][eJatekosInfo]; - A játékos adatait tároló tömb.

  • kapcs - ebben a mysql szerver-samp szerver kapcsolatát jelölõ ID-t fogjuk tárolni. Ez azért kell, mert egyszerre több kapcsolatunk is lehet, pl. ráköthetjük a fórumunkra, hogy az utolsó hozzászólást mutassa, stb. Mindegy, nekünk egyelõre csak egy lesz.

  • query[2000] - ez a query-t fogja tárolni stringként. A query egy szöveg, ami elmondja az sql szervernek, hogy mit csináljon.

  • enum {d_reg, d_belep} - Dialogok automatikus számozása.


Amikor a játékmód elindul, csatlakoznunk kell a mysql-szerverhez. A naplózást is bekapcsoljuk, hogy lássuk, sikeres volt-e a kapcsolódás, stb. Ezeket így tesszük meg:
 
public OnGameModeInit() {
mysql_log(LOG_ALL, LOG_TYPE_HTML); //Mindent naplózzon (igen, a sikeres dolgokat is), hogy lássunk mindent. A második paraméter azt jelzi, hogy HTML-be naplózzon; így szerintem jóval átláthatóbb.
kapcs = mysql_connect(\"127.0.0.1\", \"root\", \"teszt-adatb\", \"tesztjelszo\"); //A mysql_connect visszatérési értéke a kapcsolat id, ez pont kapóra jön nekünk, beletesszük a változóba.
if(mysql_errno(kapcs) != 0) printf(\"MySQL hiba! Hibakód: %d\", mysql_errno(kapcs)); //Amennyiben a hiba kód nem 0 (azaz van hiba), írassuk ki azt.
return 1;
}

 
Amikor a játékmód bezárul le kell csatlakoznunk a mysql-szerverrõl, ezt így tehetjük meg:
 
public OnGameModeExit() {
mysql_close(kapcs); //Lezárjuk a kapcsolatot, ez csak akkor történik meg, ha minden késleltetett (threaded) query végzett. Ha nem zárnánk le, a háttérben futna tovább a kapcsolat.
return 1;
}

 
Amikor egy játékos csatlakozik, meg kell néznünk regisztrált-e. Én még létrehozom az enumot, természetesen ezt behelyettesíthetitek a saját változóitokkal.
 
public OnPlayerConnect(playerid) {
TogglePlayerSpectating(playerid, true); //eltûntetjük a spawn gombot.
for(new a; eJatekosInfo:a < eJatekosInfo; a++) JatekosInfo[playerid][eJatekosInfo:a] = 0; //Nullázzuk az enumjait, nehogy baj legyen.
GetPlayerName(playerid, JatekosInfo[playerid][Nev], 25); //Lekérjük a nevét.
if(strfind(JatekosInfo[playerid][Nev], \"_\") == -1) //Nem tartalmaz alsóvonást; egyelõre nem csinálunk semmit ,de itt akár ki is rúghatjuk.
for(new a; a < strlen(JatekosInfo[playerid][Nev]); a++) if(JatekosInfo[playerid][Nev][a] == \'_\') JatekosInfo[playerid][Nev][a] = \' \';//Végigfutunk a nevén. Ha az egyik karaktere \'_\', kicseréli \' \'-re.
mysql_format(kapcs, query, 256, \"SELECT ID,Nev FROM jatekosok WHERE Nev=\'%e\' LIMIT 1\", JatekosInfo[playerid][Nev]);
//Azért kell formázni a queryt, hogy mindig az adott játékos nevét tegye bele. Azért kell mysql_format, mert itt van a %e specifier, ami a stringnek a mysql-kompatibilitis változatát teszi a stringbe.
//Ez itt jelen esetben tulajdonképpen felesleges, azonban ezt is meg kell mutatnom valahol; ilyen %e-t kell mindenhova, ahol a felhasználó által változtatható szöveget formázunk bele, pl. egy bugjelentés dialognál a beírt szöveg. Na ott kihasználhatná ezt, %e kéne, itt speciel felesleges. A limit 1 azért van ott, hogy ha 250 játékos közül a másodikban megtalálta õt, akkor ne nézze tovább, több után kutatva, mert mi nekünk csak egyre lesz szükségünk. De arra nagyon.
mysql_tquery(kapcs, query, \"RegEllenorzes\", \"d\", playerid); //A \"kapcs\" id-jû kapcsolatra elküldjük a fent megformázott queryt. megadjuk neki, hogy a query befejezése után a RegEllenorzes eljárásra ugorjon. A \"d\" az eljárás paramétereinek a formátuma (ugyanúgy adható meg mint a SetTimerEx-nél például), a playerid pedig, hogy kit ellenõriztünk.
return 1;
}

 
Ahol meghívjuk a query lefutása után az eljárásainkat, az alá szoktam tenni az eljárásokat, hogy rögtön mellette lássam. Íme a fent meghívott:
 
forward RegEllenorzes(playerid);
public RegEllenorzes(playerid) {
new sorok_szama = cache_get_row_count(); //A sorok_szama változóba lekérjük, hány sort talált. Mint fentebb is beszéltük, ha 0, nincs regelve, ha 1, igen.
if(sorok_szama == 0) ShowPlayerDialog(playerid, d_reg, DIALOG_STYLE_PASSWORD, \"Regisztráció\", \"{FFFFFF}Üdv a szerveren!\\nMég nem regisztráltál!\\nKérlek adj meg egy megjegyezhetõ és erõs jelszót!\", \"Regisztrál!\", \"Kilép!\");
else ShowPlayerDialog(playerid, d_belep, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"{FFFFFF}Üdv a szerveren!\\nMár regisztráltál!\\n\\nKérlek add meg a jelszavad, amivel regisztráltált!\", \"Regisztrál!\", \"Kilép!\");
return 1;
}

 
Amikor egy játékos kilép, el kell mentenünk az adatait, a következõképpen:
 
public OnPlayerDisconnect(playerid, reason) {
GetPlayerPos(playerid, JatekosInfo[playerid][X], JatekosInfo[playerid][Y], JatekosInfo[playerid][Z]);
mysql_format(kapcs, query, 384, \"UPDATE jatekosok SET Penz=\'%d\',X=\'%f\',Y=\'%f\',Z=\'%f\' WHERE Nev=\'%s\'\", JatekosInfo[playerid][Penz], JatekosInfo[playerid][X], JatekosInfo[playerid][Y], JatekosInfo[playerid][Z], JatekosInfo[playerid][Nev]);
mysql_tquery(kapcs, query);
return 1;
}

 
A threaded query (mysql_tquery) azért jó, mert elküldjük neki, várólistára helyezi, és futhat tovább a kód, nem akad be 6 másodpercre, mint a réginél például. Majd a háttérben lefut (lehet, hogy kicsivel késõbb), ezt nem tudhatjuk mikor, éppen emiatt meg kell adnunk egy eljárást, ami meghívódik, ha lefutott a query. Így biztosan kérhetünk le adatokat, annak veszélye nélkül, hogy 0-kat kapunk vissza, vagy valami más hiba fellép. És még gyorsabb is.
Pontosabban:
Egy jobb magyarázat a threaded queryre, hatalmas köszönet érte Anthony-nak:
 
Idézetet írta: Anthony date=1409221133\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"49083\" data-ipsquote-contentclass=\"forums_Topic
Ezt a threaded query dolgot tegyük rendbe, mert azért ez kicsit érdekesen van leírva.
Elõször is a threadet magyarul \"szál\"nak szokás fordítani. Mi is egy szál? Gyakorlatilag tekinthetõ egy-egy önálló programnak. Azt azért a nagy többség tudja, hogy manapság a processzorok több szálon képesek programokat futtatni, ezt párhuzamos szálkezelésnek, vagy angolul multithreadingnek hívjuk. Egy processzor alapesetben annyi szálat tud kezelni, ahány processzormag található benne (ez így teljesen nem igaz már manapság, de most képzeljük azt hogy így van). Ha nekünk több szálon fut a programunk(/programjaink) mint ahány processzor magunk van, akkor a processzor idõ megoszlik a szálak között. Ezt általában az oprendszerek oldják meg, vagy fordításkor belekerül a programkódba. Na tehát mire is jó ez akkor konkrétan, ha külön szálakra helyezzük a programjaink bizonyos részét?
- programunk felgyorsítása, lassabb részek külön szálra helyezése, háttérben futtatása -> nem kell várnunk az eredményre, a \"fõ\" programunk tovább futhat (pl. bizonyos programrészletek háttérben való betöltése)
- bizonyos programrészek \"pihentetése\" (sleep, wait, vagy várakozás valamilyen eseményre)
A többszálú kezelés fõ elõnye tehát, hogy különbözõ háttérfolyamatokat indíthatunk, vagy a programunkat szétválaszthatjuk több egymástól független szálra, az elvégzendõ feladat tekintetében (pl. egy multi-client socket szerver esetén minden felhasználó számára saját threaded érdemes biztosítani, valamint egy threadet a bejövõ kapcsolatoknak, így mindenki \"programrészlete\" a többiekétõl függetlenül tud futni, nem kell egymásra várakozni). A különbözõ szálak, még ha az egyik végtelen ciklusba is futna, akkor sem fogják egymást akadályozni a végrehajtódásban (maximum a végrehajtás sebességét befolyásolja).
Esetünkben a threaded query értelme, hogy nem szükséges megvárnunk az eredményt. Pl. nagy szerverek esetén OnGameModeInit alatt meghívunk egy 2000 rakordot érintõ lekérdezést, és hagyjuk futni egy másik szálon, miközben a szerver a többi dolog betöltésével foglalatoskodik.
DE szó nincs semmiféle várólistáról. A szálak párhuzamosan hajtódnak végre, nem pedig egymás után, annak pont ugyanúgy semmi értelme nem lenne, mint az egyszálú programkezelésnek, hisz ugyanúgy egyetlen program lefoglalná a teljes CPU-t.
Valamint, ennek semmi köze ahhoz, hogy mivel tér vissza az SQL lekérésünk. Ettõl még kaphatunk vissza 0-t, vagy errort, a többszálúsításnak kizárólag a végrehajtódás sebességére, és a programrészek egymástól független futására van kihatása, de ezen kívül semmi másra. (Igazából nem is nagyon értem hogy itt mire értetted hogy nem kapunk 0-t eredményül)
 
Csakis akkor kell eljárást (3. paramétertõl) megadni, ha szeretnénk tudni a query ereményét. Pl. kiválasztottuk a játékost. Itt szeretnénk tudni, ugyanis kíváncsiak vagyunk, hogy van-e találat (ezesetben már regisztrálva van), vagy nincs (nincs ilyen sor, ahol a név az õ neve).
Pl. egy insert querynél nem igazán leszünk kíváncsiak az eredményre, viszont lehet, hogy pont a query lefutása   után szeretnénk lefuttatni egy másik kódot; ezesetben is kell majd az eljárás.
Egy UPDATE querynél is ugyanaz a helyzet mint az insertnél.
A DELETE-nél is. Ha meg szeretnénk tudni, hány sor törlõdött ((vagy akár a fenti kettõnél beszúródott, vagy frissült), ld. cache_affected_rows()), akkor adjunk meg eljárást; egyébként minek?
Kezdõdjenek az eljárások és a dialogresponse rész:
 
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) {
switch(dialogid) {
case d_reg: {
   if(!response) return Kick(playerid);
   if(strlen(inputtext) < 5 || strlen(inputtext) > 32) return ShowPlayerDialog(playerid, d_reg, DIALOG_STYLE_PASSWORD, \"Regisztráció\", \"{FFFFFF}Üdv a szerveren!\\nMég nem regisztráltál!\\nKérlek adj meg egy megjegyezhetõ és erõs jelszót!\\n\\n{FF0000}Jelszavadnak 5-32 karakter között kell lennie!\", \"Regisztrál!\", \"Kilép!\");
   mysql_format(kapcs, query, 256, \"INSERT INTO jatekosok (Nev,Jelszo,Penz,X,Y,Z) VALUES (\'%e\',SHA1(\'%e\'),\'185000\',-1980.6168,141.2433,27.6875)\", JatekosInfo[playerid][Nev], inputtext);
   mysql_tquery(kapcs, query, \"JatekosBeregelt\", \"d\", playerid);
}
case d_belep: {
   if(!response) return Kick(playerid);
   if(strlen(inputtext) < 5 || strlen(inputtext) > 32) return ShowPlayerDialog(playerid, d_belep, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"{FFFFFF}Üdv a szerveren!\\nMár regisztráltál!\\nKérlek add meg a jelszavad, amivel regisztráltáltál!\\n\\n{FF0000}Jelszavadnak 5-32 karakter között kell lennie!\", \"Regisztrál!\", \"Kilép!\");
   mysql_format(kapcs, query, 256, \"SELECT * FROM jatekosok WHERE Nev=\'%e\' AND Jelszo=SHA1(\'%e\')\", JatekosInfo[playerid][Nev], inputtext);
   mysql_tquery(kapcs, query, \"JatekosBelep\", \"d\", playerid);
   //Jatekosunk megpróbált belépni \'inputtext\' jelszóval. Kiválasztottuk a sorokat, ahol a név a játékos neve, a jelszó a beírt szöveg titkosított változata. Folytatás a callbackben.
}
}
return 0;
}
forward JatekosBeregelt(playerid);
public JatekosBeregelt(playerid) {
SendClientMessage(playerid, 0xFFFFFFFF, \"Sikeresen regisztráltál!\");
SetSpawnInfo(playerid, 0, 7, -1980.6168, 141.2433, 27.6875, 90.0, 0, 0, 0, 0, 0, 0); //Beállítjuk a spawn pozíciót, skint egyebeket.
TogglePlayerSpectating(playerid, false); //Elõhozzuk a spawn gombot, hogy így le tudja spawnolni a szerver.
SpawnPlayer(playerid); //Lespawnoljuk.
JatekosInfo[playerid][Penz] = 185000;
SendClientMessage(playerid, 0xFFFFFFFF, \"Jó játékot kívánok!\");
return 1;
}
forward JatekosBelep(playerid);
public JatekosBelep(playerid) {
new sorok_szama = cache_get_row_count(); //A sorok_szama változóba lekérjük, hány sort talált. Ha 0, nem jó a jelszó, ha 1 igen, mert van olyan (1) sor, amelynél ez a név és a jelszó is.
if(sorok_szama == 0) return ShowPlayerDialog(playerid, d_belep, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"{FFFFFF}Üdv a szerveren!\\nJatekosInfo regisztráltál!Kérlek add meg a jelszavad, amivel regisztráltált!\\n\\n{FF0000}Hibás jelszó!\", \"Regisztrál!\", \"Kilép!\");
//Az elõbb, ha hibás volt a jelszó visszatértünk volna, szóval innenztõl ami lefut kód, az már jó jelszóval fut le:
SendClientMessage(playerid, 0xFFFFFFFF, \"Sikeresen bejelentkeztél!\");
SetSpawnInfo(playerid, 0, 7, cache_get_field_content_float(0, \"X\"), cache_get_field_content_float(0, \"Y\"), cache_get_field_content_float(0, \"Z\"), 90.0, 0, 0, 0, 0, 0, 0); //Beállítjuk a spawn pozíciót, skint egyebeket.
TogglePlayerSpectating(playerid, false); //Elõhozzuk a spawn gombot, hogy így le tudja spawnolni a szerver.
SpawnPlayer(playerid); //Lespawnoljuk.
JatekosInfo[playerid][Penz] = cache_get_field_content_int(0, \"Penz\"); //A 0. sorból (a legelsõ, mivel csak 1 találat van, a játékos, akit kerestünk) a pénz oszlop tartalmát integerként (egész számként) lekérjük, és beletesszük a JatekosInfo[playerid][Penz] változóba.
new string[128]; format(string, sizeof(string), \"Pénzed: %dFt.\", JatekosInfo[playerid][Penz]);
SendClientMessage(playerid, 0xFFFFFFFF, \"Üdv újra itt!\");
return 1;
}

 
Változókat (természetesen csakis select query után) így kérhetsz le a kapott sorokból:
- Sor- és oszlopszám szerint:
Ezek akkor lehetnek hasznosak, ha egy ciklussal végig akarunk futni egy játékos minden oszlopán, és pl. kiíratni azokat.
 
cache_get_row(0, 1, string); //1. sor 2. oszlopának lekérése (0-tól indul a számozás ugye), a string nevû karakterláncba.
JatekosInfo[playerid][Penz] = cache_get_row_int(0, 3); //1. sor 4. oszlopának lekérése (pénz) lekérése. Ennek a visszatérési értéke maga a kapott érték, szóval elé kell írni, mely változóba akarjuk tenni.
JatekosInfo[playerid][Elet] = cache_get_row_float(0, 3); //1. sor 4. oszlopának lekérése floatként, a játékos élet változójába.


Például:
 
new string[128], oszlopnev[64], tartalom[64];
for(new i = 0; i < cache_get_field_count(); i++) {//Addig növeljük az i-t, amíg el nem éri az oszlopok számát, azaz végigfutunk minden oszlopon.
cache_get_field_name(i, oszlopnev);
cache_get_row(0, i, tartalom);
format(string, sizeof(string), \"%s: %s\", oszlopnev, tartalom);
SendClientMessage(playerid, 0xFFFFFFFF, string);
}

 
A fenti példa, akárhány oszlopod is van, kiíratja mindet.
- Sorszám és oszlopnév alapján:
 
cache_get_field_content
cache_get_field_content_int
cache_get_field_content_float

 
Ezek ugyanúgy mûködnek, mint a fentebb lévõ három, annyi különbséggel, hogy itt oszlopszám helyett a nevét kell megadni. Ez jobb, ha nem ciklusban használjuk, és nem szeretnénk, hogy elcsússzon az egész egy oszlop beillesztése miatt, hiszen a név nem változik olyankor, csak a sorszám.
Tehát az SQL tábla így néz ki:
 
CREATE TABLE IF NOT EXISTS `jatekosok` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Nev` varchar(25) NOT NULL,
  `Jelszo` varchar(40) NOT NULL,
  `Penz` int(11) NOT NULL,
  `X` float NOT NULL,
  `Y` float NOT NULL,
  `Z` float NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

 
A script egészben:
 
#include a_samp
#include a_mysql
main(){}
enum eJatekosInfo {Nev[25], Penz, Float:X, Float:Y, Float:Z}
new JatekosInfo[MAX_PLAYERS][eJatekosInfo];
new kapcs, query[2000];
enum {d_reg, d_belep} //Dialogok automatikus számozása.
public OnGameModeInit() {
mysql_log(LOG_ALL, LOG_TYPE_HTML); //Mindent naplózzon (igen, a sikeres dolgokat is), hogy lássunk mindent. A második paraméter azt jelzi, hogy HTML-be naplózzon; így szerintem jóval átláthatóbb.
kapcs = mysql_connect(\"127.0.0.1\", \"root\", \"teszt-adatb\", \"tesztjelszo\"); //A mysql_connect visszatérési értéke a kapcsolat id, ez pont kapóra jön nekünk, beletesszük a változóba.
if(mysql_errno(kapcs) != 0) printf(\"MySQL hiba! Hibakód: %d\", mysql_errno(kapcs)); //Amennyiben a hiba kód nem 0 (azaz van hiba), írassuk ki azt.
return 1;
}
public OnGameModeExit() {
mysql_close(kapcs); //Lezárjuk a kapcsolatot, ez csak akkor történik meg, ha minden késleltetett (threaded) query végzett.HTTP Ha nem zárnánk le, a háttérben futna tovább a kapcsolat.
return 1;
}
public OnPlayerConnect(playerid) {
TogglePlayerSpectating(playerid, true); //eltûntetjük a spawn gombot.
for(new a; eJatekosInfo:a < eJatekosInfo; a++) JatekosInfo[playerid][eJatekosInfo:a] = 0; //Nullázzuk az enumjait, nehogy baj legyen.
GetPlayerName(playerid, JatekosInfo[playerid][Nev], 25); //Lekérjük a nevét.
if(strfind(JatekosInfo[playerid][Nev], \"_\") == -1) //Nem tartalmaz alsóvonást; egyelõre nem csinálunk semmit ,de itt akár ki is rúghatjuk.
for(new a; a < strlen(JatekosInfo[playerid][Nev]); a++) if(JatekosInfo[playerid][Nev][a] == \'_\') JatekosInfo[playerid][Nev][a] = \' \';//Végigfutunk a nevén. Ha az egyik karaktere \'_\', kicseréli \' \'-re.
mysql_format(kapcs, query, 256, \"SELECT ID,Nev FROM jatekosok WHERE Nev=\'%e\' LIMIT 1\", JatekosInfo[playerid][Nev]);
//Azért kell formázni a queryt, hogy mindig az adott játékos nevét tegye bele. Azért kell mysql_format, mert itt van a %e specifier, ami a stringnek a mysql-kompatibilitis változatát teszi a stringbe.
//Ez itt jelen esetben tulajdonképpen felesleges, azonban ezt is meg kell mutatnom valahol; ilyen %e-t kell mindenhova, ahol a felhasználó által változtatható szöveget formázunk bele, pl. egy bugjelentés dialognál a beírt szöveg. Na ott kihasználhatná ezt, %e kéne, itt speciel felesleges. A limit 1 azért van ott, hogy ha 250 játékos közül a másodikban megtalálta õt, akkor ne nézze tovább, több után kutatva, mert mi nekünk csak egyre lesz szükségünk. De arra nagyon.
mysql_tquery(kapcs, query, \"RegEllenorzes\", \"d\", playerid); //A \"kapcs\" id-jû kapcsolatra elküldjük a fent megformázott queryt. megadjuk neki, hogy a query befejezése után a RegEllenorzes eljárásra ugorjon. A \"d\" az eljárás paramétereinek a formátuma (ugyanúgy adható meg mint a SetTimerEx-nél például), a playerid pedig, hogy kit ellenõriztünk.
return 1;
}
forward RegEllenorzes(playerid);
public RegEllenorzes(playerid) {
new sorok_szama = cache_get_row_count(); //A sorok_szama változóba lekérjük, hány sort talált. Mint fentebb is beszéltük, ha 0, nincs regelve, ha 1, igen.
if(sorok_szama == 0) ShowPlayerDialog(playerid, d_reg, DIALOG_STYLE_PASSWORD, \"Regisztráció\", \"{FFFFFF}Üdv a szerveren!\\nMég nem regisztráltál!\\nKérlek adj meg egy megjegyezhetõ és erõs jelszót!\", \"Regisztrál!\", \"Kilép!\");
else ShowPlayerDialog(playerid, d_belep, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"{FFFFFF}Üdv a szerveren!\\nMár regisztráltál!\\n\\nKérlek add meg a jelszavad, amivel regisztráltált!\", \"Regisztrál!\", \"Kilép!\");
return 1;
}
public OnPlayerDisconnect(playerid, reason) {
GetPlayerPos(playerid, JatekosInfo[playerid][X], JatekosInfo[playerid][Y], JatekosInfo[playerid][Z]);
mysql_format(kapcs, query, 384, \"UPDATE jatekosok SET Penz=\'%d\',X=\'%f\',Y=\'%f\',Z=\'%f\' WHERE Nev=\'%s\'\", JatekosInfo[playerid][Penz], JatekosInfo[playerid][X], JatekosInfo[playerid][Y], JatekosInfo[playerid][Z], JatekosInfo[playerid][Nev]);
mysql_tquery(kapcs, query);
return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) {
switch(dialogid) {
case d_reg: {
   if(!response) return Kick(playerid);
   if(strlen(inputtext) < 5 || strlen(inputtext) > 32) return ShowPlayerDialog(playerid, d_reg, DIALOG_STYLE_PASSWORD, \"Regisztráció\", \"{FFFFFF}Üdv a szerveren!\\nMég nem regisztráltál!\\nKérlek adj meg egy megjegyezhetõ és erõs jelszót!\\n\\n{FF0000}Jelszavadnak 5-32 karakter között kell lennie!\", \"Regisztrál!\", \"Kilép!\");
   mysql_format(kapcs, query, 256, \"INSERT INTO jatekosok (Nev,Jelszo,Penz,X,Y,Z) VALUES (\'%e\',SHA1(\'%e\'),\'185000\',-1980.6168,141.2433,27.6875)\", JatekosInfo[playerid][Nev], inputtext);
   mysql_tquery(kapcs, query, \"JatekosBeregelt\", \"d\", playerid);
}
case d_belep: {
   if(!response) return Kick(playerid);
   if(strlen(inputtext) < 5 || strlen(inputtext) > 32) return ShowPlayerDialog(playerid, d_belep, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"{FFFFFF}Üdv a szerveren!\\nMár regisztráltál!\\nKérlek add meg a jelszavad, amivel regisztráltáltál!\\n\\n{FF0000}Jelszavadnak 5-32 karakter között kell lennie!\", \"Regisztrál!\", \"Kilép!\");
   mysql_format(kapcs, query, 256, \"SELECT * FROM jatekosok WHERE Nev=\'%e\' AND Jelszo=SHA1(\'%e\')\", JatekosInfo[playerid][Nev], inputtext);
   mysql_tquery(kapcs, query, \"JatekosBelep\", \"d\", playerid);
   //Jatekosunk megpróbált belépni \'inputtext\' jelszóval. Kiválasztottuk a sorokat, ahol a név a játékos neve, a jelszó a beírt szöveg titkosított változata. Folytatás a callbackben.
}
}
return 0;
}
forward JatekosBeregelt(playerid);
public JatekosBeregelt(playerid) {
SendClientMessage(playerid, 0xFFFFFFFF, \"Sikeresen regisztráltál!\");
SetSpawnInfo(playerid, 0, 7, -1980.6168, 141.2433, 27.6875, 90.0, 0, 0, 0, 0, 0, 0); //Beállítjuk a spawn pozíciót, skint egyebeket.
TogglePlayerSpectating(playerid, false); //Elõhozzuk a spawn gombot, hogy így le tudja spawnolni a szerver.
SpawnPlayer(playerid); //Lespawnoljuk.
JatekosInfo[playerid][Penz] = 185000;
SendClientMessage(playerid, 0xFFFFFFFF, \"Jó játékot kívánok!\");
return 1;
}
forward JatekosBelep(playerid);
public JatekosBelep(playerid) {
new sorok_szama = cache_get_row_count(); //A sorok_szama változóba lekérjük, hány sort talált. Ha 0, nem jó a jelszó, ha 1 igen, mert van olyan (1) sor, amelynél ez a név és a jelszó is.
if(sorok_szama == 0) return ShowPlayerDialog(playerid, d_belep, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"{FFFFFF}Üdv a szerveren!\\nJatekosInfo regisztráltál!Kérlek add meg a jelszavad, amivel regisztráltált!\\n\\n{FF0000}Hibás jelszó!\", \"Regisztrál!\", \"Kilép!\");
//Az elõbb, ha hibás volt a jelszó visszatértünk volna, szóval innenztõl ami lefut kód, az már jó jelszóval fut le:
SendClientMessage(playerid, 0xFFFFFFFF, \"Sikeresen bejelentkeztél!\");
SetSpawnInfo(playerid, 0, 7, cache_get_field_content_float(0, \"X\"), cache_get_field_content_float(0, \"Y\"), cache_get_field_content_float(0, \"Z\"), 90.0, 0, 0, 0, 0, 0, 0); //Beállítjuk a spawn pozíciót, skint egyebeket.
TogglePlayerSpectating(playerid, false); //Elõhozzuk a spawn gombot, hogy így le tudja spawnolni a szerver.
SpawnPlayer(playerid); //Lespawnoljuk.
JatekosInfo[playerid][Penz] = cache_get_field_content_int(0, \"Penz\"); //A 0. sorból (a legelsõ, mivel csak 1 találat van, a játékos, akit kerestünk) a pénz oszlop tartalmát integerként (egész számként) lekérjük, és beletesszük a JatekosInfo[playerid][Penz] változóba.
new string[128]; format(string, sizeof(string), \"Pénzed: %dFt.\", JatekosInfo[playerid][Penz]);
SendClientMessage(playerid, 0xFFFFFFFF, \"Üdv újra itt!\");
return 1;
}

 
A script ingame:
[videó]
Nos ennyi lenne, a fõbb részeket bemutattam a pawn-os részérõl, kicsit bele is mentünk az SQL nyelvezetébe, habár fõként nem ez akart lenni a célja a tutorialnak.
Ha van valami kérdésetek (vagy hiba a kódban, ez simán lehetséges), nyugodtan írjátok le, viszont miután megtanultátok, hogy kell használni a pawn scriptben a plugin segítségével az SQL nyelvet, onnantól csak arra lesz szükségetek.
Pl. nem tudom, hogy kell insert queryt csinálni.
Google: mysql insert query examples.
Elsõ találat elsõ bekezdésében:
 

INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)

 
[/quote]
Megjegyzés: a modban sokkal jobb, hogyha mondjuk egy Whirlpool pluginnal generálod a jelszó hash-t, és azt illeszted be a querybe. Hostolt szervereken különösen nem érdemes a querybe illeszteni a jelszót magát, mert így az SQL logból bárki kilophatja!
Köszönöm, hogy elolvastátok az útmutatómat, mindenkinek sok szerencsét, és további jó scriptelést! :thumbsup:

4
Fórum Archívum (Témák/Fórumok) / Re:MySql plugin
« Dátum: 2014. Június 25. - 22:42:32 »
Tekerj lentebb bro XD

5
Segítségkérés / MySQL - Az ORM ment, de nem tölt be
« Dátum: 2014. Április 13. - 11:58:01 »
Sziasztok! Egy igen furcsa problémával fordulnék most hozzátok. Nemrég elkezdtem írni egy játékmódot, amiben úgy döntöttem, hogy a BlueG által készített R38-as plugint fogom használni. ORM-et használok, mert ezzel egyszerûbb menteni / betölteni, hiszen automatikusan legenerálja a queryket.
Ezt maga maddinat0r, a plugin készítõje írta:
\"rmhn6kJ.jpg\"
A játékos adatait enumokban tartom, és lecsatlakozáskor elmentem az adatbázisba.
A függvénykönyvtárak, melyeket használok:
 

#include <a_samp>
#include <sscanf2>
#include <zcmd>
#include <streamer>
#include <a_mysql>
#include <crashdetect>

 
A makrók, amiket használok:
 

#define fuggveny%0(%1) forward%0(%1); public%0(%1)

 
A játékosok adatait tartalmazó enum így néz ki:
 

enum eJatAd
{
ORM:ORMSzam,
ABSzam,
Belepve,
ProcSzam[256],
AdminSzint,
Nev[MAX_PLAYER_NAME+1],
KiirNev[MAX_PLAYER_NAME+1],
Jelszo[32],
Fagyasztva,
Kinezet,
Penz,
Float:Elet,
Float:Melleny,
Vilag,
Belso,
Float:KoordX,
Float:KoordY,
Float:KoordZ,
Float:KoordF,
}
new JatAd[LegfJatekos][eJatAd];

 
Megjegyz. (csak, hogy értsétek minden részét): a \"LegfJatekos\" \"MAX_PLAYERS\"-ként van definiálva. A SimaUzenet függvény csak 3 sorrá darabolja az SCM-et, mert így használhatóbb számomra. Az UzenetMindenki függvény pedig csak a belépett játékosoknak küldi el az üzenetet. A Kirug függvény egy késleltetett kick, a KirugIndok és KirugIndokNev pedig ír mellé indokot is. Ezek mellett az Uzenet függvény az a Y_Less által készített fajta, ami lényegében egy SendFormatMessage, ami nem csak define, hanem függvény, így bõvíthetõ több argumentummal. Az UzenetMindenki függvény ugyanez, csak mindenkinek elküldi. A Lefagyaszt és Kiolvaszt függvény csak egy fagyasztás, és kiolvasztás, annyi különbséggel, hogy itt a változóját is átállítja, ami késõbb lesz használva olyan helyeken, ahol fagyasztástól függ a script.
Nos, bele is kezdenék a játékmódba:
 

public OnGameModeInit()
{
    mysql_log(LOG_ALL, LOG_TYPE_HTML);
    ABKapcs = mysql_connect(ABHoszt, ABFelh, ABAd, ABJelsz);
    return 1;
}
public OnGameModeExit()
{
SimaUzenetMindenki(Feher, \"A szerver leállítása folyamatban...\");
    for(new a = 0; a < LegfJatekos; a++)
    {
        if(JatAd[a][belepve] == 1 && JatAd[a][ABSzam] != 0) MentJatAd(a);
    }
    mysql_close(ABKapcs);
return 1;
}
    //Itt lekéri a szériaszámát, és megnézi RP-s-e a neve. Ha igen, akkor kiveszi belõle az alsóvonást, és beleteszi mindezt a KiirNev változójába.
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][ABSzam], \"ABSzam\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][belepve], \"Belepve\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][AdminSzint], \"AdminSzint\");
    orm_addvar_string(JatAd[playerid][ORMSzam], JatAd[playerid][Nev], MAX_PLAYER_NAME+1, \"Nev\");
    orm_addvar_string(JatAd[playerid][ORMSzam], JatAd[playerid][KiirNev], MAX_PLAYER_NAME+1, \"KiirNev\");
    orm_addvar_string(JatAd[playerid][ORMSzam], JatAd[playerid][Jelszo], MAX_PLAYER_NAME+1, \"Jelszo\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][Fagyasztva], \"Fagyasztva\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][Kinezet], \"Kinezet\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][Penz], \"Penz\");
    orm_addvar_float(JatAd[playerid][ORMSzam], JatAd[playerid][Elet], \"Elet\");
    orm_addvar_float(JatAd[playerid][ORMSzam], JatAd[playerid][Melleny], \"Melleny\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][Vilag], \"Vilag\");
    orm_addvar_int(JatAd[playerid][ORMSzam], JatAd[playerid][belso], \"Belso\");
    orm_addvar_float(JatAd[playerid][ORMSzam], JatAd[playerid][KoordX], \"KoordX\");
    orm_addvar_float(JatAd[playerid][ORMSzam], JatAd[playerid][KoordY], \"KoordY\");
    orm_addvar_float(JatAd[playerid][ORMSzam], JatAd[playerid][KoordZ], \"KoordZ\");
    orm_addvar_float(JatAd[playerid][ORMSzam], JatAd[playerid][KoordF], \"KoordF\");
    orm_setkey(JatAd[playerid][ORMSzam], \"ABSzam\");
    orm_select(JatAd[playerid][ORMSzam], \"AmikorJatAdBet\", \"d\", playerid);
}

 
És most jön a \"problémás rész\", azért idézõjelben, mert tudom, hogy nem itt van a probléma, de itt látszik meg.
 

fuggveny AmikorJatAdBet(playerid)
{
switch(orm_errno(JatAd[playerid][ORMSzam]))
    {
        case ERROR_OK: ShowPlayerDialog(playerid, BelepDialog, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"Kérlek írd be a jelszavadat.\", \"Belép!\", \"Kilép!\");
        case ERROR_NO_DATA: ShowPlayerDialog(playerid, RegisztrDialog, DIALOG_STYLE_PASSWORD, \"Regisztráció\", \"Kérlek írd be a jelszavadat.\", \"Regisztrál!\", \"Kilép!\");
    }
    Uzenet(playerid, Feher, \"ABSzam: %d | ORMSzam: %d  | Nev: %s | KiirNev: %s | Jelszo: %s | Kinezet: %d | Penz: %d | Elet: %f | Melleny: %f...\", JatAd[playerid][ABSzam], JatAd[playerid][ORMSzam], JatAd[playerid][KiirNev], JatAd[playerid][Jelszo], JatAd[playerid][Kinezet], JatAd[playerid][Penz], JatAd[playerid][Elet], JatAd[playerid][Melleny]);
}

 
Megjegyz: A végén az üzenet azért van ott, hogy kiírja, hogy tényleg 0-k-e az adatai, és azért hozza be mindig a regisztrációs dialogot, hát.. igen.
A dialogoknál:
 

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch(dialogid)
{
case RegisztrDialog:
{
   if(!response) return Kirug(playerid);
   if(4 > strlen(inputtext) || strlen(inputtext) > 24) return ShowPlayerDialog(playerid, RegisztrDialog, DIALOG_STYLE_PASSWORD, \"Regisztráció\", \"Kérlek írd be a jelszavadat. \\n A jelszavadnak 0-24 karakter között kell lennie!\", \"Regisztrál!\", \"Kilép!\");
            new TitkJelsz[129];
            WP_Hash(TitkJelsz, sizeof(TitkJelsz), inputtext);
   format(JatAd[playerid][Jelszo], 24, \"%s\", TitkJelsz);
   RegisztrJat(playerid);
}
case BelepDialog:
{
   if(!response) return Kirug(playerid);
   if(4 > strlen(inputtext) || strlen(inputtext) > 24) return ShowPlayerDialog(playerid, BelepDialog, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"Kérlek írd be a jelszavadat. \\n A jelszavadnak 0-24 karakter között kell lennie!\", \"Belép!\", \"Kilép!\");
   new TitkJelsz[129];
   WP_Hash(TitkJelsz, sizeof(TitkJelsz), inputtext);
   if(strcmp(JatAd[playerid][Jelszo], TitkJelsz) != 0) return ShowPlayerDialog(playerid, BelepDialog, DIALOG_STYLE_PASSWORD, \"Bejelentkezés\", \"Kérlek írd be a jelszavadat. \\n Az általad beírt jelszó hibás!\", \"Belép!\", \"Kilép!\");
            BelepJat(playerid);
}
}
return 1;
}

 
Íme a RegisztrJat, a BelepJat, és a függvények, melyeket azok használnak:
 

stock RegisztrJat(playerid)
{
SetSpawnInfo(playerid, 0, 7, 1743.0239, -1864.4617, 13.5738, 0, 0, 0, 0, 0, 0, 0);
SpawnPlayer(playerid);
JatAd[playerid][belepve] = 1;
    printf(\"%s beregisztrált a szerverre.\", JatAd[playerid][KiirNev]);
SimaUzenet(playerid, Feher, \"Sikeresen regisztráltál a kSAMP szerverére!\");
JatAd[playerid][Penz] = 185000;
SimaUzenet(playerid, Feher, \"Kezdésnek kaptál az államtól 185.000Ft-ot!\");
orm_save(JatAd[playerid][ORMSzam], \"MentJatAd\", \"d\", playerid);
}
stock BelepJat(playerid)
{
    JatAd[playerid][belepve] = 1;
printf(\"%s belépett a szerverre.\", JatAd[playerid][KiirNev]);
    SimaUzenet(playerid, Feher, \"Sikeresen beléptél a kSAMP szerverére!\");
BeallJatAd(playerid);
//TogglePlayerSpectating(playerid, false);
JatAd[playerid][belepve] = 1;
SimaUzenet(playerid, Feher, \"Sikeresen bejelentkeztél! Jó játékot!\");
MentJatAd(playerid);
}
fuggveny MentJatAd(playerid)
{
    JatAd[playerid][Kinezet] = GetPlayerSkin(playerid);
GetPlayerHealth(playerid, JatAd[playerid][Elet]);
GetPlayerArmour(playerid, JatAd[playerid][Melleny]);
JatAd[playerid][Vilag] = GetPlayerVirtualWorld(playerid);
JatAd[playerid][belso] = GetPlayerInterior(playerid);
GetPlayerPos(playerid, JatAd[playerid][KoordX], JatAd[playerid][KoordY], JatAd[playerid][KoordZ]);
GetPlayerFacingAngle(playerid,  JatAd[playerid][KoordF]);
orm_save(JatAd[playerid][ORMSzam]);
}
fuggveny BeallJatAd(playerid)
{
SetSpawnInfo(playerid, 0, JatAd[playerid][Kinezet], JatAd[playerid][KoordX], JatAd[playerid][KoordY], JatAd[playerid][KoordZ], JatAd[playerid][KoordF], 0, 0, 0, 0, 0, 0);
SpawnPlayer(playerid);
SetPlayerHealth(playerid, JatAd[playerid][Elet]);
SetPlayerArmour(playerid, JatAd[playerid][Melleny]);
SetPlayerVirtualWorld(playerid, JatAd[playerid][Vilag]);
SetPlayerInterior(playerid, JatAd[playerid][belso]);
//Fegyverek hozzáadása
printf(\"%s adatai beállítva  megfelelõ értékre!\", JatAd[playerid][KiirNev]);
}

 
Már 1000 féleképpen próbáltam, de nem megy.
Ha csak a bejelentkezés dialogot hozom ki, akkor sem lépteti be teljesen, illetve belépteti, csak 0-s adatokkal, ami nem egészen jó.
Az adatbázisban teljesen jól beteszi az adatokat:
\"0srjZJ5.jpg\"
Megjegyz.: A wikin azt írja, az orm_save akkor updatel, ha be van regelve, és akkor insertel, ha nincs. Az orm_loadra pedig azt írja \"...teknikailag ugyanaz, mint az orm_load.\". Mégis csak a jelenlegi felállásban ment egyátalán, betölteni viszont semmilyen kombinációban nem tölt.
Valakinek nincs valami tuti tippje / tapasztalata, hogy mi okozhatja ezt a problémát, mert kezd idegesítõvé válni.
Szerk.: A MySQL tábla felépítése ilyen:
 

//Maga a szerkezet:
CREATE TABLE IF NOT EXISTS `jatekosok` (
  `ABSzam` int(11) NOT NULL AUTO_INCREMENT,
  `Belepve` tinyint(1) NOT NULL,
  `AdminSzint` int(11) NOT NULL,
  `Nev` varchar(24) NOT NULL,
  `KiirNev` varchar(24) NOT NULL,
  `Jelszo` varchar(24) NOT NULL,
  `Fagyasztva` tinyint(1) NOT NULL,
  `Kinezet` int(11) NOT NULL,
  `Penz` int(11) NOT NULL,
  `Elet` float NOT NULL,
  `Melleny` float NOT NULL,
  `Vilag` int(11) NOT NULL,
  `Belso` int(11) NOT NULL,
  `KoordX` float NOT NULL,
  `KoordY` float NOT NULL,
  `KoordZ` float NOT NULL,
  `KoordF` float NOT NULL,
  PRIMARY KEY (`ABSzam`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=19 ;
//Itt pedig az adatok, amiket teljesen jól elmentett.
INSERT INTO `jatekosok` (`ABSzam`, `Belepve`, `AdminSzint`, `Nev`, `KiirNev`, `Jelszo`, `Fagyasztva`, `Kinezet`, `Penz`, `Elet`, `Melleny`, `Vilag`, `Belso`, `KoordX`, `KoordY`, `KoordZ`, `KoordF`) VALUES
(1, 0, 0, \'Layne_Konnor\', \'Layne Konnor\', \'FD9D94340DBD72C11B37EBB\', 0, 7, 185000, 100, 0, 0, 0, 1742.72, -1852.12, 13.4141, 0);

6
Média / Biznisz iroda - rövid bemutató
« Dátum: 2014. Március 15. - 22:20:00 »
Sziasztok! Tudvari szerverére készítettem egy mapot, amit nem fogok publikálni, de azért megmutatom nektek. Ez életem elsõ mapja, amit más embereknek is bemutatok. Itt is lenne a videó: http://youtu.be/xYgS_1FX85Q. Remélem elnyeri majd a tetszéseteket! Negatív és pozitív kritikákat is szívesen fogadok vele kapcsolatban. Nekem pl. az nem tetszik, hogy nem sikerült szebb falat találnom hozzá.

7
Kérdések, Segítség / Ez most akkor GF elem, vagy szimpla realitás?
« Dátum: 2014. Március 09. - 22:04:23 »
Sziasztok! A minap egy furcsa kérdés merült fel bennem. Vajon az, hogy az autóbérlõben csak jogsival lehet bérelni, az GF elem, mert scripttel korlátozza a játékost, vagy teljesen reális, mert pl. az autóbérlõ cég legálisan dolgozik, és nem engedhet forgalomba egy jogsival nem rendelkezõ személyt?
Én az utóbbira tippelek, de nagyon el vagyok bizonytalanodva.
Szerintetek melyik?

Oldalak: [1]
SimplePortal 2.3.7 © 2008-2024, SimplePortal