hlmod.hu

Magyar Half-Life Mód közösség!
Pontos idő: 2026.03.01. 00:09



Jelenlévő felhasználók

Jelenleg 284 felhasználó van jelen :: 1 regisztrált, 0 rejtett és 283 vendég

A legtöbb felhasználó (2883 fő) 2025.07.30. 16:00-kor tartózkodott itt.

Regisztrált felhasználók: Google [Bot]az elmúlt 5 percben aktív felhasználók alapján

Utoljára aktív
Ahhoz hogy lásd ki volt utoljára aktív, be kell jelentkezned.



Az oldal teljeskörű
használatához regisztrálj.

Regisztráció

Kereső


Új téma nyitása Hozzászólás a témához  [1 hozzászólás ] 
Szerző Üzenet
 Hozzászólás témája: [TUT] Hatékony scriptelés
HozzászólásElküldve:Tegnap, 11:02 
Offline
Fanatikus
Avatar

Csatlakozott:2020.05.14. 11:32
Hozzászólások:165
Megköszönt másnak: 14 alkalommal
Megköszönték neki: 63 alkalommal
[Előzetes]
Az AMXX Pawn-ban minden változó 4 bájtot, azaz 32 bitet foglal. Egy plugin által lefoglalt memóriaterületet az 1.6-nak létrehozott (virtuális) memóriatér kezeli, ami több részre oszlik fel: stack (verem), heap(kupac), adat- és kódszegmens (utóbbi számunkra irreleváns). Ezekbe nem megyek bele mélyen, mivel külön topicot kellene rá szentelni és szeretném ezt a posztot hibridnek tartani, hogy érthető legyen kezdő/haladó fejlesztőnek is.

Habár játékos ma már kevésbé, régi/új fejlesztők fel-fel bukkannak időnként, most pláne a mestint miatt, és mivel sokakat láttam használni (vagy akár teljes kódot megírni :nono:) úgy láttam nem ártana lebutítva egy gyorstalpalót adni a hatékony kódolásról, mivel rengeteg kódon akad meg a szemem, és vannak nagyon súlyos esetek is. Ha más nem, legalább ezt be lehet linkelni az AI-nak hogy ez alapján dolgozzon.

A tutorial alatt egy példakóddal fogok szemléltetni minden problémát és megoldást, hogy egyértelműen követhető legyen a nyavajgásom.

  1. #include <amxmodx>
  2. #include <fakemeta>
  3. #include <hamsandwich>
  4. #include <sqlx>
  5.  
  6. #define LVL_UP_TEXT "%s szintet lépett! Új szintje: %d"
  7.  
  8. new const XP_PER_KILL = 2
  9. new const XP_REQUIRED_FOR_LEVEL_UP = 10
  10. new userxp[33], userlevel[33], bool:uservip[33]
  11. new Handle:g_SqlTuple
  12.  
  13. new const SQLINFO[][] = {"Kiszolgáló", "Felhasználó", "Jelszó", "Adatbázis"}
  14.  
  15. public plugin_init(){
  16.     register_plugin("NAME", "VERSION", "AUTHOR")
  17.  
  18.     register_clcmd("say /secret", "CmdSecret")
  19.  
  20.     register_event("DeathMsg", "eDeathMsg", "a")
  21.  
  22.     register_forward(FM_PlayerPreThink, "FM_ClientPrethink")
  23.  
  24.     RegisterHam(Ham_TraceAttack, "player", "Ham_TraceAttack_Post", 1)
  25. }
  26.  
  27. public CmdSecret(id) {
  28.     uservip[id] = true
  29. }
  30.  
  31. public TraceAttack(victim, attacker, Float:damage, Float:dir[3], trace, damagetype){
  32.     if(!uservip[attacker]
  33.     || !(1 <= attacker <= 32)
  34.     || !(1 <= victim <= 32)
  35.     || !is_user_connected(attacker)){
  36.         return HAM_IGNORED
  37.     }
  38.    
  39.     new weapon = get_user_weapon(attacker)
  40.     new hitgroup = get_tr2(trace, TR_iHitgroup)
  41.  
  42.     if(hitgroup == HIT_HEAD && is_gun_weapon(weapon)){
  43.         userxp[attacker]++
  44.     }
  45.  
  46.     return HAM_IGNORED
  47. }
  48.  
  49. public eDeathMsg(){
  50.     new Killer = read_data(1);
  51.     new Victim = read_data(2);
  52.  
  53.     if (!is_user_connected(Killer) || !is_user_connected(Victim))
  54.         return PLUGIN_HANDLED;
  55.  
  56.     if (Killer == Victim)
  57.         return PLUGIN_HANDLED;
  58.  
  59.     userxp[Killer] += XP_PER_KILL;
  60.  
  61.     return PLUGIN_CONTINUE;
  62. }
  63.  
  64. public plugin_cfg(){
  65.     g_SqlTuple = SQL_MakeDbTuple(SQLINFO[0], SQLINFO[1], SQLINFO[2], SQLINFO[3]);
  66.  
  67.     static Query[10048];
  68.     new Len;
  69.  
  70.     Len += formatex(Query[Len], charsmax(Query) - Len, "CREATE TABLE IF NOT EXISTS \\`szintrendszerxp\\` (");
  71.     Len += formatex(Query[Len], charsmax(Query) - Len, "\\`id\\` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,");
  72.     Len += formatex(Query[Len], charsmax(Query) - Len, "\\`steamid\\` varchar(32) NOT NULL,");
  73.     Len += formatex(Query[Len], charsmax(Query) - Len, "\\`Lvl\\` int(11) NOT NULL,");
  74.     Len += formatex(Query[Len], charsmax(Query) - Len, "\\`Xp\\` int(11) NOT NULL)");
  75.  
  76.     SQL_ThreadQuery(g_SqlTuple, "createTableThread", Query);
  77. }
  78.  
  79. public createTableThread(FailState, Handle:Query, Error[], Errcode, Data[], DataSize, Float:Queuetime)
  80. {
  81.     if (FailState == TQUERY_CONNECT_FAILED)
  82.         set_fail_state("[HIBA*] NEM TUDTAM CSATLAKOZNI AZ ADATBAZISHOZ!");
  83.     else if (FailState == TQUERY_QUERY_FAILED)
  84.         set_fail_state("Query Error");
  85.  
  86.     if (Errcode)
  87.         log_amx("[HIBA] %s", Error);
  88. }
  89.  
  90. public FM_ClientPrethink(){
  91.     for(new id = 0; id <= 32; id++){
  92.         if(userxp[id] >= XP_REQUIRED_FOR_LEVEL_UP){
  93.             userlevel[id]++
  94.             userxp[id] -= XP_REQUIRED_FOR_LEVEL_UP
  95.  
  96.             new name[32]
  97.             get_user_name(id, name, charsmax(name))
  98.             client_print_color(0, 0, LVL_UP_TEXT, name, userlevel[id])
  99.         }
  100.     }
  101. }
  102.  
  103. stock bool:is_gun_weapon(wpn)
  104. {
  105.     switch (wpn)
  106.     {
  107.         case CSW_KNIFE, CSW_HEGRENADE, CSW_FLASHBANG, CSW_SMOKEGRENADE, CSW_C4:
  108.             return false
  109.     }
  110.     return true
  111. }


A kód lényege:

Idézet:
Ez a direkt(!) csonkított kód, ahol nincs userid kezelés, sql betöltés, mentés, beszúrás hogy könnyebben átláthatóbb legyen a tutorial érdekében, Egy egyszerű szintrendszert valósít meg.
new userxp[33] -> A user xp-t tárolja
new userlevel[33] -> user szintet tárol
new bool:uservip[33] -> azt nézi, hogy a játékos beírt-e egy "titkos" parancsot, mely segítségével nem csak akkor kap xp-t ha valakit megöl, de akkor is ha valakit fejbe talál.
1 sql utasítás van a plugin_cfg-ben, ami létrehozza a táblát.

Ha valaki szintet lép, azt kiírja a plugin a chatre amit mindenki lát.

I. Memóriafoglalás (Static, New, méret)

Azért kezdem ezzel, mert tapasztalat szerint ez a legsúlyosabb mindközül.
  1. static Query[10048];


Itt azt mondjuk a fordítónak, hogy:
"Itt egy változó. Ezt tartsd készenlétben a plugin teljes életciklusa alatt."

Miért teljes életciklus? Mert a static/globális változók az adatszegmensben tárolódnak, azaz nem időszakosan jönnek elő a new-al ellentétben.

Mi ennek az eredménye?

A Query változó 10048*4 bájtot foglal egy függvényben. Mivel én ezt használom SQL adatbeszúrásnál, létrehozásnál, mentésnél és betöltésnél is (azaz összesen 4x), kumulálva 160,768B van felhasználva a plugin teljes futása alatt.

Holott, ha egyszerűen new-t használnánk minden alkalommal nem lenne ennyi nyomás alatt a szerverünk a korlátozott memória miatt. ILLETVE.

A tömbméret sem mindegy. Ez a static Query[10048] egy vírusként terjed az egész fórumon. Szinte mindenhol látom, nem lehet menekülni előle.

A 10048 helyett adjuk meg egy méretet a Queryként átadott parancsunknak a karakterszámát + még várható input karakterszámot véve, pl.: steamid. Jelen esetben:
  1. "CREATE TABLE IF NOT EXISTS \\`szintrendszerxp\\`" + "\\`id\\` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY," + "\\`steamid\\` varchar(32) NOT NULL, " + \\`Lvl\\` int(11) NOT NULL," + \\`Xp\\` int(11) NOT NULL" -> ~200 karakter (ctrl c + ctrl v egy character counter oldalra)

ebből kifolyólag, legyen a tömbünk mérete 300 (200+steamid karakterszám+x számjegyű id + x számjegyű xp + x számjegyű szint) körül.

  1. new Query[300];


Most 1200 bájtot foglalunk összesen, amit ráadásul nem is végig veszünk használatba hanem csak időszakosan.

Ez azt jelenti, hogy 159,568B memóriát spóroltunk meg. Százharmincháromszorosára (!!) csökkentettük a memóriahasználatot.

Fontos: mivel ha new-al létrehozunk egy változót, az bekerül a stackbe, majd nullázódik. Ez 1 cellánál egyszerű művelet. Viszont ha már nagyobb tömbökkel dolgozunk, sűrűn használjuk, akkor mindenképp érdemes static-al deklarálni.

Tehát:
- static: érdemes akkor használni, ha 1 másodperc alatt sokszor vesszük igénybe a változót ÉS nagyobb tömbről beszélünk.
- new: minden más esetben

II. Makrók/konstansok
  1. #define LVL_UP_TEXT "%s szintet lépett! Új szintje: %d"


Ezzel az a probléma, hogy a #define több műveletet igényel, mintha const-ként definiálnánk a változót.

A #define minden meghívásnál rátesz a stackre egy copy-t belőle. A const egyszer kerül be a heapbe, és onnantól kezdve a referenciáját kezeli a plugin.

Tehát érdemes:

  1. new const LVL_UP_TEXT[] = "%s szintet lépett! Új szintje: %d"


Mivel a többi típust máshogy kezeli, ezért pl. intnél vagy boolnál mindegy, hogy #define-al vagy const-al hozzuk létre.

Makrókat viszont CSAK #define-al tudunk létrehozni.

Pl:
  1. if(!uservip[attacker]
  2.     || !(1 <= attacker <= 32)
  3.     || !(1 <= victim <= 32)
  4.     || !is_user_connected(attacker)){
  5.         return HAM_IGNORED
  6.     }
  7. ->
  8. #define IsPlayer(%0) (%0 >= 1 && %0 <= 32)
  9.  
  10.     if (!uservip[attacker]
  11.     || !IsPlayer(iAttacker)
  12.     || !IsPlayer(iVictim)
  13.     || !is_user_connected(iAttacker))
  14.         return HAM_IGNORED


Ez miért jobb? Leginkább olvashatóság és skálázhatóság szempontjából. Elég annyit látnom, hogy IsPlayer, akkor fogom tudni hogy mit jelent, és még könnyen is tudom változtatni az implementációját is.

Fontos tudni, hogy amíg erre mondjuk egy stock függvényt hoztunk volna létre (ami tárolódik is a veremben) addig a makrókat a preprocessor dolgozza fel és csak a kódszegmens méretét növeli.

A %0 paraméterként várja a bejövendő argumentumokat, és azokkal végez behelyettesítéses számolást.

Ilyen makrókat nem tudunk létrehozni const-okkal.

III. Bitműveletek (haladóknak)
  1. if(hitgroup == HIT_HEAD && is_gun_weapon(weapon)){
  2.         userxp[attacker]++
  3.     }
  4.  
  5. stock bool:is_gun_weapon(wpn)
  6. {
  7.     switch (wpn)
  8.     {
  9.         case CSW_KNIFE, CSW_HEGRENADE, CSW_FLASHBANG, CSW_SMOKEGRENADE, CSW_C4:
  10.             return false
  11.     }
  12.     return true
  13. }


Ez alapjáraton egy szép megoldás. Viszont a legtöbb alkalommal 5 ellenőrzést hajtok végre, és ráadásul egy Ham_TraceAttack_Post-ban, ami lövésenként lefut.

  1. #define NON_GUN_MASK (1<<CSW_KNIFE|1<<CSW_HEGRENADE|1<<CSW_FLASHBANG|1<<CSW_SMOKEGRENADE|1<<CSW_C4)
  2. #define is_gun_weapon(%0) !(1<<%0 & NON_GUN_MASK)


Makrókkal sokkal optimálisabb és szebb dolgozni. Valamint, így csak 1 ellenőrzés lesz végrehajva 5 helyett. Azaz, ötödére csökkentettük a számítást.

Viszont fontos megjegyezni, hogy a makrók nem mindig a legjobb választás. Ez most egy tökéletes példa rá, hogy sokkal optimálisabban jövünk ki 2 sorral, mint 10-el.

Hacsak nincs úgynevezett branchelés (if-else elágazás, switch, ciklus) a függvényünkben, érdemes lehet elgondolkodni rajta.

  1. new uservip[33]


(Habár bőven elhanyagolható, szemfülesek észrevehetik hogy ez alapjaiban rossz, mivel 33 elemű tömböt hozunk létre 32 játékosra. Persze, ezt az egyszerű indexelés végett csináljuk így (én is így használom).)

Viszont most ott járunk, hogy 132 bájt van lefoglalva a memóriában.

Ha bitműveleteket alkalmaznánk:
  1. #define SetBit(%0,%1) (%0 |= (1 << (%1 & 31)))
  2. #define GetBit(%0,%1) (%0 & (1 << (%1 & 31)))
  3. #define ClearBit(%0,%1) (%0 &= ~(1 << (%1 & 31)))
  4. #define ToggleBit(%0,%1) (%0 ^= (1 << (%1 & 31)))
  5.  
  6. new uservip


4 bájtot használnánk. És itt most úgy gondolkodjunk, hogy nagyobb modokban nem csak 1 globális változónk van ami bool.

Használata pedig így nézne ki:
  1. public SecretCmd(id){
  2.     SetBit(uservip, id)
  3. }
  4.  
  5.     if(!GetBit(uservip, attacker)
  6.     || !(1 <= attacker <= 32)
  7.     || !(1 <= victim <= 32)
  8.     || !is_user_connected(attacker)){
  9.         return
  10.     }

Ha valaki tömbre akarja használni, annak korábban ezt írtam össze:
  1. #define Player_Set(%0,%1) (g_bPlayer[%1] |= (1 << (%0 & 31)))
  2. #define Player_Get(%0,%1) (g_bPlayer[%1] & (1 << (%0 & 31)))
  3. #define Player_Unset(%0,%1) (g_bPlayer[%1] &= ~(1 << (%0 & 31)))
  4. #define Player_Toggle(%0,%1) (g_bPlayer[%1] ^= (1 << (%0 & 31)))


IV. Optimalizált kód
  1. public FM_ClientPrethink(){
  2.     for(new id = 0; id <= 32; id++){
  3.         if(is_user_connected(id)){
  4.             if(userxp[id] >= XP_REQUIRED_FOR_LEVEL_UP){
  5.                 userlevel[id]++
  6.                 userxp[id] -= XP_REQUIRED_FOR_LEVEL_UP
  7.  
  8.                 new name[32]
  9.                 get_user_name(id, name, charsmax(name))
  10.                 client_print_color(0, 0, LVL_UP_TEXT, name, userlevel[id])
  11.             }
  12.         }
  13.     }
  14. }


Itt a másodperc tört része alatt lefuttatunk minden alkalommal egy ciklust ami 32-ig iterál.

Ehelyett, sokkal ésszerűbb lenne csak akkor megnézni hogy az adott játékos él-e vagy sem amikor az XP-jét változtatjuk.

  1. if(userxp[id] >= XP_REQUIRED_FOR_LEVEL_UP){
  2.         userlevel[id]++
  3.         userxp[id] -= XP_REQUIRED_FOR_LEVEL_UP
  4.     }


Ennél mégokosabb megoldás, ha jó programozóként skálázhatóvá tesszük ezt az eljárást. Magyarul, csináljunk rá egy külön funkciót.

  1. public CheckUserXp(id){
  2.     if(userxp[id] >= XP_REQUIRED_FOR_LEVEL_UP){
  3.         userlevel[id]++
  4.         userxp[id] -= XP_REQUIRED_FOR_LEVEL_UP
  5.     }
  6. }


Ennek a segítségével a kód több pontján is meghívhatjuk ugyanazt a folyamatot. Ha változtatni szeretnénk rajta, akkor csak ebben az eljárásban kell azt elvégeznünk. Csökkentett és skálázhatóbb lett a kódunk.

  1. new name[32]
  2.                 get_user_name(id, name, charsmax(name))
  3.                 client_print_color(0, 0, LVL_UP_TEXT, name, userlevel[id])


Itt létrehozunk egy name változót, és lekérjük bele a user nevét.

AMXX 1.9 óta már nem szükséges külön funkcióval lekérni a user nevét minden esetben, hanem elég egy literállal azt megtenni.

  1. new const LVL_UP_TEXT[] = "%n szintet lépett! Új szintje: %d"
  2.  
  3. client_print_color(0, 0, LVL_UP_TEXT, id, userlevel[id])


Tehát, a %s helyett %n-t használunk, és name változó helyett id-t!

V. Elnevezési konvenciók
Az AMXX-ben mint tudjuk vannak típusok. Ezen típusok közé tartozik a: Int, Bool, Char, Handle, Float, Array, Trie, stb.

  1. new userxp[33], userlevel[33], bool:uservip
  2. new Handle:g_SqlTuple


Ezeket (és minden más változót) a pluginban szebben, érthetőbben is eltudunk nevezni. PL:
  1. new g_iUserXp[33]
  2. new g_iUserLevel[33]
  3. new g_bUserVip
  4. new Handle:g_hSqlTuple
  5.  
  6. g_ -> globális
  7. i -> integer
  8. s, sz -> string
  9. c -> char
  10. t -> trie
  11. a -> array
  12. h -> handle
  13. f -> float


Ezt anno még -tól lestem el, mint logikus váltózó elnevezések. Alapjáraton Alliedmoddersen is úgy látom, hogy sokan követik ezt a formát.

+ Egyéb
  1. public createTableThread(FailState, Handle:Query, Error[], Errcode, Data[], DataSize, Float:Queuetime)
  2. {
  3.     if (FailState == TQUERY_CONNECT_FAILED)
  4.         set_fail_state("[HIBA*] NEM TUDTAM CSATLAKOZNI AZ ADATBAZISHOZ!");
  5.     else if (FailState == TQUERY_QUERY_FAILED)
  6.         set_fail_state("Query Error");
  7.  
  8.     if (Errcode)
  9.         log_amx("[HIBA] %s", Error);
  10. }


Ez így HELYTELEN. Alapjáraton rosszul terjedt el ez is a fórumon... hamarabb kap fail state-t és áll le a plugin, minthogy kiírná a hibát.

->

  1. public createTableThread(FailState, Handle:Query, Error[], Errcode, Data[], DataSize, Float:Queuetime)
  2. {
  3.     if (Errcode)
  4.         log_amx("[HIBA] %s", Error);
  5.  
  6.     if (FailState == TQUERY_CONNECT_FAILED)
  7.         set_fail_state("[HIBA*] NEM TUDTAM CSATLAKOZNI AZ ADATBAZISHOZ!");
  8.     else if (FailState == TQUERY_QUERY_FAILED)
  9.         set_fail_state("Query Error");
  10. }


Végső kód, az optimalizálások után:
  1. #include <amxmodx>
  2. #include <fakemeta>
  3. #include <hamsandwich>
  4. #include <sqlx>
  5.  
  6. #define IsPlayer(%0) (%0 >= 1 && %0 <= 32)
  7.  
  8. #define SetiBit(%0,%1) (%0 |= (1 << (%1 & 31)))
  9. #define GetiBit(%0,%1) (%0 & (1 << (%1 & 31)))
  10. #define CleariBit(%0,%1) (%0 &= ~(1 << (%1 & 31)))
  11.  
  12. #define NON_GUN_MASK (1<<CSW_KNIFE|1<<CSW_HEGRENADE|1<<CSW_FLASHBANG|1<<CSW_SMOKEGRENADE|1<<CSW_C4)
  13. #define is_gun_weapon(%0) !(1<<%0 & NON_GUN_MASK)
  14.  
  15. new const g_szLvlUpText[] = "^x04%n ^x01szintet lépett! Új szintje: ^x04%d"
  16. new const g_iXpPerKill = 2
  17. new const g_iXpRequired = 10
  18.  
  19. new g_iUserXp[33], g_iUserLvl[33]
  20. new g_bUserVip
  21. new Handle:g_hSqlTuple
  22.  
  23. new const g_szSqlInfo[][] = {"Kiszolgáló", "Felhasználó", "Jelszó", "Adatbázis"}
  24.  
  25. public plugin_init() {
  26.     register_plugin("PLUGIN", "VERSION", "AUTHOR")
  27.  
  28.     register_clcmd("say /secret", "CmdSecret")
  29.     register_event("DeathMsg", "EventDeathMsg", "a")
  30.    
  31.     RegisterHam(Ham_TraceAttack, "player", "Ham_TraceAttack_Post", 1)
  32. }
  33.  
  34. public CmdSecret(id) {
  35.     SetiBit(g_bUserVip, id)
  36. }
  37.  
  38. public Ham_TraceAttack_Post(iEnt, iAttacker, Float:fDamage, Float:fDir[3], iTrace, iDamageType) {
  39.     if (!GetiBit(g_bUserVip, iAttacker)
  40.     || !(IsPlayer(iAttacker))
  41.     || !(IsPlayer(iVictim))
  42.     || !is_user_connected(iAttacker))
  43.         return HAM_IGNORED
  44.  
  45.     static iWeapon; iWeapon = get_user_weapon(iAttacker)
  46.     static iHitgroup; iHitgroup = get_tr2(iTrace, TR_iHitgroup)
  47.  
  48.     if (iHitgroup == HIT_HEAD && is_gun_weapon(iWeapon)) {
  49.         g_iUserXp[iAttacker]++
  50.         CheckUserXp(iAttacker)
  51.     }
  52.    
  53.     return HAM_IGNORED
  54. }
  55.  
  56. public EventDeathMsg() {
  57.     new iKiller = read_data(1)
  58.     new iVictim = read_data(2)
  59.  
  60.     if (!iKiller || iKiller == iVictim || !is_user_connected(iKiller))
  61.         return
  62.  
  63.     g_iUserXp[iKiller] += g_iXpPerKill
  64.     CheckUserXp(iKiller)
  65. }
  66.  
  67. public CheckUserXp(id) {
  68.     while (g_iUserXp[id] >= g_iXpRequired) {
  69.         g_iUserLvl[id]++
  70.         g_iUserXp[id] -= g_iXpRequired
  71.  
  72.         client_print_color(0, print_team_default, g_szLvlUpText, id, g_iUserLvl[id])
  73.     }
  74. }
  75.  
  76. public plugin_cfg() {
  77.     g_hSqlTuple = SQL_MakeDbTuple(g_szSqlInfo[0], g_szSqlInfo[1], g_szSqlInfo[2], g_szSqlInfo[3])
  78.  
  79.     new szQuery[512]
  80.     formatex(szQuery, charsmax(szQuery),
  81.         "CREATE TABLE IF NOT EXISTS \\`szintrendszerxp\\` (
  82.        \\`id\\` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  83.        \\`steamid\\` VARCHAR(32) NOT NULL,
  84.        \\`Lvl\\` INT(11) NOT NULL,
  85.        \\`Xp\\` INT(11) NOT NULL)")
  86.  
  87.     SQL_ThreadQuery(g_hSqlTuple, "TableCreateCallback", szQuery)
  88. }
  89.  
  90. public TableCreateCallback(iFailState, Handle:hQuery, szError[], iErrCode, szData[], iDataSize, Float:fQueueTime) {
  91.     if (iErrCode)
  92.         log_amx("[SQL HIBA] %s", szError)
  93.  
  94.     if (iFailState == TQUERY_CONNECT_FAILED)
  95.         set_fail_state("SQL Connection Failed")
  96.     else if (iFailState == TQUERY_QUERY_FAILED)
  97.         set_fail_state("SQL Query Failed")
  98. }


Trie vs Array:

Ebbe nem megyek bele, mert sokkal nehezebb leegyszerűsíteni mint a többit, valamint nem férne bele ennek a posztnak a scopejába. Röviden:
- Trie-t érdemes használni, ha stringeket tárolunk
- Trie-ba könnyebb keresgélni. Vannak jó use-casek, pl. prefix használat chatbe, mute rendszer, stb.
- Többi usecase dynamic array.
- Mindkettő gyorsan olvas, viszont lassan ír

Ui:
Hasznos: Akosch:. @ [TUT] Bitműveletek, [TUT] [AlliedModders] Dynamic Array, [TUT] [AlliedModders] const vs #define

_________________
Zombie Mutation

Kép

Ők köszönték meg DexoN nek ezt a hozzászólást (összesen 3):Csabika20034 (Tegnap, 11:32) • Dooz (Tegnap, 15:37) • koko.988 (Tegnap, 21:06)
  Népszerűség: 6.82%


Hozzászólás jelentése
Vissza a tetejére
   
Hozzászólások megjelenítése: Rendezés 
Új téma nyitása Hozzászólás a témához  [1 hozzászólás ] 


Ki van itt

Jelenlévő fórumozók: nincs regisztrált felhasználó valamint 1 vendég


Nyithatsz új témákat ebben a fórumban.
Válaszolhatsz egy témára ebben a fórumban.
Nem szerkesztheted a hozzászólásaidat ebben a fórumban.
Nem törölheted a hozzászólásaidat ebben a fórumban.
Nem küldhetsz csatolmányokat ebben a fórumban.

Keresés:
Ugrás:  
Powered by phpBB® Forum Software © phpBB Limited
Magyar fordítás © Magyar phpBB Közösség
Portal: Kiss Portal Extension © Michael O'Toole