Jump to content

Banditul

Moderator
  • Posts

    1,134
  • Joined

  • Last visited

  • Days Won

    96

Everything posted by Banditul

  1. Da , cele defautl care sunt setate, daca nu e nimic pus la default va fi null
  2. Ai doua variante 1: mysql_format(SQL,Str2,sizeof(Str2),"INSERT INTO `crimes` (`name`) VALUES ('%s')",playername3); Cu mentiunea ca trebuie sa ai setata o valoare default pentru crime(merge si fara, e putin mai naspa) 2: mysql_format(SQL,Str2,sizeof(Str2),"INSERT INTO `crimes` (`name`,`Crime1`,`Crime2`,`Crime3`,`Crime4`,`Crime5`,`Crime6`,`Crime7`,`Crime8`,`Crime9`,`Crime10`,`Crime11`,`Crime12`,`Crime13`,`Crime14`,`Crime15`,`Crime16`,`Crime17`,`Crime18`,`Crime19`,`Crime20`) VALUES ('%s', 'Crima1', 'Crima2', 'Crima3', 'Crima4', 'S.A.M.D.')",playername3); Iti da eroarea pentru ca tu specifici toate coloanele, da ii dai doar 1 valoare dar el asteapta mai multe
  3. https://github.com/pBlueG/SA-MP-MySQL/archive/R41-3.zip Ai in example_scripts , cel mai bun, in dupa parerea mea, pentru ca mysql_query opreste tot scriptu pana se executa query-ul (desigur, in naumite cazuri poate lua doar cateva nano secunde sau chiar milisecunde , dar afecteaza rularea gm-ului) (sau poti folosi mysql_pquery in loc de mysql_tquery pentru a executa query-uri in paralel astfel incat sa poti incarca datele mai rapid , da doar pentru incarcare , si nu zic ca e recomandat dar e bun)
  4. Si de ce mysql_query? Daca ti se conecteaza > 2 playeri in acelasi timp va fi bai ales daca ai foarte multe date si lucruri facute la login/register. + ce a zis Mister
  5. Te referi la faptul ca in momentul ce esti "nou" pe server ti se cere sa te inregistrezi iar mai apoi sa the loghezi? Daca da, cine a inceput gm-u de la care au pornit mare parte din rpg-uri s-a gandit ca e o idee buna sa faca asta. Singura solutie sa scapi de aia e sa rescrii sistemul de login/register cea ce e o durere de cap sincer.....
  6. https://github.com/pBlueG/SA-MP-MySQL/archive/R41-3.zip Descarci asta, si in arhiva ai "exampel cripts" si ai acolo login system cache. Foloseste-l
  7. In primul rand , WantedLevel nu este array ( WantedLevel[numar] In al doilea rand , cum ti-a spus si AddisoN for(new i = 0; i < sizeof(WantedLevel); i++) { WantedLevel[i] = 0; WantedMotiv[i] = "Furt vehicul", WntedLevel[i] = 1; WantedMotiv[i] = "Apel Nefondat 112", WntedLevel[i] = 1; WantedMotiv[i] = "Atacare Civil", WntedLevel[i] = 2; WantedMotiv[i] = "Neconformare Ordin", WntedLevel[i] = 2; WantedMotiv[i] = "Patrundere Teren Guvernamental", WntedLeveli[i] = 2; WantedMotiv[i] = "Rapire Civil", WntedLevel[i] = 3; WantedMotiv[i] = "Posesie/Folosire Droguri", WntedLevel[i] = 3; WantedMotiv[i] = "Atacare Politist", WntedLevel[i] = 3; WantedMotiv[i] = "Neplata Amenda", WntedLevel[i] = 3; WantedMotiv[i] = "Jefuire Politist", WntedLevel[i] = 3; WantedMotiv[i] = "Drive-by", WntedLevel[i] = 4; WantedMotiv[i] = "Mituire Politist", WntedLevel[i] = 4; WantedMotiv[i] = "Omorare Civil", WntedLevel[i] = 4; WantedMotiv[i] = "Rapire Politist", WntedLevel[i] = 5; WantedMotiv[i] = "Fugar", WntedLevel[i] = 6; WantedMotiv[i] = "Complice", WntedLevel[i] = 6; } Asta ar fi abordarea , desigur cu cu WantedLevel find cum am mentionat in primul rand.
  8. Nu ti se incarca GeoIP Si sincer sa fiu nu stiu unde il gasesti sa-l descarci....
  9. A da scuze, aparent e bugu de la 0.3 , la 0.2 nu era. Cand o masina nu este folosita de nici un player nu se cheama OnVehicleDeath ca mai apoi sa se cheme OnVehicleSpawn. Si habar nu am de nici un workaround....
  10. Daca ai return 1; la OnVehicleDeath cat si la OnVehicleSpawn ar trebuie sa fie ok Vezi daca la CreateVehicle/AddStaticVehicleEx nu ai setat -1 la parametru respawn_delay http://wiki.sa-mp.com/wiki/AddStaticVehicleEx http://wiki.sa-mp.com/wiki/CreateVehicle Pentru ca daca ai -1 , atunci masina nu se va respawna
  11. Initial voiam sa scriu doar despre partea de mySQL , dar m-a luat valu si am inceput sa scriu mai mult de atat. Si in momentu asta, ma gandesc ca sta e doar jumate din tot intregu . Meritau sa fie mentioante mai multe lucruri, da merge si atat. Mai ales ca sunt 12k caractere
  12. Esti sigur? Ai folosit search in gm/includes? Pentru ca eroarea aia sugereaza faptul ca este undeva in gm
  13. In primul rand nu poti denumi variabile cu nume de tip de data , in cazu tau nu o poti denumi bool pentru ca bool e un tag pentru un tip de data. Daca ai inclus sscanf2 prin #include, atunci cauta dupa functia din gm numita sscanf si sterge-o
  14. De curand am inceput sa deschid cateva gm-uri RPG si de foarte multe ori anumite gm-uri ma fac sa sterg system32 din calculator prin simplu fapt ca comit greseli mari/mici si asta m-a determinat sa fac acest topic Sa incepem mai intai cu baza de date. Pe foarte multi i-am auzit ca baza lor a depasit 2MiB in marime , ei bine daca structura bazei de date ar fi fost mult mai buna asta nu s-ar fi intamplat nici macar cu 1000 conturi inserate Ce vreau sa spun cu asta? Ei bine.... Daca vrei sa salvezi spre exemplu valori de 1 sau 2 si care nu vor fi niciodata sub zero si niciodata mai amri de 127/255 se poate folosi cu usurinta tinyint. Ce este tinyint? Este un int care salveaza valori intre -128 si 127 (sau 0-255 daca unsigned) Ce il face asa special si il recomand? Pentru ca foloseste doar 1byte de memorie si nu 4bytes ca si int normal ( ce mie 1byte ce imi sunt 4bytes , nu? ) , ei bine aceasta diferenta de bytes conteaza prin simplu fapt ca se acumuleaza pentru fiecare rand inserat(cont, masina sau whatever) si se ajunge la 1.5Mib (depinde de cat de mare e tabelul users/players etc) foarte repede Si nu, valoarea pe care o pui la lenght/values conteaza doar ca afisaj cand vizualizati prin phpmyadmin tabelul. (desigur asta se aplica doar in cazul valorilor de tip integer) Deci despre valori de nuemre intregi , sfatul meu este sa folositi si restul tipurilor de date , nu doar INT (asta desigur depinde de ce valori vreti sa stocati ). Cu cat e mai mic tipul de data cu atat mai bine pentru baza de date ( https://dev.mysql.com/doc/refman/5.7/en/integer-types.html ) Bun, acum sa vorbim de VARCHAR , am vazut in multe baze de date nsite valori imense pentru lucruri care nu depaseau 24/32 etc caractere. Deci de ce sa sacrifici memoria bazei de date si a HDD/SSD-ului cand poti sa specifici exact marimea valori pe care vrei sa o stochezi in acel VARCHAR? Ca nu cred ca daca modifici un numar , iti cade mana. Vreti sa stocati data si ora in mysql? Evitati VARCHAR si stringuri/gettime/getdate inutile. Folositi DATETIME sau TIMESTAMP . De ce? De ce nu, e o alternativa mult mai eficienta si are exact acelasi rezultat(daca nu chiar mai bun). Vreti sa extrageti DATETIME/TIMESTAMP din bazade date? Faceti-o ca pe orcare string , nu trebuie sa va murdariti mana si gm-u scriind gettime/getdate , variabile pentru ele , formatare etc. Se poate face foarte simplu folosind CURENT_TIMESTAMP la valaorea default a coloanei din baza de date care contine timpul . Si daca vreti sa updatati data si ora (last seen spre exemplu). " UPDATE users SET lastseen = CURRENT_TIMESTAMP WHERE ID = 5" , nimic mai simplu. Si cat despre storage engine evitati pe cat posibil MyISAM sau altele , folositi InnoDB (pentru ca InnoDB e cel mai bun pentur sa-mp ) Si ca exemplu, va ofer baza de date saints v1.3 vs baza de date saints v1.3 facuta de mine folosind ce am spus mai sus (tabelul users ): http://imgur.com/rE8Q8RC (1008 conturi vs 2008 conturi) Toate cele de mai sus pe langa faptul ca reduc marimea bazei de date , dar deasemenea fac scrierea/citirea din baza de date putin mai eficeinte.Desigur , ar mai fi de mentionat despre tabele separate pentru anumite sisteme (pentru a incarca tabela users etc) dar este mult de scris (forgein key, design de structura etc) Cam atat am avut de spus depsre baza de date (ar mai fi cateva mici chestii , dar nu astea sunt indeajuns) Incat priveste gm-ul , am cateva obiectii si sfaturi (pentru ca si eu la randu meu am facut aceste greseli , fie ele importante sau mai putin importante) In primul rand, evitati pe cat posibil mysql_query . De ce? Pentru ca poate produce unsync la server foarte rapid (query-uri mari sau dese). mysql_query va stopa rularea gm-ului pana ce executa query-ul. Folositi mysql_tquery cat mai mult posibil , pentru ca va lasa serverul sa-si faca treaba cat timp el executa query-ul. Pentru a incarca datele din baza de date(in special la sistemu de logare ) folositi mysql_pquery. De ce? Pentru ca e capabil sa execue query-uri in paralel (in cazul in care mai multi playeri se logheaza in acelasi timp pe server se va dovedi eficient) In al doilea rand, am vazut foarte multe query-uri de genul "UPDATE users SET Money = '%d' WHERE id = '%d'" , nimic gresit nu? Merge foarte bine. Dar problema e cauza din care merge. In cazul de fata, se trimit 2 stringuri spre baza de date care vor fi stocate in baza de date ca integer. Nu stiu motivul pentru care mySQL permite asta , dar are un sistem de conversie string > integer. Diferenta dintre a trimite un string si un integer pentru a fi stocate intr-o coloana de tip integer e putin neglijabila , dar nu tot timpul. Pentru ca acea conversie poate dura doar cateva nanosecunde sau poate chiar cateva secunde (depinde de sarcina pe serverul de mysql) , asa ca de ce sa lasi serverul de mysql sa lucreze in plus cand poti evita aceasta greseala. In al treilea rand , am vazut ceva in gm-u saints care m-a socat( probabil sa fie si in alte gm-uri): for(new turf = 1; turf < sizeof(TurfInfo); turf++) { TurfInfo[turf][zTime] = 0; format(str,sizeof(str),"UPDATE `turfs` SET `Time`='0' WHERE `ID`='%d'",turf); mysql_query(SQL,str); } Aceasta prostie pur si simplu parca mi-a facut un neuron sa explodeze . Sa zicem ca serverul are 100 turfs = 100 query trimise cu mysql_query. Ce inseamna asta? La ora 23 lag garantat + posibile probleme de sync si pierderi de date De ce sa trimiti un astfel de query cand poti face asta: for(new turf = 1; turf < sizeof(TurfInfo); turf++) { TurfInfo[turf][zTime] = 0; } mysql_tquery(SQL,"UPDATE Turfs SET Time = 0"); Ambele fac acelasi lucru, dar modul , viteza si eficienta in care o fac le deiferentiaza enorm. Deci de ce sa sacrifici serverele (mysql/sa-mp) cand poti pastra lucrurile simple si eficiente. In al patrulea rand, folosirea GetPlayerName foarte excesiv. Ce vrea usa spun cu asta? Pentru ca peste se fosoeste GetPlayerName cand de fapt se poate folosi o singura data in tot gm-u. Ce vrea usa psun cu asta? Simplu. Cream o variabila pentru numele jucatorului( cel fara taguri sau alte ccaturi) in PlayerInfo(sau cum o fi) si folosim la OnPlayerConnect: GetPlayerName(playerid, PlayerInfo[playerid][pNormalName], MAX_PLAYER_NAME); Si cand vrem sa ne folosim de numele jucatorului , pur si simplu apelam la aceasta variabila. Deci de ce sa scriem 100000000 de GetPlayerName in tot gm cand putem scrie unul singur si ne facem viata mai simpla? In al cincelea rand, am vazut foarte multe query de genul : UPDATE `users` SET `Money`='%d' WHERE `name`='%s' Ce e gresit in asta? Ei bine, este mult mai rapid si eficient sa ne folosim de ID-ul din baza de date , mai ales ca este un index principal ,iar cautarea dupa ID este mult mai rapida decat cautarea dupa nume (string) Singurele momente in care vrei sa cauti un player in baza de date dupa nume este la conectare (login) si in cazul in care vrei sa te asiguri ca un player exista in baza de date ( referal , ban etc) In al saelea rand, am vazut pe multi folosind cea mai neeficienta metoda de anti sql injection (ce cu cautarea dupa anumite caractere) . Mi se pare cea mai mare prostie sa faci asta. De ce? Pentru ca exista mysql_format care are specificatorul %e care semnifica un string caruia ii se face escape. Daca nu vrei sa folosesti %e pentru a trimite stringuri catre baza de date , se poate folosi deasmeana mysql_real_escape_string care este folosit in background-ul lui %e In al saptelea rand, textdaw-urile globale NU se fac asa: for(new i = 0; i < MAX_PLAYERS; i++) { Speedd[i] = TextDrawCreate(483.600067, 145.848937, " "); TextDrawFont(Speedd[i], 1); TextDrawLetterSize(Speedd[i], 0.270000, 1.000000); TextDrawColor(Speedd[i], -505290241); TextDrawSetOutline(Speedd[i], 1); TextDrawSetProportional(Speedd[i], 1); TextDrawSetShadow(Speedd[i], 1); ..... } Asta inseamna 650 (50 sloturi) de textdraw-uri gobale deja epuizate cand limita este de 2048 ( 13000 de textdarw-uri pentru 1000 sloturi) . Ce naiba?? Cine a facut asta , a fost cel mai "destept" om. Daca vreti sa faceti textdraw per player, folositi textdraw-uri per player. Cum? Creati cate o variabila pentru fiecare player textdraw in PlayerInfo (PlayerText: text1, PlayerText: text2 etc) si puenti ceva asemanator la OnPlayerConnect: PlayerInfo[playerid][Speedd] = CreatePlayerTextDraw(playerid,483.600067, 145.848937, " "); PlayerTextDrawFont(playerid,PlayerInfo[playerid][Speedd], 1); PlayerTextDrawLetterSize(playerid,PlayerInfo[playerid][Speedd], 0.270000, 1.000000); PlayerTextDrawColor(playerid,PlayerInfo[playerid][Speedd], -505290241); PlayerTextDrawSetOutline(playerid,PlayerInfo[playerid][Speedd], 1); PlayerTextDrawSetProportional(playerid,PlayerInfo[playerid][Speedd], 1); PlayerTextDrawSetShadow(playerid,PlayerInfo[playerid][Speedd], 1); Pentru fiecare in parte , si va folisiti de variabila respectiva . ( Player textdraw-urile se sterg la deconectarea playerului singure) Cat inseamna asta pentru limita de textdraw-uri? 0 pentru cele gloable, si posibil 10-15 per player. Nu e mai ok asa? De ce sa ai 650 , 1300 ....13000 de textdraw-uri cand poti sa ai 10-15 per player ( limita per player este de 256 , si nu are legatura cu textdarw-urile gloable) In al optulea rand, loop-uri de playeri/masini. Multi inca mai scriu loop-uride genul: for(new i; i < MAX_PLAYERS;i++) Cea ce nu mai este atat de eficient si bun , avand in vedere ca exista foreach si GetPlayerPoolSize disponibile si mult mai eficiente (GetVehiclePoolSize in cazuk masinilor) for(new i = 0, j = GetPlayerPoolSize(); i <= j; i++) for(new i = 1, j = GetVehiclePoolSize(); i <= j; i++) foreach(new i: Player) Ce fac GetPlayerPoolSize si GetVehiclePoolSize? Ei bine, returneaza toate sloturile ocupate( sa zicem ca max de sloturi e 50, si ai abia 3 playeri conectati , GetPlayerPoolSize() va intoarce 3 pentru ca sunt numa 3 playeri / 3 sloturi ocupate , acelasi principiu se aplica si la GetVehiclePoolSize()) In al noulea rand, nu vreti ca playerul care se conecteaza sa mosteneasca datele precedentului player care tocmai a iesit? Nu este nevoie sa scrieti PlayerInfo[playerid][VariabilaX] = 0 la OnPlayerDisconect sau Conenct pentru fiecare variabila in parte. Ce mai eficienta si rapida metoda este aceasta: static const empty_player[pInfo]; PlayerInfo[playerid] = empty_player; Ce face asta? Atribuie 0 pentru fiecare variabila in parte (pentru cele existente in PlayerInfo) , deci de ce sa scrii N randuri cand poti sa scrii numa 2 In al zecelea rand, evitati pe cat posibil array-uri mari (stringuri etc) . De ce sa definesti un string de 500 cells(2000 bytes) si sa folosesti pentru cel mult 60 caractere? E o pierdere de memorie inutila (da stiu nu e semnificativa , bla bla ,dar totu se aduna si pe termen lung nu are rost). Cam atat, poate ar mai fi lucruri de spus dar pur si simplu nu-mi mai vin in minte. E cam lung ce-i drept dar am incercat sa explic cat de cat..... Sper sa nu ma injurati cand ajunget ila aceste randuri ca e prea mult de citit. Sper sa fie cat de cat de folos cuiva si sper ca cel macar sfaturile legate de baza de date sa le vad aplicate (pentru ca pe asta se bazeaza RPG , multe query-uri si mult contact cu baza de date si nu vrem sa avem pierderi de date sau delay-uri sau mai stiu eu ce)
  15. Selectezi baza de date din partea stanga si apesi pe http://imgur.com/C5U0eYb Si in acolo copiezi alea
  16. Aia nu eroare, dar am copiat ce ai postat mai sus si e din cauza ca acel comentariu inainte de CREATE TABLE IF NOT EXISTS `Accounts` nu e terminat ,deci totul este ignorat Incearca sa copiezi din acel fisier sql tot ce este de la TE TABLE IF NOT EXISTS `Accounts` si mai departe si copaiza-le in phpmyadmin dupa ce apesi pe butonul SQL (selectezi baza de date inainte)
  17. Nu vad nici o eroare aici....Care e problema mai exact? Ce-ti zice? Ce nu merge?
  18. https://www.microsoft.com/en-us/download/details.aspx?id=48145 Dai download si alege x86. Ai scos macar .dll din server.cfg? Si testat dupa?
  19. Cel mai probabil nu se face escape la string inainte sa fie trimis in baza de date... Edit: http://forum.sa-mp.com/showthread.php?t=608871 Eu unu nu am avut niciodata probleme cu dialogu cu astfel de caractere....
  20. In primul rand pe winodws nu trebuie sa pui extensia .dll la plugins in server.cfg In al doilea rand, incearca sa instalezi urmatoarele: http://filehippo.com/download_visual_c_redistributable_packages_for_visual_studio/ https://www.microsoft.com/en-us/download/confirmation.aspx?id=48145 http://sh.st/r/e44b4fdcd0ea33c4c8ccea5f408e8798/12/1/http://adf.ly/576535/_eaHR0cDovL2Rvd25sb2FkLm1pY3Jvc29mdC5jb20vZG93bmxvYWQvMS82L0IvMTZCMDZGNjAtM0IyMC00RkYyLUI2OTktNUU5Qjc5NjJGOUFFL1ZTVTMvdmNyZWRpc3RfeDg2LmV4ZQ== E posibil sa nu ai versiunile visual c++ necesare instalate
  21. Pai ar fi ajutat sa faci un topic cu problema. Dar merge si asa amu. Posteaza serverlog pentru a vedea ce erori primesti astfel incat sa te pot ajuta cu problema, nu sunt vrajitor sa vad ce anume iti cauzeaza problema, poate fi din multe cauze
  22. https://pastebin.com/sgnTy7Sk Incearca asa
  23. Nu primesti nici o eroare in serverlog? Spre exemplu legata de streamer? Sau stiu eu ce? Pentru ca e imposibil sa nu iti apara macar o eroare sau warning
  24. Unknow iti poate da din 2 motive: Nu ti se incarca unul dintre pluginuri sau nu se poate conecta cu baza de date. Si in ce sens nu poti intra? Nu apar dialoguriel de login/register? Daca da, atunci nu ti se conecteazacu baza de date sau nu ti se incarca pluginul mysql sa se poata conecta.
  25. Am facut un mic exemplu , desigur pare putin ciudat. Ideea de baza este acea ca tabelul users este tabelul de baza iar crimes este o derivata pentru ca in tabelul crimes avem o referinta catre tabelul users si anume user_id care face referinta la id-ul din tabelul users. Doar ca va trebui sa faci un query separat sa incarci datele din tabelul crimes si sa le incarci in variabilele din gm ale playerului. Si deasemenea trebuie sa faci un query separat la inregistre pentru a introduce in crimes datele playerului (inca nu am descoperit o modalitate mai buna de a face asta) Ceva de genul am facut eu intr-un gm pentru un sistem de Level: new query[221]; mysql_format(g_SQL, query, sizeof query, "INSERT INTO `players` (`username`, `password`, `salt`,`IP`) VALUES ('%e', '%s', '%e','%e')", APlayerData[playerid][PlayerName], APlayerData[playerid][PlayerPassword], APlayerData[playerid][Salt],IP); mysql_tquery(g_SQL, query, "OnPlayerRegister", "i", playerid); mysql_format(g_SQL, query,sizeof(query), "INSERT INTO `ExpLevel` (`pid`) VALUES ((SELECT `ID` FROM `players` WHERE `username` = '%e'))", APlayerData[playerid][PlayerName]); mysql_tquery(g_SQL, query, "",""); Asta e din dialogul de register , astfel incat in momentul in care un player se inregistreaza pe langa introducerea datelor in users se introduc si in crimes . Doar ca va trebui sa faci update la tabelul crimes in momentul in care se produce o crima. Asta e doar o idee de baza sa zic asa, as fi vrut sa stiu putin mai multe despre forgein key(cheie straina) mai ales ca folositoare cand faci diferite sisteme gen de ownership sau Level cum am facut eu. Tin baza de date mai organizata si e putin mai eficient. Trebuie sa te joci cu mysql, sa ii inveti smecheriile sa inveti cum functioneaza s.a.m.d.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more details you can also review our Terms of Use and Privacy Policy.