SA-MP.RPG-BOARD.NET
http://hv-zone.ro/

(Tutorial): Optimizare, simplitate şi stil

Vezi subiectul anterior Vezi subiectul urmator In jos

(Tutorial): Optimizare, simplitate şi stil

Mesaj Scris de r00t la data de Mar 7 Mar - 21:58

Salutare, astăzi vreau să discut cu voi nişte lucruri legate de optimizarea unui GM şi tot în acelaşi timp cum să faci lucrurile mai simple în GM.
Q: Mai simple? Cum mai simple?
A: Urmăreşte-mă şi vei află.

În primul rând să discutăm despre optimizare.
Optimizarea este esenţială pentru un GM, adică reduce timpul de execuţie a unei/unor functi.
Q: Bun, şi dacă îl reduce ce?
A: În timpul de executare a unei/unor funcţii lagul va creşte, şansă de crash devine mai mare şi nimeni nu e mulţumit.
Dacă optimizăm, timpul de lag va fi redus substanţial cea ce scade şansă de crash.
Q: Dar lagul acela de ce se produce?
A: Că să înţelegeţi mai bine imaginativă un calculator mai vechi, cu componente slabe de genu: 1 GB ram , placă video 64 , procesor AMD 2.0 GH.
Acum ganditiva că el lucrează. cu cât deschizi mai multe programe cu atât funcţionează din ce în ce mai greu , până se blochează.
Acum imaginativă un calculator mai bun de genu 4GB ram , placă video 1GB, procesor i3 şi punetil să ruleze aceleaşi programe. Cu siguranţă veţi observă diferenţa şi anume că se mişcă mai rapid la acele programe şi nu se mai blochează aşa de repede.
Aşa ceva este şi cu GM-ul. El trebuie să gândească în acelaşi timp ce face fiecare player în parte. Dacă GM nu este optimizat atunci clientul(adică voi) de a se bloca(crash) este mai mare.

Acum că am lămurit aceste aspecte haideţi să discutăm despre cum putem face un GM mai optim şi totodată introducem şi simplitatea.

Mai întâi voi începe cu sistemul de stocare a datelor MYSQL.


MYSQL


Observ că mulţi se plâng că nu mai sunt GM-uri pe ini(dini, yini sau alte derivări ale acestuia).Dacă tot am pomenit de derivările lui ini, pentru cei care nu ştiu sistemul de stocare a datelor ini este cel care crează un fişier .txt în scriptfiles>user(account/conturi/akk/etc). Dini, yini şi mai sunt câteva derivări sunt pentru a face puţină parformantă, adică să fie creat fişierul .txt mai rapid.
Ok , am lămurit şi acest aspect, acum hai să facem diferenţa mai întâi între ini şi mysql.Mai există şi SQLLite, dar habar nu am cu ce se mânca ăla...
Mysql este în momentul actual cel mai rapid şi mai de folos sistem de creare a datelor. Este cel mai avantajos dintre toate, iar conturile sunt într-o deplină siguranţă.
Q: Ok , şi ce treaba are cu siguranţă conturilor?
A: Hai să va zic ce mi să întâmplat mie personal după un restart. Eram pe un server de să-mp, şi numai văd că se da restart la server, eu aveam nivelul 5 , aveam 2.000.000 $ , 2 maşini, totul bine şi frumos , dar după ce să dat restart , mă văd că trb să mă înregistrez din nou, singurul de pe server, m-am înregistrat şi văd că am lvl 1 şi cele 2 maşini, iar ceilalţi nu aveau contul afectat. La mysql nu să întâmplat nici odată această.
Am zis că e şi mai rapid. Da este mult mult mai rapid decât ini , deoarece un cont pe mysql poate fi creat în baza de date într-un interval scurt de timp (0.0001-0.0010 secunde, tastaţi o comandă şi vedeţi timpul de execuţie dacă nu mă credeţi), iar la dini este undeva la 0.1 - 0.9 secunde , poate ajunge dacă este lag pe server chiar şi la 1 - 1.3 - 1.5 secunde.
Personal cred că este şi mai uşor de folosit. La mysql trebuie să fi atent la query-uri, pentru că ele trimit în baza de date informaţiile, în rest conturile se verifică cu if(Rows)- adică dacă se găsesc rânduri la acel cont, la dini de exemplu se verifică cu if(dini_Exists(file)) şi , personal mă bucur că e mai greu de făcut legătură cu baza de date, deoarece nu tot puştiul poate să-şi deschidă server.

Acum să vorbim despre procesoarele de comenzi.

ZCMD(cel mai cunoscut) şi altele

Văd că încă se foloseşte strcmp pe unele GM-uri. STRCMP este extrem de lent. STRCMP este o funcţie ce verifică mesajul din chat.
Adică, uitaţi cum arată o comandă pe strcmp: if (strcmp("/mycommand", cmdtext, true, 10) == 0) - verifică dacă a fost scris /mycomand.
Aici intervine zcmd, care e are 2 avantaje. Aici se poate spune de simplitate, adică e mai simplu să scri CMD:mycomand(playerid,params[]) decât if (strcmp("/mycommand", cmdtext, true, 10) == 0) , clar e mult mai simplu de scris.
Acum , haideţi să va vorbesc de ce strcmp e mult mai lent.
Să zicem că eu am 100 de comenzi pe strcmp. Eu folosesc ultima comandă, adică comandă cu numărul 100. STRCMP verifică 99 de comenzi şi când ajunge la a 100-a se aplică. În timp ce se verifică se produce lag, într-adevăr , lag-ul ăla se nu e vizibil , dar el există.
ZCMD e conceput să fie mai rapid. El foloseşte CallLocalFunction cea ce "se aruncă" direct în comandă şi nu stă să verifice cele 99 de comenzi , cea ce e vizibil mai rapidă comandă la executare.

Acum există nenumărate procesoare de comenzi LIFE-CMD MCMD(cel mai rapid la ora actuală), aceste procesoare au nevoie de plugin, iar în pluginul respectiv, este folosit memory hack, cea ce îl face mult mai rapid decât zcmd, dar e puţin vizibil ochiului că e mai rapid , dar că lag, e redus substanţial.

SSCANF

Când vorbim de sscanf putem spune clar simplitate în folosire. Sscanf este un strtok dar cu mai multe atribuiri şi este mult mult mai rapid în verificare. Am să va dau o comandă care foloseşte strtok să vedeţi şi cum se foloseşte.

Cod:
CMD:givemoney(playerid,params[])
{
    if(IsPlayerConnected(playerid))
    {
        tmp = strtok(cmdtext, idx);
        if(!strlen(tmp))
        {
            SendClientMessage(playerid, COLOR_GRAD2, "USAGE: /givemoney [playerid/PartOfName] [money]");
            return 1;
        }
        new playa;
        new money;
        playa = ReturnUser(tmp);
        tmp = strtok(cmdtext, idx);
        money = strval(tmp);
        if (PlayerInfo[playerid][pAdmin] >= 1339)
        {
            if(IsPlayerConnected(playa))
            {
                if(playa != INVALID_PLAYER_ID)
                {
                    GivePlayerMoney(playa, money);
                }
            }
        }
        else
        {
            SendClientMessage(playerid, COLOR_GRAD1, "Nu esti autorizat sa folosesti aceasta comanda");
        }
    }
    return 1;
}
Vedeţi voi, în comandă există 2 strtok-uri şi acele strtok-uri se leagă şi de strlen. Strtok-ul , în comandă are atribuţia de a îi pune un parametru, în cazul nostru, la comandă de mai sus, avem 2 parametri şi anume "playerid/PartOfName" şi "money". Ele sunt definite în felul următor cu strtok: tmp = strtok(cmdtext, idx); - face legătură cu money, adică pune că parametru şi money(suma de bani pe care o atribuim) playa = ReturnUser(tmp); - transformă playa în jucător, adică oricare playa este jucător(playa este ţintă, persoană pe care aplicăm comandă) tmp = strtok(cmdtext, idx); - cu strtok îl definim că parametru în comandă money = strval(tmp); - cu strval money este definită că număr. Deci avem nevoie de 4 functi pentru o comandă simplă. Pare inutil să le scri , dar sunt esenţiale şi fără ele nu poţi face comandă corectă, mai ales că trebuie să transformăm definirile în valori playa - jucător, money - suma de bani şi să le facem că parametru. Aici intervine sscanf care e mult mult mai simplu de folosit şi mai rapid, adică noi transformăm definirile în valori şi totodată le facem şi parametri. Putem face în felul următor comandă, în loc să scriem atât o simplificăm şi o şi optimizăm.

Cod:
CMD:givemoney(playerid,params[])
{
    if(IsPlayerConnected(playerid))
    {
        new playa, money;
        if(sscanf(params,"ud", playa, money))
                return SendClientMessage(playerid, COLOR_GRAD2, "USAGE: /givemoney [playerid/PartOfName] [money]");
               
        if (PlayerInfo[playerid][pAdmin] >= 1339)
        {
            if(IsPlayerConnected(playa))
            {
                if(playa != INVALID_PLAYER_ID)
                {
                    GivePlayerMoneyEx(playa, money);
                }
            }
        }
        else
        {
            SendClientMessage(playerid, COLOR_GRAD1, "Nu esti autorizat sa folosesti aceasta comanda");
        }
    }
    return 1;
}
Acum să analizăm. Noi avem parametri următori, eu vii prezint pe cei mai folosiţi:
s - String(sir de caractere, sau mesaj)
i, d - Integer(sau numar intreg) -> 1, 42, -10
c - Caracter -> a, o, *
l - Logical -> true, false
b - Binary -> 01001, 0b1100
h, x - Hex -> 1A, 0x23
o - Octal -> 045 12
n - Numar -> 42, 0b010, 0xAC, 045
f Float(numar cu virgula sau pozitie) -> 0.7, -99.5
u Username(Nume jucator sau id jucator) -> WiDuAlK(numele), 0(id-ul meu)
Bun şi acum să analizăm situaţia următoare: new playa, money; - eu am definit 2 lucruri: playa - care vreau să fie playerul şi money - care vreau să fie suma de bani pe care o atribui. if(sscanf(params,"ud", playa, money)) sscanf - funcţia (params - vine de la CMD:givemoney(playerid,params[]), dacă folosiţi strcmp, cea ce nu va recomand, în loc de params puneţi "cmdtext" din funcţia if (strcmp("/givemoney", cmdtext, true, 10) == 0) "ud", playa, money - fac 2 chestii 1 definesc valorile : "u" i se atribuie lui playa, "d" i se atribuie lui money, dacă era "ud", money, playa "u" i se atribuia lui money iar "d" lui playa. Deci revenim, această funcţie if(sscanf(params,"ud", playa, money)) este exact că funcţiile menţinute mai sus, adică : playa = ReturnUser(tmp); money = strval(tmp); deci respectivul "u" îl transformă pe playa în jucător, iar respectivul "d" îl transformă pe money în număr întreg. Tot în acelaşi timp, transformă cele acele 2 definiri în condiţi pentru comandă , adică dacă nu scrie /givemoney Widualk/0(id meu) 1000(suma de bani) să îi dea mesaj cu parametri comenzii. Totodată sscanf verifică dacă a scris parametri , nu doar îi transformă, deci if(sscanf(params,"ud", playa, money)) verifică dacă sau scris greşiţi parametri şi îi returnează un mesaj cu ei, sau cu ce vreţi voi. Că o concluzie la sscanf , ea are mai multe atribuţii , e şi simplă şi elegantă şi optimă şi ce vreţi voi. Deci e recomandabil să îl folosiţi la orice GM.

Foreach

Foreach-ul , este că un loop rapid. Loop-ul arată ceva de genu: for(new i = 0; i < MAX_PLAYERS; i++) , adică i să fie egal cu toţi jucători, adică să atribuie o funcţie tuturor jucătorilor. de genu:

Cod:
for(new i = 0; i < MAX_PLAYERS; i++)
{
    GivePlayerMoney(i,100);
}
sau

Cod:
for(new i = 0; i < MAX_PLAYERS; i++)
{
    GivePlayerWeapon(i,46(id arma),1(nr de munitii/gloante));
}
Acest "i" creşte de la 0 şi ajunge la nr playerilor conectaţi pe server, adică dacă voi aveţi 46 de playeri pe server, i = 46, dacă voi aveţi 600 playeri, i = 600 şi se atribuie la toţi 600 nu doar unuia. În timp ce creşte i la nr max de playeri, adică se verifică playeri conectaţi, apoi creşte, se face într-un timp , pe care noi nu îl vedem , dar el există şi timpul acela, bine înţeles este încărcat cu lag. Aici intervine foreach şi prin simplitate şi pentru că este şi mai rapid, deci simplu pentru că scri aşa: foreach(Player, i) în loc de acel cod mărişor şi include-ul foreach este structurat să fie mai rapid decât loop-ul normal, deci timp de lag scăzut.

Streamer

Streamer este un include, care depinde şi de plugin Neutral . Şi cam atât pot să va zic... Glumesc Very Happy , cu streamer poţi introduce obiecte în joc. Cu funcţia CreateObject poţi introduce doar 1000 de obiecte, deci voi puteţi pune 2000 de obiecte, dar primele 1000 le va citi. Streamer nu are limita şi poate fi configurat că obiectele să se vadă mai de la distanţă, mai de aproape. Q: Bun , dar de ce e limita de 1000 de obiecte? A: Limita respectivă este pentru binele clientului(voi când intraţi pe server sunteţi client, hostul e serverul), deci dacă marea limita era nevoie de resurse de pc, RAM şi alte resurse, deci limita este pentru binele clientului. Streamer nu are nevoie de multe resurse, doar dacă puneţi hărţi stricate, în sens cu multe obiecte într-o zona , ele fiind şi dublicate, poate chiar de mai multe ori, în rest nu produce lag, serverele de stunt au o groază de linii numai cu obiecte, dar nu prea au lag.

Array-uri

Array-ul e ceva de genu:

new string[200];
acesta este array pt că are "[200]". Este un simplu array, el poate fi şi dublu de genu: new PlayerInfo[MAX_PLAYERS][pInfo] sau new număr[100][25]; sau mai mare. Dacă vedeţi, lungimea strîng-ului meu este de 200 de caractere(caracterele însemnând litere, cifre, simboluri sau spaţiul dintre 2 cuvinte). Deci va citi un mesaj de 200 caractere, în caz că va avea mai mult, caracterele în + nu vor fi afişate. De multe ori strîng-urile mari sunt inutile şi consumă biţi. În chat se pot vedea maxim 144 de caractere, deci strîng-ul nostru este mai mare cu 56 de caractere, care mănâncă biţi. Ce va recomand eu, este să faceţi strîng-urile mici, cam de 144 , mai mult nu aveţi nevoie, sau calculaţi în minte câte cuvinte scrieţi, şi îl puteţi face şi mai mic. Dacă e necesar, de exemplu pui comandă /stats pe dialog MSGBOX, da , ai nevoie de strîng mai mare, pentru că te foloseşti de el, dar în rest nu e necesar, şi e recomandabil să îl faci mai mic.

Stilul

Tot acum vreau să va vorbesc despre stilul în care scriptati. Eu personal folosesc tab-ul de multe ori, şi fac economie de new-uri, de genu: new strîng[100], targetid, suma = 0; în loc de new strîng[200]; new targetid; new suma = 0; şi mereu folosesc 2 tab-uri la aliniere de genu:

Cod:
if(sscanf(params,"ud", playa, money))
        return SendClientMessage(playerid, COLOR_GRAD2, "USAGE: /givemoney [playerid/PartOfName] [money]");
sau

Cod:
if(PlayerInfo[playerid],[pAdmin] < 1)
        return SendClientMessage(playerid, COLOR_GRAD2, "Nu poti folosi aceasta comanda!");
Sau alţi folosesc SPACE între caracterele din functi, dar mie personal nu prea îmi place, dar dacă vouă va place e ok. Sau dacă aveţi multe enum-uri de genu:

new engine, lights, alarm, doors, bonnet, boot, objective;
putem face aşa:

Cod:
new engine,
    lights,
    alarm,
    doors,
    bonnet,
    boot,
    objective;
Sau dialogurile să le aduceţi într-un enum nu în define, puteţi face ceva de genu:

Cod:
#define DIALOG_LOGIN 1
#define DIALOG_REGISTER 2
#define DIALOG_STATS 3
#define DIALOG_HELP 4
il faceti asa:

Cod:
enum
{
    DIALOG_LOGIN,
    DIALOG_REGISTER,
    DIALOG_STATS,
    DIALOG_HELP
};
Şi iese mult mai frumos. Eu nu sunt fan acoladelor foarte lungi, de exemplu:

Cod:
CMD:fixveh(playerid,params[])
{
    if(IsPlayerConnected(playerid))
    {
        if(PlayerInfo[playerid][pAdminServer] < 1337)
        {
            SendClientMessage(playerid, COLOR_GRAD1, "  Nu esti autorizat sa folosesti comanda asta!");
            return 1;
        }
        if(IsPlayerInAnyVehicle(playerid))
        {
            RepairVehicle(GetPlayerVehicleID(playerid));
            SendClientMessage(playerid, COLOR_GREY, "  Masina a fost reparata !");
        }
    }
    return 1;
}

transformam in:

Cod:
CMD:fixveh(playerid,params[])
{
    if(PlayerInfo[playerid][pAdminServer] < 1337)
            return SendClientMessage(playerid, COLOR_GRAD1, "  Nu esti autorizat sa folosesti comanda asta!");
           
    if(!IsPlayerInAnyVehicle(playerid))
            return SendClientMessage(playerid, COLOR_GRAD1, "  Nu esti intr-un vehicul!");
           
    RepairVehicle(GetPlayerVehicleID(playerid));
    SendClientMessage(playerid, COLOR_GREY, "  Masina a fost reparata !");
   
    return 1;
}
Observaţi că am scăpat de acoladele în exces, când se tastează comandă îşi face verificările, după ce trece de verificări se execută, dacă rămâne la o verificare îi da mesaj.
Observaţi că am scăpat şi de verificarea if(IsPlayerConnected(playerid)) deoarece, cel care tastează comandă este mereu conectat, dar dacă folosim o comandă pe cineva, şi el nu este conectat, trebuie să facem verificarea dar în loc de if(IsPlayerConnected(playerid)) punem if(IsPlayerConnected(playa)) sau în loc de playa cum am definit noi jucătorul.

Cam atât am avut de zis, dacă cunoaşteţi şi alte metode , puteţi să le ziceţi printr-un reply aici.

Mic anunţ!!
Am decis că la fiecare tutorial dacă acumulez 5 puncte de + şi câteva reply uri voi mai poştă un tutorial. Nu imediat, ci doar când observ acest lucru.
Deci dacă acumulez câte 5 puncte + la aceste tutoriale:
[Trebuie sa fiti inscris si conectat pentru a vedea acest link]
[Trebuie sa fiti inscris si conectat pentru a vedea acest link]
[Trebuie sa fiti inscris si conectat pentru a vedea acest link]
[Trebuie sa fiti inscris si conectat pentru a vedea acest link]

Am câteva topicuri care mai au +-uri dar nu au câte vreau eu.
Q: Ce faci tu cu +, la ce îţi trebuie, de ce tot inişti?
A: Acel + şi reply reprezintă mai multe pentru mine... Un lucru ar fi ăla că apreciez ce am făcut eu, ce am încercat să explic, ce am vrut să arăt, apreciezi faptul că am făcut ceva pentu ţine/voi sau pentru această comunitate, luaţi-o cum vreţi, şi îmi mai spuneţi că v-am ajutat prin tutorialul meu şi mai doriţi să mai fac, la fel prin reply mai creşte şi activitatea pe forum.

SURSA: [Trebuie sa fiti inscris si conectat pentru a vedea acest link]
avatar
r00t
Admin

Mesaje : 19
Respect Points : 1442
Reputation : 0
Data de inscriere : 14/12/2013

Vezi profilul utilizatorului http://sa-mp.rpg-board.net

Sus In jos

Vezi subiectul anterior Vezi subiectul urmator Sus

- Subiecte similare

 
Permisiunile acestui forum:
Nu puteti raspunde la subiectele acestui forum