Popular Post Scydo 397 Odesláno: 4. Srpen, 2016 Popular Post Share Odesláno: 4. Srpen, 2016 sscanf2***** Zdravím vás u dalšího návodu, konkrétně o velice populárním a dost často používaném pluginu a to sscanf. Jde o plugin, který mnoha uživatelům vypomáhá při tvorbě více parametrových příkazů či u více informačních údajů(například inputtext) v samp.Obsah Ukázka použití Specifikátory Integer String Pole Enum Velké specifikátory Integer String Pole Enum Použití Změnit hráčovi počet životů Zabanovat hráče s důvodem Nahrát více údajů v jednom souboru Download Závěr Ukázka použitíHodně uživatelů využívá tuhle funkci hlavně v podmínkách v příkazech, například: if (sscanf(params, "ui", ID, Penize)) return SendClientMessage(playerid, -1, "Použití: /prachy [ID/Jméno hráče] [Počet]"); Jak to funguje? Vezme údaje ze params, a z celého řetězce zjistí, kde tam jsou dané datové typy, a to u nebo-li string(číslo nebo nick hráče, či jeho součást) a i nebo-li integer, a dosadí do daných proměnných(ID a Peníze), a podmínka nám vrací true/false dle toho, zda při rozdělovaní (ne)vzniknou nějaké komplikace, například jeden z údajů chybí, nebo nenašel v řetězci daný datový typ(například místo čísla aka peněz napíšete nějaký string. Funkce to vyhodnotí jako text, nikoliv číslo a chyba). Díky mezeře mezi id hráče a množství peněz funkce rozezná, že jde o další argument, a nevezme to celé, jako jeden text. V případě, že jste to nepochopili, můžeme si to ukázat na jiném příkladě. Jelikož sscanf2 je funkce, lze jí jednoduše používat i bez podmínek: new String[15] = "abcd", Cislo = 0; sscanf("Potrebuji 1000", "si", String, Cislo); printf(" %s %i", String, Cislo); Právě jsme si deklarovali 2 proměnné a to String a k němu jsme si přiřadili hodnotu "abcd" a proměnnou Cislo s přiřazenou hodnotou 0. Nyní využijeme fci sscanf, aby vzal daný řetězec a to Potrebuji 1000 a rozdělil je do těchto 2 proměnných. Jak si můžete všimnout, obsahuje 2 datové typy a to string a integer. Takže jelikož první údaj je string tak logicky první specifikátor(o nich později) bude s, a druhé je číslo, takže specifikátor bude i. Nyní se nám za proměnné dosadí oba údaje a do konzole se nám vypíše Potrebuji 1000, a ne abcd 0. Do konzole se nám také vypíše varování sscanf warning: Strings without a length are deprecated, please add a destination size.. V překladu a zjednodušeně toto varování znamená, že specifikátor s(tring), potřebuje nějakou délku, takže ji můžete jednoduše přidat(ale pozor, délka musí být dostatečně velká, aby se do ní vešel celý daný řetězec!): sscanf("Potrebuji 1000", "s[10]i", String, Cislo); SpecifikátoryNebudu tu vypisovat všechny specifikátory, které sscanf obsahuje, ale jen prozatím ty, které uživatelé používají asi nejčastěji: Specifikátor Jméno Příklad i, d Integer 4, 72, -1024 [/td] --> s String Ahoj, Admin, sb75c4 l Boolean true, false f Float 0.5, 33.1, -99.9 h, x Hex FF, 0xAD35 u Jméno/ID hráče a botů SkiBig18, 2 r Jméno/ID hráče SkiBig18, 2 Integer Specifikátor se značí písmenkem i nebo d. Nejjednoduší specifikátor. Jde rozdělit 2 nebo i více řad čísel do daných proměnných, například: new Cislo1 = 0, Cislo2 = 0; sscanf("100 200", "ii", Cislo1, Cislo2); printf("%i %i", Cislo1, Cislo2); /* Vypíše 100 200 */ Není problém ani s řadou čísel, jen si musíte hlídat počet íček: new Cislo[6]; sscanf("1 4 9 2 -1 5", "iiiiii", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); printf("%i %i %i %i %i %i", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); V případě, že vynecháte jedno z íček, sscanf poslední hodnotu specifikuje jako 0 a také jí dosadí. To stejné platí i u stringu: sscanf("1 4 9 2 -1 5", "iiiii", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); printf("%i %i %i %i %i %i", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); /* Vypíše 1 4 9 2 -1 0 */ Lze nahradit písmeno i také písmenem d, výsledek i efekt bude naprosto stejný: sscanf("1 4 9 2 -1 5", "dddddd", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); printf("%i %i %i %i %i %i", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); /* Vypíše 1 4 9 2 -1 5 */ String Specifikátor se značí písmenkem s. Další nejčastěji používaný specifikátor. Používá se hlavně v příkazech pro důvody. Ale sscanf2 nabízí více možností práce se stringem.Jak jsem již na začátku ukazoval, kód: sscanf("Potrebuji 1000", "si", String, Cislo); Vypíše Potrebuji 1000. Ale co, když chceme do první proměnné přidat ještě slovo? sscanf("Potrebuji ihned 1000", "s[10]i", String, Cislo); Tak selže dosazování, jelikož slovo ihned není číslo, a po slově Potrebuji doplní nulu a tím končí. Řešení je prosté. Stačí buď přidat další specifikátor: new String[2][10], Cislo; sscanf("Potrebuji ihned 1000", "s[16]s[6]i", String[0], String[1], Cislo); printf("%s %s %i", String[0], String[1], Cislo); /* Vypíše Potrebuji ihned 1000 */ A nebo vynechat číslo a nechat jen jeden specifikátor pro celý text: new String[16]; sscanf("Potrebuji ihned", "s[16]", String); print(String); /* Vypíše Potrebuji ihned */ Ale problém je teď, že specifikátor vezme celý text, nebo-li všechno po slovech Potrebuji ihned(pokud samozřejmě bude mít větší délku). V případě, že potřebujeme jen samostatně jediné slovo, stačí přidat po specifikátoru mezeru: new String[16]; sscanf("Potrebuji ihned", "s[16] ", String); print(String); /* Vypíše Potrebuji */ Všimněte si, že i když délka specifikátoru je 16, stejně vezme jen slovo Potrebuji. Takže jakákoliv délka vám vůbec neovlivní výsledek Pole Specifikátor se značí písmenkem a<>. Práce s polem u sscanf je podobné jako stringu, s tím rozdílem, že velikost pole nepoužíváme jako délku, ale k dosazení počtu prvků, a za každý prvek se dosadí daná hodnota v poli určité proměnné, například: new Pole[5]; sscanf("1 3 8 6 2", "a<i>[5]", Pole); printf("%i %i %i %i %i", Pole[0], Pole[1], Pole[2], Pole[3], Pole[4]); /* Vypíše 1 3 8 6 2 */ Jak si můžete všimnout, specifikátory pro jediné pole jsou 2 a to a(array v překladu pole), a i jako integer. Aby si sscanf nepletlo pole a velikost retězce, využíváme na začátek specifkátoru pro pole, jiné závorky, a to <>. Specifikátor i pak obsahuje datové typy pole nebo-li čísla. A nakonec [5] je maximální počet buněk v poli.Samozřejmě lze kombinovat i jiné datové typy v poli, například string: new String[3][3 + 1]; sscanf("Abc Ab A", "a<s[4]>[3]", String); printf("%s %s %s", String[0], String[1], String[2]); /* Vypíše Abc Ab A */ Jak to funguje tady? Deklarovali jsme si 3 řetězce s počtem 4 znaků (3 + nul. znak). Za každý řetězec dosadí specifická písmena. Je to úplně stejné jako bychom retězci0( String[0] ) přiřadili hodnotu "Abc", řetězci1( String[1] ) hodnotu "Ab" a řetězci2( String[2] ) hodnotu "A". Enum Specifikátor se značí písmenkem e<>. Tento dodatek se považuje za nejlepší dodatek v sscanf. A ani se nedivím, jelikož vám umožní měnit výčet hodnot dokonce v samotném enumu. A jako u pole i zde platí, že lze přepsat všechny datové typy. Ale je to pár rozdílů, jeden z nejrelevantnějších je, že musíte vypsat všechny specifikátory všech datových typů, co enum obsahuje(logicky, jinak by sscanf nevěděl, jakou proměnnou má přesně v enumu přepsat). Ukážeme si to na příkladu: enum enum_PlayerInfo { e_AdminLevel, e_VipLevel, e_VipBodu, } new e_Enum[enum_PlayerInfo]; sscanf("5 1 1000", "e<iii>", e_Enum); printf("%i %i %i", e_Enum[e_AdminLevel], e_Enum[e_VipLevel], e_Enum[e_VipBodu]); /* Vypíše 5 1 1000 */ Zde jsem si deklarovali proměnnou s výčtem hodnot, který obsahuje AdminLevel, VipLevel a počet bodů. Sscanf nám zjistí ze všech specifikátorů ve specifikaci struktury v enumu(nebo-li v <>), že jde o čísla a tak přepíše hodnoty. Ano, práce s polem je mu velice podobná a teď zkusíme zapojit více datových typů a všem nastavíme nějakou hodnotu: enum enum_Info { e_Integer, e_String[24], Float: e_Float, e_Char } new e_Enum[enum_Info]; sscanf("10 Ahoj 12.33 c", "e<is[24]fc>", e_Enum); printf("%i %.2f %s %c", e_Enum[e_Integer], e_Enum[e_Float], e_Enum[e_String], e_Enum[e_Char]); /* Vypíše 10 12.33 Ahoj c */ Velké specifikátoryV případě, že vložíme prázdný řetězec(či neúplný), můžeme mu při rozdělení přidat i tzv. "defaultní hodnoty", které pak dosadí, nejjednodušší příklad: Integer new Cislo; sscanf("", "I(10)", Cislo); printf("%i", Cislo); /* Vypíše 10 */ Specifikátor se značí písmenkem I nebo D. Jak si můžeme všimnout, sscanf dostal prázdný řetězec na rozdělení. Tak jak je možné, že se nám do konzole odešle 10? Je to prosté: U specifikátorů datových typů, jsme zaměnili malé i za velké I, což je znamení pro sscanf, že v případě, že tam hodnotou nenajde v řetězci, ať tam doplní jinou, a ta hodnota se přidává do kulatých závorek (). Samozřejmě, lze nastavit defaultní hodnoty i více prom. například: new Cislo1, Cislo2; sscanf("", "I(10)I(20)", Cislo1, Cislo2); printf("%i %i", Cislo1, Cislo2); /* Vypíše 10 20 */ String Specifikátor se značí písmenkem S. Tady je to zajímavější, jelikož defaultní hodnotu u stringu nemusíme psát do uvozovek: new String[4 + 1]; sscanf("", "S(Ahoj)", String); print(String); /* Vypíše */ Samozřejmě nesmíme zapomenout na délku stringu, jelikož nám to hodí varování. Doplňujeme zásadně až za defaultní hodnotou: new String[4 + 1]; sscanf("", "S(Ahoj)[5]", String); print(String); /* Vypíše Ahoj */ Pole Specifikátor se značí písmenkem A<>. Ani tady není extra rozdíl. Může se hodit při doplňování hodnot, například: new Pole[3]; sscanf("1 2", "A<i>(3)[3]", Pole); printf("%i %i %i", Pole[0], Pole[1], Pole[2]); /* Vypíše 1 2 3 */ Všimněte si ale, že nesmíme přepsat specifikátor integeru, v poli na velké písmenko ale musíme celé pole. I tady je funkčnost jednoduchá. Pole, které jsme si deklarovali má 3 prvky. My mu ale doplníme jenom 2. Díky velkému písmenku A informujeme sscanf, že tam nebudou všechny údaje, a tak poslednímu ať defaultně přiřadí hodnotu 3. A co, když tam nebudou například 2? Postup je stále stejný: sscanf("1", "A<i>(1, 2)[3]", Pole); A jak postup, tak výsledek bude stejný. Sscanf dostane na rozdělení pouze jeden údaj ze 3, které mají být správně v poli, a tak vezme defaulní hodnoty a doplní je. Ale co, když nastavíme defaulní hodnotu pouze 1 na 2 chybějící prvky?: sscanf("1", "A<i>(2)[3]", Pole); Tady sscanf nemá moc na vybranou. I když jeho primárním cílem bude doplnit všechny hodnoty do pole, dostane jen jednu defaultní, a zapracuje velice zajímavě: vezme tu jedinou defaultní a doplní je do všech prvků v poli, takže ve výsledku se nám do konzole vypíše 1 2 2 Enum Specifikátor se značí písmenkem E<>. Tady je problém, že uživatel ne jen, že musí přidávat všechny specifikátory ve výčtu, ale také ještě v případě práce s defaultními hodnotami v enumu musí vypsat k každému údaji defaultní hodnotu, i když už nějakou má, například: sscanf("11", "E<iii>(11, 22, 33)", epromenna); printf("%i %i %i", epromenna[e_cislo], epromenna[e_cislo2], epromenna[e_cislo3]); /* Vypíše 11 22 33 */ Jak si můžete všimnout, v řetězci je 11, ale stejně jí musíme přidat do defaultních hodnot. Na závěr kapitoli něco trošku těžšího: sscanf("", "E<s[5]fs[6]ii>(Ahoj, 11.2, Scydo, 11, 22)", epromenna); print(epromenna[e_String]); printf("%.1f", epromenna[e_Float]); print(epromenna[e_String2]); printf("%i", epromenna[e_Integer]); printf("%i", epromenna[e_Integer2]); /* Vypíše: Ahoj 11.2 Scydo 11 22 */ Použití Změnit hráčovi počet životů #include <i-zcmd> /* http://pawno.cz/topic/53498-i-zcmd/ */ #include <sscanf2> CMD:sethealth(playerid, params[]) { if (!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "Nejste rcon administrátor !"); new id, Float: health; if (sscanf(params, "rf", id, health)) return SendClientMessage(playerid, -1, "Použití: /sethealth ID/Jméno hráče Počet životů"); if (id == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Hráč není připojený !"); if (health < 1.0 || health > 100.0) return SendClientMessage(playerid, -1, "Lze nastavit jen 1-100.0 hp !"); new sPlayerNick[MAX_PLAYER_NAME + 1], sNick[MAX_PLAYER_NAME], sString[102 + 1]; GetPlayerName(playerid, sPlayerNick, sizeof sPlayerNick);GetPlayerName(playerid, sNick, sizeof sNick); format(sString, sizeof sString, "Administrátor %s nastavil hráči %s život na %.1f", sPlayerNick, sNick, health); SendClientMessageToAll(0xFF000000, sString); return true; } Zabanovat hráče s důvodem CMD:ban(playerid, params[]) { if (!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "Nejste rcon administrátor !"); new id, duvod[124 + 1]; if (sscanf(params, "rs[125]", id, duvod)) return SendClientMessage(playerid, -1, "Použití: /ban ID/Jméno hráče Důvod"); if (id == INVALID_PLAYER_ID) return SendClientMessage(playerid, -1, "Hráč není připojený !"); if (strlen(duvod) > 124) return SendClientMessage(playerid, -1, "Uvedl jste příliš dlouhý důvod !"); new sPlayerNick[MAX_PLAYER_NAME + 1], sNick[MAX_PLAYER_NAME], sString[102 + 1]; GetPlayerName(playerid, sPlayerNick, sizeof sPlayerNick);GetPlayerName(playerid, sNick, sizeof sNick); format(sString, sizeof sString, "Administrátor %s zabanoval hráče %s, důvod: %s", sPlayerNick, sNick, duvod); SendClientMessageToAll(0xFF000000, sString); SetTimerEx("BanTimer", 1000*1, false, "d", id); return true; } Nahrát více údajů v jednom souboru /* Vyčtení */ fread(Cesta, ObsahSouboru); sscanf(ObsahSouboru, "ifffs[24]i", GangInfo[gangid][Kasa], GangInfo[gangid][PoziceX], GangInfo[gangid][PoziceY], GangInfo[gangid][PoziceZ], GangInfo[gangid][Vudce], GangInfo[gangid][Clenu]); /* Zápis */ format(ObsahSouboru, sizeof ObsahSouboru, "%i %.3f %.3f %.3f %s %i", GangInfo[gangid][Kasa], GangInfo[gangid][PoziceX], GangInfo[gangid][PoziceY], GangInfo[gangid][PoziceZ], GangInfo[gangid][Vudce], GangInfo[gangid][Clenu]); fwrite(Cesta, ObsahSouboru); DownloadTo už je složitější, jelikož i když se vydala nová verze, spousty uživatelů hlásí, že buď je tam něco nefunkční a nebo samotná verze nefunguje. Proto jsem vám pro jistotu nahrál verzi sscanfu, kterou používám já a použil jsem ho i na kódy v tomto návodě, a je plně funkční:https://uloz.to/!vV4WzRFEG/sscanf2-zipIhned na začátek zdrojového kódu samozřejmě nesmíte zapomenou sscanf vůbec nahrávat: #include <sscanf2> A do konfigurace serveru do řádku pro nahrávání pluginů na Windows vepíšete: plugins sscanf V případě Linuxu: plugins sscanf.so ZávěrNaschvál jsem vynechal spousty ještě dodatků v sscanf2, například "quite" stringy, jelikož nevidím moc lidí, co by to tady využívalo.A na závěr bych chtěl dodat, že některá teoretická vysvětlení se mohou zdát neúplná, pozměněná a nebo trošku špatná. Důvodem je, že zcela správnÁ vysvětlení by prostý začátečník nebo i čtenář nepochopil. Samozřejmě, pokud mám některé hrubější chybu v kódě nebo v teorii, jak mi napište. Ověřený návod Tento návod prošel validací, a lze ho proto považovat za ověřený. 5 Link to comment Share on other sites More sharing options...
Hlavní moderátor vEnd 279 Odesláno: 4. Srpen, 2016 Hlavní moderátor Share Odesláno: 4. Srpen, 2016 Solidní návod, i já jsem se něčemu přiučil (nikdy jsem nedělal s pluginovou verzí). Ověřeno a přesunuto. Link to comment Share on other sites More sharing options...
Paulee 16 Odesláno: 4. Srpen, 2016 Share Odesláno: 4. Srpen, 2016 Dost dobrý návod. Vše krásně rozepsané a srozumitelné. Určitě pokračuj s dalšími návody. GJ Link to comment Share on other sites More sharing options...
Pán Podnikateľ 52 Odesláno: 5. Srpen, 2016 Share Odesláno: 5. Srpen, 2016 Ďalší skvelí a prešpekulovaný tutoriál. Hádam na to nováčikovia narazia a budú ho používať tak ako majú. Tiež si vypomohol väčšej časti ktorá nevie anglicky tím pádom čo nie je na pawno.cz ako by neexistovalo. Dúfam že budeš písať ďalšie návody do budúcna a budu rovnako skvelo popísané ako dnes. Na záver môžem dodať " Len tak ďalej ". ps. Vďaka za spomenutie parametru r. 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now