Popular Post Scydo 397 Odesláno: 17. Duben, 2016 Popular Post Share Odesláno: 17. Duben, 2016 PŘECHOD Z DINI/DCMD/JINÉ NA YSI4 ***** Je to až k neuvěření... dini oslavuje 10 let od doby jeho první publikace(8 let od jeho poslední aktualizace) a stejně se najde spousty uživatelů, kteří si ho bez nějakých námitek vesele používání, a prohlašují ho za nejlepšího, i když ani nemají ponětí jak přesně funguje. To samé dcmd. A navíc, o nějaké lepší, rychlejší a efektivnější variantě nechtějí ani slyšet, protože buď zatvrdnou na nich a ostatní je pro ně pitomost nebo moc složité i přesto, že je to neuvěřitelných 80% to samé. Myslím, že je asi zbytečné vám vysvětlovat funkčnost dini/dcmd a jejich pomalost. Zkušenější to už dávno ví a snaží se to vtlouc začátečníkům, kteří buď o tom nic neví, nebo to nechápou či to ignorují. Chci se zaměřit na ukázky hlavně v kódě. Ale nenechte se zmást. I když mají uživatelé YSI za neskutečně rychlou, už se najdou i rychlejší includy. Akorát, k čemu si stahovat celou knihovnu a z ní využít jen pár includů a pak si postahovat ty rychlejší? Nikdo vám za to nemůže utrhnout hlavu, když budete pracovat jen s knihovnou, protože už jenom, že se odvážíte pracovat s YSI je pro ně něco.V tomto topicu vám nechci jen popsat, jak jednoduše přejít z dcmd a dini na YSI4, ale také další změny v kódě, například práce s timery, cyklusem a tak dále. A do budoucna doufám, že v případě, kdyby si někdo neuměl představit jak přejít na YSI, nebo by ho měl za složité, tak, že bych mu mohl já nebo někdo z uživatelů mu odeslat odkaz na tento topic, aby se přesvědčil o opaku.Chtěl bych upozornit, že tento topic je doporučen především pro uživatele, co už mají přehled, jak funguje jaká funkce či callbacky. Proto se nechci zdržovat s vysvětlováním některých fcí, které se objeví v tomto topicu.Obsah Ukládání a načítání - Ukázka, jak můžeme jednoduše přejít z dini na y_ini. Příkazy - Ukázka, jak je jednoduché přejít z dcmd na y_commands. Proměnné - Ukázka, jaký je rozdíl práce klasicky s proměnnými a s y_playerarray + y_bit. Formátování - Ukázka, jak nám y_va velice usnadní práci s formátováním například zpráv. Dialogy - Ukázka, jak nám y_dialog pomůže s dialogID a všeobecně s prací s dialogy. Cyklus - Ukázka, jak y_iterate může zjednodušit práci s cyklusem. Callback - Ukázka, jak můžeme jednodušeji hookovat callbacky pomocí y_hooks jinak, než pomocí preprocesoru "ALS". Timer - Ukázka, jak je jednoduché přejít z klasického timeru na y_timers. Použito z knihovny Závěr Ukládání a načítáníUkládání a načítání je docela základní záležitost. Hlavně pro registraci a přihlášení. Ale pracovat na tom s dini je zbytečně zdlouhavé a ještě velice pomalé. Je desítek návodů na dini, samozřejmě i na jeho mnohonásobně lepší variantu dof2, najdou se dokonce návody i na y_ini, ale nikdo je moc nechápe, proto zůstávájí u toho dini s tím, že si myslí, že je to jednodušší. Ale dělat na registraci s y_ini není o nic moc složitější. Tady je taková rychlá jednoduchá registrace přes dini: new iALevel[MAX_PLAYERS], sHeslo[MAX_PLAYERS][60], Float: fHealth[MAX_PLAYERS], bool: bIsVip[MAX_PLAYERS]; public OnPlayerConnect(playerid) { new sSoubor[50 + 1], sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); format(sSoubor, sizeof(sSoubor), "%s.sav", sNick); if(dini_Exists(sSoubor)) ShowPlayerDialog(playerid, 2, DIALOG_STYLE_INPUT, "Přihlášení", "Zadejte heslo pro přihlášení:", "Potvrdit", "Odejit"); else ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, "Registrace", "Zadejte heslo pro registraci:", "Potvrdit", "Odejit"); return (true); } public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { switch(dialogid) { case 1: { if (!response) return Kick(playerid); if (!strlen(inputtext)) return ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, "Registrace", "Zadejte heslo pro registraci:", "Potvrdit", "Odejit"); new sSoubor[50 + 1], sNick[MAX_PLAYER_NAME + 1]; GetPlayerHealth(playerid, fHealth[playerid]); GetPlayerName(playerid, sNick, sizeof(sNick)); format(sSoubor, sizeof(sSoubor), "%s.sav", sNick); dini_Create(sSoubor); dini_IntSet(sSoubor, "AdminLevel", iALevel[playerid]); dini_Set(sSoubor, "Heslo", inputtext); dini_FloatSet(sSoubor, "Health", fHealth[playerid]); dini_BoolSet(sSoubor, "IsVip", bIsVip[playerid]); return (true); } case 2: { if (!response) return Kick(playerid); if (!strlen(inputtext)) return ShowPlayerDialog(playerid, 2, DIALOG_STYLE_INPUT, "Přihlášení", "Zadejte heslo pro přihlášení:", "Potvrdit", "Odejit"); new sSoubor[50 + 1], sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); format(sSoubor, sizeof(sSoubor), "%s.sav", sNick); format(sHeslo[playerid], sizeof(sHeslo[playerid]), dini_Get(sSoubor, "Heslo")); if (strcmp(inputtext, sHeslo[playerid], false)) return ShowPlayerDialog(playerid, 2, DIALOG_STYLE_INPUT, "Přihlášení", "Hesla se neshodují", "Potvrdit", "Odejit"); iALevel[playerid] = dini_Int(sSoubor, "AdminLevel"); SetPlayerHealth(playerid, dini_Float(sSoubor, "Health")); bIsVip[playerid] = dini_Bool(sSoubor, "IsVip"); return (true); } } return (false); } (INFO Ano, prozatím se nebudeme zdržovat s hashováním hesla. A také nepřidám i ukládání při odchodu, protože je to prakticky to samé, jako je v callbacku s dialogem přihlašování).Teď si ten samý script uděláme pomocí YSI knihovny. V případě, že ostatním funkcím nerozumíte, tak nevadí. Dozvíte se o nich později v topicu. Začneme v OnPlayerConnect(). Především budeme pracovat s podmínkou existence souboru. Můžeme jí nahradit, že v případě, že neexistuje jeho soubor, zobrazí se dialog s registrací, a pokud ano, tak načteme údaje ze souboru(kvůli heslu hlavně), a zobrazíme dialog s přihlašováním.Ano, já vím. Načítám už všechny ostatní údaje (život, adminlevel...), když se ještě ani nepřihlásil. Ale to nevadí, jelikož, pokud nezadá správné heslo, tak se stejně na server nedostane. A když ho zadá správně, tak se nemusíme zdržovat s načítáním už: public OnPlayerConnect(playerid) { new sSoubor[50 + 1], sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); format(sSoubor, sizeof(sSoubor), "%s.sav", sNick); if (!fexist(sSoubor)) Dialog_ShowCallback(playerid, using callback dRegistrace, DIALOG_STYLE_INPUT, "Registrace", "Zadejte heslo pro registraci", "Potvrdit", "Odejit"); else{ INI_ParseFile(sSoubor, "NacistData", .bExtra = true, .extra = playerid); Dialog_ShowCallback(playerid, using callback dPrihlaseni, DIALOG_STYLE_INPUT, "Přihlášení", "Zadejte heslo pro přihlášení", "Potvrdit", "Odejit"); } return (true); } A nyní vše načteme. Funkce pro načítání si jsou dosti podobné s dini(jak později uvidíte v tabulce). Nebude tak obtížné se je naučit. Všimně te si, že nemusíme už zadávat adresu souboru, odkud to má načítat. Callback už to zná, stejně jako funkce: forward NacistData(playerid, name[], value[]); public NacistData(playerid, name[], value[]) { INI_Int("AdminLevel",iALevel[playerid]); INI_String("Heslo", sHeslo[playerid], 60); INI_Float("Health", fHealth[playerid]); INI_Bool("IsVip", bIsVip[playerid]); SetPlayerHealth(playerid, fHealth); return (false); } A nakonec už jen samotné callbacky s dialogy. Oba budou samozřejmě kontrolovat, zda hráč nezadal žádné heslo. U registrace nemusíme zjišťovat, jestli hráčův soubor neexistuje pro vytvoření, jelikož INI_Open ho vytvoří automaticky v případě, že neexistuje, a nesmíme zapomenout soubor zavřít. U přihlášení samozřejmě zkontrolujeme, zda nezadal špatné heslo. Jelikož jsme už údaje načetli, nemusíme naše heslo znova zjišťovat ze souboru, už s naší proměnnou můžeme pracovat rovnou. Stejně jako načítání, i zde jsou callbacky. Musíme přidat i forward: forward dRegistrace(playerid, dialogid, response, listitem, inputtext[]); forward dPrihlaseni(playerid, dialogid, response, listitem, inputtext[]); public dRegistrace(playerid, dialogid, response, listitem, inputtext[]) { if (!response) return Kick(playerid); new sSoubor[50 + 1], sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); GetPlayerHealth(playerid, fHealth[playerid]); format(sSoubor, sizeof(sSoubor), "%s.sav", sNick); new INI: Soubor = INI_Open(sSoubor); INI_WriteInt(Soubor, "AdminLevel", iALevel[playerid]); INI_WriteString(Soubor, "Heslo", sHeslo[playerid]); INI_WriteFloat(Soubor, "fHealth", fHealth[playerid]); INI_WriteBool(Soubor, "IsVip", bIsVip[playerid]); INI_Close(Soubor); return (true); } public dPrihlaseni(playerid, dialogid, response, listitem, inputtext[]) { if (!response) return Kick(playerid); if (strcmp(inputtext, sHeslo[playerid], false)) return Dialog_ShowCallback(playerid, using callback dPrihlaseni, DIALOG_STYLE_INPUT, "Přihlášení", "Hesla se neshodují", "Potvrdit", "Odejit"); SendClientMessage(playerid, -1, "Úspěšně jste se přihlásil"); return (true); } U přihlášení můžeme i přidat zprávu, že se přihlásil. Jinak nemusíme nic více, jelikož vše se jíž načetlo.No, nevím co vy, ale podle mě je to mnohem přehlejší, kratší, jednoduší... a dokonce i mnohem rychlejší jak po stránce tvorby, tak po stránce funkčnosti.To byla jen ukázka, kde jsme použili ukládání 4 základních datových typů (integer, string, float a boolen). Aby jste viděli, že v práci mezi dini a y_ini není tak velký rozdíl, připravil jsem si pro vás 2 tabulky. Obě obsahují dini a y_ini, a obě obsahují fce a informace k nim:Funkce pro ukládání a vepisování údajů [/td]td --> dini YSI Účel Funkce Informace Funkce Informace Vytvořit soubor dini_Create(); - INI_Open INI_Open otevře a zároveň vytvoří sbr v případě, že neexistuje. Používá ještě tag INI: jako mají files File: Zavřít soubor - Zavírá soubor zbytečně při každém vepsání! INI_Close(); - Existence sbr dini_Exists Je to prakticky jen preprocesor fce fexist - - Vepsat tag - - INI_SetTag(); Jde jen o poznámku, ale lze i šikovně využít. Vepsat integer dini_IntSet - INI_WriteInt(); - Vepsat string dini_Set - INI_WriteString(); - Vepsat float dini_FloatSet - INI_WriteFloat(); - Vepsat boolen dini_BoolSet - INI_WriteBool(); - Vepsat hex - - INI_WriteHex(); - Vepsat bin - - INI_WriteBin(); - Funkce pro načítání údajů dini YSI Účel Funkce Informace Funkce Informace Načíst všechny údaje--INI_ParseFile();Všechny fce na načítaní pak stačí přidávat do callbacku.Načíst integerdini_Int-INI_Int();-Načíst stringdini_Get-INI_String();Musíte do fce přidat i délku.Načíst floatdini_Float-INI_Float();-Načíst boolendini_Bool-INI_Bool();-Načíst hex--INI_Hex();-Načíst bin--INI_Bin();-PříkazyPawn obsahuje sice callback, který zjišťuje, zda hráč zadal příkaz, ale zjistit, co zadal po příkazu (tzv. parametry) není už tak jednoduché. Takže, začátečníkům dělá problémy vytvořit příkazy s id, například /heal [iD_hráče]. Ale na internetu je jednoduché řešení, a to za pomoci includu. Akorát, velká většina skončí u dcmd.Jakmile přidáte do kódu patřičný preprocesor (pro jeho "nahrání"), tak využití je celkem jednoduché a prosté:dcmd_prikaz(playerid, params[]) { Avšak to není všechno. S každým příkazem musíme ještě přidat takovou "funkci" ještě do callbacku OnPlayerCommandText. Nechci se zdržovat s vysvětlováním o co přesně je a co to dělá, ale jde o:public OnPlayerCommandText(playerid, cmdtext[]) { dcmd(prikaz, 6, cmdtext); Není to tak hrozné, ale představte si, že to budete muset psát pro každičký příkaz, a jakmile zapomenete jen jediný, tak nám to nepůjde a budeme se divit proč.Všimněte si, jak je každé přidávání příkazu zpracováno: nejdříve samotné slovíčko dcmd, což je i jméno preprocesoru, díky kterému můžeme naše příkazy přidávat, pak spodní podtržítko a jméno příkazu a nakonec parametry playerid a params. Okej... nyní to porovnáme se zápisem y_commands:YCMD:prikaz(playerid, params[], help) { Jako u dcmd, je také nějaké označení, že přidáváme příkazy s parametrem a to YCMD, pak to pokračuje podobně akorát místo spodního podtržítka je tam dvojtečka a za ní jméno příkazu, a nakonec také parametry playerid a params, včetně help. Parametr help nám vrací true v případě, že hráč napíše příkaz a za ním otazník (například /admins ?), nebo nemusí to být otazník ale cokoliv jiného. Ale, když ho nebudete využívat, nic ne nestane.Nyní, kde je takový rozdíl? Není nějak extrémně velký, pro ukázku obě přidávání příkazu:dcmd_prikaz(playerid, params[]) { YCMD:prikaz(playerid, params[], help) { Rozdíl v zápisu tak velký není ale po stránce funkčnosti je celkem dost značný. Hlavně po stránce rychlosti, jelikož y_commands pracuje na principu, že každý příkaz bere jako nějaké id, jelikož hledání/porovnávání stringu(textu) je mnohem pomalejší. Ale také y_commands obsahuje další vychytávky, například přidávání alternativných příkazů:public OnScriptInit() { Command_AddAltNamed("help", "pomoc"); Nyní, když přidáme příkaz help, tak automaticky už je /help to samé jako /pomoc a nemusíme nikde nic vracet či přidávat znovu obsah příkazu.Nebo také lze jednoduše povolit, zda se hráčovi povede příkaz napsat. V případě, že je mu nastaveno false, bude to pro něj, jako by ten příkaz neexistoval: if (!IsPlayerAdmin(playerid)) { Command_SetPlayerNamed("kick", playerid, false); } Nyní si ukážeme nějakou rozsáhlejší ukázku, například zrovna příkaz /heal [iD_hráče], nejdříve využijeme dcmd: dcmd_heal(playerid, params[]) { if (!strlen(params)) return SendClientMessage(playerid, -1, "Použití příkazu: /heal [ID_hráče]"); new id = strval(params); if (!IsPlayerConnected(id)) return SendClientMessage(playerid, -1, "Hráč není připojený !"); new sString[144 + 1], sAdminNick[MAX_PLAYER_NAME + 1], sPlayerNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sAdminNick, sizeof(sAdminNick)); GetPlayerName(id, sPlayerNick, sizeof(sPlayerNick)); format(sString, sizeof(sString), "Admin %s uzdravil hráče %s", sAdminNick, sPlayerNick); SendClientMessageToAll(-1, sString); SetPlayerHealth(id, 100.0); return (true); } public OnPlayerCommandText(playerid, cmdtext[]) { dcmd(heal, 4, cmdtext); return (false); } Teď to zkusíme s y_command. První co změníme je naše první slovíčko a to ze dcmd_ na YCMD:. Dále přidáme parametr help. Využijeme již formátované zprávy ze y_va, a nakonec vymažeme naší "funkci" z callbacku: YCMD:heal(playerid, params[], help) { if (isnull(params)) return SendClientMessage(playerid, -1, "Použití příkazu: /heal [ID_hráče]"); new id = strval(params); if (!IsPlayerConnected(id)) return SendClientMessage(playerid, -1, "Hráč není připojený !"); new sAdminNick[MAX_PLAYER_NAME + 1], sPlayerNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sAdminNick, sizeof(sAdminNick)); GetPlayerName(id, sPlayerNick, sizeof(sPlayerNick)); va_SendClientMessageToAll(-1, "Admin %s uzdravil hráče %s", sAdminNick, sPlayerNick); SetPlayerHealth(id, 100.0); return (true); } Žádný extra rozdíl, co? Každopádně je to kratší samozřejmě a nemusíme přidávat naší "funkci" do callbacku. Ale jak jsem říkal, po stránce funkčnosti je tam značný rozdíl.ProměnnéDalší ukázky se už netýkají dini a dcmd, ale spíše, kdyby jste dělali na gamemodu či scriptu, tak jak přejít na YSI a pracovat s knihovnou.V téhle části jde o práci s proměnnými, přesněji s datovým typem boolen a polem. Zkušenější, možná i někteří začátečnicí ví, že ke každé proměnné můžeme přidat pole, a čím větší to pole je, tím více zabírá paměti. Například proměnná: new bool:Promenna[MAX_PLAYERS]; Jak jistě někteří ví, tak MAX_PLAYERS není nic více než jen preprocesor pro číslo 500. Když si nyní trošku započítáme, tak zjistíme z příkladu 500*4 že touto jedinou proměnnou využijeme až 2 000 bajtů. Teď si jich představte například deset. Nemluvě o tom, že některé publikované gamemody se zdrojovým kódem obsahují až stovky takových proměnných. Můžeme využít i char, které nám pole vydělí 4, a využití paměti spadne už na 500 bajtů, ale furt je to dost. Ale, když přidáme proměnnou pomocí y_bite:new BitArray:Promenna<MAX_PLAYERS>; Tak využití paměti spadne už jen na pár desítek bitů(nejsem si jistý přesným číslem).Nojo, ale, když chceme zjistit, jestli má hráč premium, tak jak to uděláme? Jednoduše, přidáme si naší proměnnou(když je to pro hráče hodí se využít y_playerarray):new PlayerArray:bIsPremium<MAX_PLAYERS>; Teď ale příjde ta těžší část. y_playerarray a y_bit používá na zjištění hodnoty a přiřazování hodnot fce. Ale, pokud vám nesedí s nimi pracovat, můžete na to použít preprocesor(ukážeme si později). Použítí pro podmínky(takže zjištění hodnoty): if (Bit_Get(sIsPremium, playerid)) /* v případě, že vlastní premium */ if (!Bit_Get(sIsPremium, playerid)) /* v případě, že nevlastní premium */ Nebo si na to přidáme preprocesor: #define IsPlayerPremium(%0) Bit_Get(bIsPremium, %0) if (IsPlayerPremium(playerid)) /* V případě že vlastní premium */ if (!IsPlayerPremium(playerid)) /* V případě že nevlastní premium */ Pro přiřazení hodnot máme 2 možnosti, a to buď klasické Bit_Set, kterým můžeme přiřadit hodnotu jak true tak i false a nebo využít 2 rychlejší fce: Bit_Set(sIsPremium, playerid, true); /* Nyní vlastní premium */ Bit_Set(sIsPremium, playerid, false); /* Nyní přišel o premium */ Bit_Let(sIsPremium, playerid); /* Nyní vlastní premium */ Bit_Vet(sIsPremium, playerid); /* Nyní přišel o premium */ A toť vše. Že to není tak složité, že ne? A co, když chceme VIP s 3 levely? Řešení je prosté. Prostě využijeme dvojdimenzní proměnnou:new PlayerArray:bIsPremium[3]<MAX_PLAYERS>; Můžeme si říct, že 0 bude Bronze, 1 bude Silver a 2 bude Gold. A pro kontrolu, pokud například není Silver použijeme: if (!Bit_Get(sIsPremium[1], playerid)) return NejsiSilver(); A pro nastavení Silver VIP zase použijeme: Bit_Let(sIsPremium[1], playerid); /* Nyní má VIP level Silver FormátováníI když Pawn obsahuje dvě funkce na odeslání zpráv (jednotlivci a nebo všem hráčům na serveru), tak jediné, co může odeslat je text, ale ne nějaké zjištěné hodnoty, například adminlevel toho hráče, jméno toho hráče a podobně. To všechno musíme formátovat. Nojo, ale každé formátování vyžaduje nějakou proměnnou, kterou bude formátovat, pak samotnou fci formátování a pak, co s tím formátováným obsahem (například odeslání zprávy). To už jsou ale 3/4 řádky a jen například na jedinou zprávu. Pro více zpráv je potřeba více řádků a to hrozně zdržuje. Ukážeme si nějaký příklad. Chceme, aby nám do chatu zjistilo několik důležitých informací(pro lepší ukázku příkladu v tomto případě nebudeme využívat nový řádek, aka \n): new sString[144 + 1], sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); format(sString, sizeof(sString), "Váš nick je %s", sNick); SendClientMessage(playerid, -1, sString); format(sString, sizeof(sString), "Nyní máte u sebe %i$", GetPlayerMoney(playerid)); SendClientMessage(playerid, -1, sString); format(sString, sizeof(sString), "Nyni máte score %i", GetPlayerScore(playerid)); SendClientMessage(playerid, -1, sString); format(sString, sizeof(sString), "Nyni máte ping %i", GetPlayerPing(playerid)); SendClientMessage(playerid, -1, sString); format(sString, sizeof(sString), "Nyní máte skinid %i", GetPlayerSkin(playerid)); SendClientMessage(playerid, -1, sString); A to ještě formátujeme jedinou proměnnou neustále. Jsou i uživatelé co neustále formátují další a další proměnné. Ale jak vidíte, je to zdlouhavé, trochu i matoucí a ne zrovna jednoduché, hlavně, kdyby tam bylo více údajů. Ale pomocí y_va to jde velice zjednodušit. Ten už má všechny "prvky"(proměnnou, formátování a akci) už v jednom, takže nemusíme nic formátovat, stačí jenom přidat: new sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); va_SendClientMessage(playerid, -1, "Váš nick je %s", sNick); va_SendClientMessage(playerid, -1, "Nyní máte u sebe %i$", GetPlayerMoney(playerid)); va_SendClientMessage(playerid, -1, "Nyni máte score %i", GetPlayerScore(playerid)); va_SendClientMessage(playerid, -1, "Nyni máte ping %i", GetPlayerPing(playerid)); va_SendClientMessage(playerid, -1, "Nyní máte skinid %i", GetPlayerSkin(playerid)); Mnohem kratší, jednoduší a přehledější, že ano? A to není vše, také je to rychlejší než obyčejné formátování, jak přes funkci, tak přes preprocesor, dokonce i rychlejši než fce za použitím emitu:Věřím, že jak se to používá, tak je zcela zřejmé. Navíc si můžeme přidat i vlastní va_ fci(je to už složitější), ale y_va už má některé fce již předpřipravené, takže nemusíme je vytvářet. Zde je seznam těch nejdůležitějších, jejich parametry a jejich příklad použití: va_GameTextForAll(const sFormat[], iCas, iStyl, Argumenty); va_GameTextForAll("Zbývá %i sekund", 5 * 1000, 1, iZavodCas); va_GameTextForPlayer(playerid, const sFormat[], iCas, iStyl, Argumenty); va_GameTextForPlayer(playerid, "START ZA %i", 1 * 1000, 1, iPocetSekund); va_SendClientMessageToAll(iBarva, const sFormat[], Argumenty); va_SendClientMessageToAll(0xFFA50000, "Hráč %s vyhrál", sNick); va_SendClientMessage(playerid, iBarva, const sFormat[], Argumenty); va_SendClientMessage(playerid, 0xFFA50000, "Vyhrál jsi %i$", iVyhra); DialogyTohle je velice častý problém mnoha začátečníků ale i několika autorů scriptů. Jelikož fce ShowPlayerDialog(), vyžaduje vepsat ID dialogu, tak si musí každý pawner hlídat, aby nezadával stejná id, jinak by se dialogy křižily a nefungovaly by, jak mají. Na to je hned několik řešení:1) Tohle je známe především u gamemodů a nebo u větších scriptů, a to místo toho čísla(dialogid) přidat preprocesor s tím číslem, a tak si uživatel pak může následující čísla měnit, aby mu dialogy už fungovaly.2) Ani tohle není vzácné, a to za dialogid dosadit nějaké obrovské číslo. Například 3000, jelikož nejvyšší možné dialogid je 32767, tak ve většine případech je celkem malá šance, že se zrovna dialogy budou křížit.Ale je tu ještě jedna možnost, a to nezadávat žádné dialogid a to pomocí y_dialog. Ten funguje na principu, že najde nejnižší nepoužívané dialogid (například, pokud zrovna někdo nebo něco nepoužívá dialogid 1, tak ho vezme) a ním pak pracuje. Uživatel má možnost také si nějaké id "zabrat", takže nebude hledat ale bude pracovat jen s tím daným id. Ukážeme si příklad, máme 3 dialogy v nějakém už propracovanějším módě: #define DIALOG_BANKA (2000) #define DIALOG_UCET (2001) #define DIALOG_ADMIN (2002) public OnPlayerCommandText(playerid, cmdtext[]) { if (!strcmp("/banka", cmdtext)) { ShowPlayerDialog(playerid, DIALOG_BANKA, DIALOG_STYLE_LIST, ...); return (true); } if (!strcmp("/ucet", cmdtext)) { ShowPlayerDialog(playerid, DIALOG_UCET, DIALOG_STYLE_LIST, ...); return (true); } if (!strcmp("/admin", cmdtext)) { ShowPlayerDialog(playerid, DIALOG_ADMIN, DIALOG_STYLE_LIST, ...); return (true); } return (false); } public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { switch(dialogid) { case DIALOG_BANKA: { if (!response) return (true); switch (listitem) { case 0: { /* zde by byl kód, například 1 2 3 4 až 5 řádků dlouhý */ } case 1: { /* tady třeba už jenom ten 1 */ } return (true); } case DIALOG_UCET: { if (!response) return (true); switch (listitem) { case 0: { /* zde by byl kód, například 1 2 3 4 až 5 řádků dlouhý */ } case 1: { /* tady třeba už jenom ten 1 */ } return (true); } case DIALOG_ADMIN: { if (!response) return (true); switch (listitem) { case 0: { /* zde by byl kód, například 1 2 3 4 až 5 řádků dlouhý */ } case 1: { /* tady třeba už jenom ten 1 */ } } return (true); } } return (false); } Je v tom už menší zmatek, a to jsou pouze tři dialogy s listy. Nic méně. Pomocí y_dialog to celé můžeme zkrátit a úplně se vyhnout callbacku OnDialogResponse. Jak je to možné? Můžeme pomocí fce Dialog_ShowCallback, což už sama o sobě něco říká, a to, že veškéré akce daného dialogu budou v patřičném callbacku, který si přidáme. Jak se s tím pracuje, tak vám samozřejmě ukážu. Nejdříve nahradíme fci ShowPlayerDialog, funkcí Dialog_ShowCallback. Ale místo parametr dialogid nedáme nějaké id ale 3 slova a to "using callback dDialogNeco" bez uvozovek. Kdo nerozumí, co to je, tak to znamená, že dění toho dialogu(hráč stiskne tlačítko, hráč klikne na list) se bude odehrát v tom daném callbacku dDialogNeco(z příkladu to jistě pochopíte). Jinak pokračujeme stejně. Jen doporučuji tuhle fci Dialog_ShowCallback u typů dialogů listy, input a password. Na obytečjný text můžete využití obyčejnou fci Dialog_Show(později si ukážeme použití). Tak začneme tím přepsáním: YCMD:banka(playerid, params[], help) { Dialog_ShowCallback(playerid, using callback dDialogBanka, DIALOG_STYLE_LIST, ...); return (true); } YCMD:ucet(playerid, params[], help) { Dialog_ShowCallback(playerid, using callback dDialogUcet, DIALOG_STYLE_LIST, ...); return (true); } YCMD:admin(playerid, params[], help) { Dialog_ShowCallback(playerid, using callback dDialogAdmin, DIALOG_STYLE_LIST, ...); return (true); } Pak přidáme postupně každý forward a každý callback, jako u normální přidávání callbacku. Nemůžeme to dát do jednoho, musíme to dát samostatně, jinak by to nefungovalo. Nemusíme kontrolovat o jaké jde id dialogu, každý ten callback to ví: forward dDialogBanka(playerid, dialogid, response, listitem, inputtext[]); forward dDialogUcet(playerid, dialogid, response, listitem, inputtext[]); forward dDialogAdmin(playerid, dialogid, response, listitem, inputtext[]); public dDialogBanka(playerid, dialogid, response, listitem, inputtext[]) { if (!response) return (true); switch(listitem) { case 0: { /* zde by byl kód například 1 2 3 4 až 5 řádků dlouhý */ } case 1: { /* a tady už jenom ten 1 řádek */ } } return (true); } public dDialogUcet(playerid, dialogid, response, listitem, inputtext[]) { if (!response) return (true); switch(listitem) { case 0: { /* zde by byl kód například 1 2 3 4 až 5 řádků dlouhý */ } case 1: { /* a tady už jenom ten 1 řádek */ } } return (true); } public dDialogAdmin(playerid, dialogid, response, listitem, inputtext[]) { if (!response) return (true); switch(listitem) { case 0: { /* zde by byl kód například 1 2 3 4 až 5 řádků dlouhý */ } case 1: { /* a tady už jenom ten 1 řádek */ } } return (true); } Přehledjší, rychlejší, kratší a navíc bez potřeby id dialogu. Ale co, když chceme odeslat obyčejný box, se zprávou, který bude mít jenom tlačítko zavřít? Není problém, můžeme využít obyčejné Dialog_Show. Dialog se po stisknutí na tlačítko Zavřit jednoduše prostě zavře a nic více se nebude dít: Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Uvítání", "Vítej na našem serveru", "Zavrit", ""); CyklusHodně tvůrců scriptů jistě zná asi nejstarší cyklus na všechny hráče na serveru a to:for(new i; i<MAX_PLAYERS; i++) { if(IsPlayerConnected(i)) { Akorát u několika lidí se moc neosvědčilo kvůli preprocesoru, který není nic více než jen číslo 500. A tak někteří přidávají preprocesor MAX_PLAYER_EX s menším číslem, (nebo jen undefnou MAX_PLAYERS a nahradí novým číslem) například:#define MAX_PLAYER_EX (100) for(new i; i<MAX_PLAYERS_EX; i++) { if(IsPlayerConnected(i)) { Ale to je furt pro několik lidí docela složitě na naučení. A ještě k tomu nedávno se v updatu objevila nová fce, která nám zjistí nejvyšší playerid na serveru a to:for(new i = 0, j = GetPlayerPoolSize(); i <= j; i++) { if(IsPlayerConnected(i)) { Ale zase je i tento způsob pro někoho složitý na naučení. A tak je tu ještě jedna možnost, dost jednoduchá, mnohem rychlejší, a to za pomocí y_iterate/y_foreach. Tam stačí pouze jmého samotného cyklusu z tohoto includu, pak deklarovaná proměnné a, co má ocyklovat:foreach(new i: Player) { } Nyní máme cyklus, který projede všechny přítomné hráče na serveru. Nic více nepotřebujeme a pracujeme stejně jako s cyklusem v první ukázce, akorát je rychlejší, efektivnější a bez nutnosti fce IsPlayerConnected.A přitom to nemusí být zrovna Player, může to být i pro všechny vozidla(Vehicle), všechny BOTy(Bot), všechny charaktery(Character) a nebo všechny actory(Actor). Nebo, si můžeme přidat i vlastní tzv. Iterator, který pak do cyklu dosadíme, který má project. Můžeme například nemovitosti. Chceme, aby nám vypsal všechny volné nemovitosti. Začneme tím, že si určíme maximum nemovitostí a to třeba 10, pak deklarujeme samotný Iterator za pomoci zrovna tagu Iterator a na konec proměnné, které budeme potřebovat. V případě, že chceme, aby tam ty nemovitosti vypsal, tak jednoduše použijeme funkci Iter_Add, ale nejdříve musíme pro něj najít volné místo v cyklusu pomocí Iter_Free. Pak následuje samotný foreach a na konec, pokud chceme, aby nám to nevypsalo jakoukoliv nemovitost, tak jednoduše ten iterator "vyčistíme", pomocí Iter_Clear: #define dMaxNemovitosti (10) enum enum_Nemovitosti { eJmeno[50], eCena, bool:eVolno } new NInfo[dMaxNemovitosti][enum_Nemovitosti], Iterator: Nemovitosti<dMaxNemovitosti>; stock PridatNemovitost(const Jmeno[], Cena, bool:Volno) { if (Iter_Count(Nemovitosti) == dMaxNemovitosti) return print("Prekroceno maximum !"); new NemID = Iter_Free(Nemovitosti); strcat(NInfo[NemID][eJmeno], Jmeno); NInfo[NemID][eCena] = Cena; NInfo[NemID][eVolno] = Volno; Iter_Add(Nemovitosti, NemID); return (true); } public OnFilterScriptInit() { PridatNemovitost("Hotel", 1000, true); PridatNemovitost("Autodílna", 1000, true); /* <----- !! */ PridatNemovitost("Továrna", 1000, false); return (true); } YCMD:VypsatNemovitosti(...) { foreach(new i: Nemovitosti) { if(NInfo[i][eVolno]) { va_SendClientMessage(playerid, -1, "Nemovitost %s Cena %s", NInfo[i][eJmeno], NInfo[i][eCena]); /* Vypíše: Nemovitost Hotel Cena 1000 Nemovitost Továrna Cena 1000 */ } } Jakto, že nevypíše tu Autodílnu s cenou 1000? Odpověď je prostá. Sice jsme všechny 3 přidali do iterátoru pomocí fce PridatNemovitost, ale v cyklusu foreach podmínkujeme, zda je volná a to naše Autodíla není.Iterator má podle mě velikou škálů využití. Například s ním lze jednoduše vytvořit fci, která vám už rovnou bude přidávat administrátory do /admins: #define dMaxAdmins (10) enum enum_eAdmin { eNick[MAX_PLAYER_NAME + 1], eFunkce[50], eLevel; } new AInfo[dMaxAdmins][enum_eAdmin], Iterator: Admins<dMaxAdmins>; stock AddAdmin(const sNick[], const sFunkce[], iLevel) { new Admin_ID = Iter_Free(Admins); strcat(AInfo[Admin_ID][eNick], sNick); strcat(AInfo[Admin_ID][eFunkce], sFunkce) AInfo[Admin_ID][eLevel] = iLevel; Iter_Add(Admins, Admin_ID); return (true); } public OnScriptInit() { AddAdmin("SkiBig18", "Pawner", 1); AddAdmin("Scydo", "Mistr", 5); AddAdmin("Alkalan", "Noob", 0); return (true); } YCMD:admins(playerid, params[], help) { new sString[600]; foreach(new i: Admins) { format(sString, sizeof(sString), "%s\n%s - %s [%i]", sString, AInfo[i][eNick], AInfo[i][eFunkce], AInfo[i][eLevel]); } Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Admins", sString, "Zavrit"); /* Výsledek: SkiBig18 - Pawner [1] Scydo - Mistr [5] Alkalan - Noob [0] */ return (true); } CallbackTato část se týká především tvůrců includů. Asi znáte, že velká škládá fci nebo možností potřebuje patřičný callback, jinak nebudou fungovat, jak mají. A tak vytváří další callback a pak uživatel ho bude muset přidat do hlavního callbacku, který a_samp již obsahuje, například: forward OnGameModeInit2(); public OnGameModeInit2() { print("Systém nemovitostí se úspěšně načetl"); } public OnGameModeInit() { OnGameModeInit2(); return (true); } Což ještě sice není tak hrozné, ale jde furt o jediný callback. Nojo, ale jak jsem říkal, je více udělaných takových to includů, hlavně ty staré, takže to může dopadat i nějak takto: public OnGameModeInit() { OnGameModeInit2(); Nem_OnGameModeInit(); HouseOnGameModeInit(); CarsCallback_OGMI(); Callback_OnGameModeInit(); return (true); } To už je trošku bordel, co? Samozřejmě je úspornější a lepší možnost a to přes preprocesor "ALS". Ale ten není o nic moc jednoduší. Ale je tu ještě 3. možnost. Představte si, že můžete volat 2x stejný callback a nemusíte přidávat nový (přes forward). S y_hooks je to jednoduché. Stačí akorát zaměnit slovíčko public za hook a můžete přidat stejný callback a compiler nebude protestovat: hook OnGameModeInit() { print("Mod se nahrava !"); return (true) } public OnGameModeInit() { return (true); } Takhle můžete do include si vesele si přidávat hooky a uživatel nebude muset nikam přidávat volání. Užitečné, že ano? Ukážu nějaké jednoduché využití. Budu mít include, například nějaké úplně jednoduché VIP.inc a v něm: stock GetPlayerNick(playerid)) { new sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); return sNick; } stock GivePlayerVip(playerid) { Bit_Let(VipLevel, playerid); return (true); } hook OnPlayerSpawn(playerid) { if (IsPlayerVip(playerid)) { SetPlayerArmour(playerid, 100.0); SetPlayerHealth(playerid, 100.0); va_SendClientMessageToAll(color, "VIP hráč %s se spawnul", GetPlayerNick(playerid)); } return (true); } Tak. Nyní jsem si vytvořil include, který obsahuje nastavení proměnné (Bit_Let) aka jeho VIP, a hook, že jakmile se spawne tak mu to nastaví plnou vestu a život, a napíše, že se spawnul VIP hráč. Teď, když si náš include nahrajeme a přejdeme do editoru, kde máme nový list: #include <VIP.inc> public OnPlayerConnect(playerid) { GivePlayerVip(playerid); return (true); } A to je vše. Jakmile se hráč připojí tak se nastaví VIP. A jakmile se spawne, stane se přesně to, co jsem popisoval před chvilkou. Všimněte si, že nikde nemusím volat OnPlayerSpawn a přidávat do něj nějaký nový callback VIP_OnPlayerSpawn. Snad tohle posune některé include už ku předu trošku.TimerA nakonec timer. Tohle se už týká i té pokročilejší skupiny. Viděl jsem hodně includů či scriptů, kde jak zachází s timery. Od jejich spuštění, po jejich obsah až k zastavení. Timer je snad jedna z nejpoužívanějších funkcí v PAWN. Má hodně velkou škálů využití. Tipy, ochrana, anticheat, eventsystém, porty (ty s 5 sekundovým čekáním), nemovitnosti, dražba a mnoho dalšího. Ale my se zaměříme na nějaké, které lze pomocí YSI4 velice zjednodušit a vylepšit. Například, asi snad každý zná jeden z nejjednoduších scriptů a to tipy. Několik desítek zpráv, které se po nějakém čase odešlou hráčům.Jako ukázku jsem si připravil tipy a k nim 5 zpráv, včetně spuštění a vypnutí: new TipyTimer; new sTextTipy[5][] = { "{FF0000}[ TIP ] {FFFFFF}Pro schování peněz navštiv banku !", "{FF0000}[ TIP ] {FFFFFF}Neustále tě někdo vraždí? Kup si zbraň ve Ammo-Nations a braň se !", "{FF0000}[ TIP ] {FFFFFF}Nezapomeň se zastavit v jedném z barů !", "{FF0000}[ TIP ] {FFFFFF}Jestli-že se nudíš, zajeť do herny !", "{FF0000}[ TIP ] {FFFFFF}Webová stránka tohoho serveru je www.server-samp.org/web" }; public OnGameModeInit() { TipyTimer = SetTimer("tTipyTimer", 1000*60*2, true); return (true); } public OnGameModeExit() { KillTimer(TipyTimer); return (true); } forward tTipyTimer(); public tTipyTimer() { SendClientMessageToAll(-1, sTextTipy[random(5)]); } Jak vidíte, i když to jsou obyčejné tipy je to celkem rozsáhlé. Teď zkusíme udělat ty samé tipy zapomocí y_timers. První co, tak můžeme vymazat proměnnou TipyTimer, jelikož y_timers pracuje "s jménem" toho timeru(uvidíme v příkladě), ale může se mu samozřejmě nastavit ID. Dál změníme fci na spouštění na repeat (defer by nám spustil jednom jednou, repeat nám to bude opakovat). Čas nemusíme zadávat, to budeme zadávat až ve fci timer. A nakonec vypnutí opět zaměníme fci KillTimer na obyčejné stop: new sTextTipy[5][] = { "{FF0000}[ TIP ] {FFFFFF}Pro schování peněz navštiv banku !", "{FF0000}[ TIP ] {FFFFFF}Neustále tě někdo vraždí? Kup si zbraň ve Ammo-Nations a braň se !", "{FF0000}[ TIP ] {FFFFFF}Nezapomeň se zastavit v jedném z barů !", "{FF0000}[ TIP ] {FFFFFF}Jestli-že se nudíš, zajeť do herny !", "{FF0000}[ TIP ] {FFFFFF}Webová stránka tohoho serveru je www.server-samp.org/web" }; public OnGameModeInit() { repeat tTipyTimer(); return (true); } public OnGameModeExit() { stop tTipyTimer(); return (true); } repeat tTipyTimer[1000*60*2]() { SendClientMessageToAll(-1, sTextTipy[random(5)]); } A to je vše. Není to přecijen jednoduší a kratší? Nemluvě o tom, že je to rychlejší.Ale y_timers také se může široce využít, například když máte příkazy ve VIP a chcete, aby je hráč mohl využít třeba jen 1x za 2 minuty. Ve starších verzích(v některých nových vlastně také) to vypadá nějak následovně: new bool:VZivot[MAX_PLAYERS]; new bool:VVesta[MAX_PLAYERS]; new bool:VScore[MAX_PLAYERS]; dcmd_vhp(playerid, params[]) { if(VZivot[playerid] ) return SendClientMessage(playerid, -1, "Počkejte 2 minuty pro další použití"); VZivot[playerid] = true; SetPlayerHealth(playerid, 100.0); SetTimerEx("PVZivot", 1000*60*2, false, "i", playerid); return 1; } dcmd_vvesta(playerid, params[]) { if(VVesta[playerid]) return SendClientMessage(playerid, -1, "Počkejte 2 minuty pro další použití"); VVesta[playerid] = true; SetPlayerArmour(playerid, 100.0); SetTimerEx("PVVesta", 1000*60*2, false, "i", playerid); return 1; } dcmd_score(playerid, params[]) { if(VScore[playerid]) return SendClientMessage(playerid, -1, "Počkejte 2 minuty pro další použití"); VScore[playerid] = true; SetPlayerScore(playerid, GetPlayerScore(playerid)+1000); SetTimerEx("PVScore", 1000*60*2, false, "i", playerid); return 1; } forward PVZivot(playerid); forward PVVesta(playerid); forward PVScore(playerid); public PVZivot(playerid) { VZivot[playerid] = false; return 1; } public PVVesta(playerid) { VVesta[playerid] = false; return 1; } public PVScore(playerid) { VScore[playerid] = false; return 1; } Je to dost vyčerpávající, a to jsou zatím jenom 3 příkazy. Teď na to zkusíme využít y_timers. Můžeme použít, že spolu se spuštěním timeru, nám pošle i pár potřebným argumentů a to id toho hráče a jaký příkaz použil. Takže nebudeme muset přidávat timer na každý příkaz zvlášť ale stačí jediný: new bool:PouzitoCMD[MAX_PLAYERS][3]; YCMD:vhp(playerid, params[], help) { if(PouzitoCMD[playerid][0]) return SendClientMessage(playerid, -1, "Počkejte 2 minuty pro další použití"); SetPlayerHealth(playerid, 100.0); PouzitoCMD[playerid][0] = true; defer tPouzitoCMD(playerid, 0); return 1; } YCMD:vvesta(playerid, params[], help) { if(PouzitoCMD[playerid][1] return SendClientMessage(playerid, -1, "Počkejte 2 minuty pro další použití"); SetPlayerArmour(playerid, 100.0); PouzitoCMD[playerid][1] = true; defer tPouzitoCMD(playerid, 1); return 1; } YCMD:score(playerid, params[], help) { if(PouzitoCMD[playerid][2] return SendClientMessage(playerid, -1, "Počkejte 2 minuty pro další použití"); SetPlayerScore(playerid, GetPlayerScore(playerid)+1000); PouzitoCMD[playerid][2] = true; defer tPouzitoCMD(playerid, 2); return 1; } tPouzitoCMD[1000*60*2](playerid, cmdid) { PouzitoCMD[playerid][cmdid] = false; } Opět mnohem kratší a jednoduší, že ano?Použito z knihovny Include Cesta Alternativní cesta Popis y_ini <YSI_Storage\y_ini> <YSI\y_ini> Ukládání a načítá údaje ze souboru. y_commands <YSI_Visual\y_commands> <YSI\y_commands> Umožňuje pracovat s příkazy a s jejich parametry, plus help. y_bit <YSI_Data\y_bit> <YSI\y_bit> Šetří paměť proměnné boolen(s polem). y_playerarray <YSI_Data\y_playerarray> <YSI\y_playerarray> Šetří paměť proměnné boolen(s polem). Doporučeno na proměnné určené pro hráče. y_va <YSI_Coding\y_va> <YSI\y_va> Umožní pracovat s již formátovanými funkcemi. y_dialog <YSI_Visual\y_dialog> <YSI\y_dialog> Umožní pracovat s dialogy bez nutnosti jim přidělovat id. y_iterate <YSI_Data\y_dialog> <YSI\y_iterate> Umožní pracovat s cyklusem foreach. y_foreach <YSI_Data\y_foreach> <YSI\y_foreach> Alternativní cesta na include y_iterate y_hooks <YSI_Data\y_hooks> <YSI\y_hooks> Umožní jednoduše hookovat callbacky. y_timers <YSI_Data\y_timers> <YSI\y_timers> Práce s timery ze YSI. y_scriptinit <YSI_Coding\y_scriptinit> <YSI\y_scriptinit> Přidává callback, který je možné použít jak ve FS tak v GM. ZávěrTo je prozadím vše. V případě, že naleznu nějakou další užitečnou zajímavou informaci, přidám jí sem.! Kódy, kde jsem nevyužíval YSI slouží jako ukázka! Nebyly kontrolovány compilerem a tak se tam můžou vyskytnout chyby. Proto je v žádném případě nepoužívejte!PS: Topic obsahuje skutečně mnoho textu a kódu a tudíž, než ho celý pročtu a zkontroluji, chvilku to potrvá, tak se prosím prozatím zdržte komentářů poukázující na nějakou chybu. Děkuji. 9 Link to comment Share on other sites More sharing options...
Hlavní moderátor vEnd 279 Odesláno: 17. Duben, 2016 Hlavní moderátor Share Odesláno: 17. Duben, 2016 1) Musíme až 3x zakládat proměnnou string na nick a na cestu souboru. Nó, ono by to šlo i lépe, což o to... 2) Musíme formátovat jedinou zprávu. Jak tohle souvisí s dcmd? Ale, když přidáme proměnnou pomocí y_bite: new BitArray:Promenna<MAX_PLAYERS>; Tak využití paměti je už pouhých 29 bajtů. To mne zaujalo, jak to funguje? dokonce i rychlejši než pomocí emitu Toto je celkem haluz. Nepochopitelná. Kde sice už nemusíme zjišťovat, jestli je připojený (IsPlayerConnected)... Počky, počky, to je kravina. GetPlayerPoolSize akorát vrací nejvyšší připojené ID, to ale neznamená, že všechna ID mezi nejnižším a nejvyšším jsou připojena. Ty kontroly u timerů nejsou zrovna ideální ukázka, u obojího se totiž můžeš vyprdnout na timery a použít gettime. Hele jo, dal sis s tím práci a jsou tam zajímavé věci (místy teda trochu zmatek, ale co už). Akorát teda jedna velká výtka – je to strašně dlouhé. Po souborech a příkazech jsem už jen tak zběžně prolétával, co jsi tam psal, ale doopravdy to nečetl. Snad nebudu jediný, co si to vůbec četl. Tak dobrá práce a zapracuj na tom, co jsem napsal výše. A taky mi odpověz na tu otázku, pokud možno. Link to comment Share on other sites More sharing options...
Scydo 397 Odesláno: 17. Duben, 2016 Author Share Odesláno: 17. Duben, 2016 Nó, ono by to šlo i lépe, což o to... ~> Kódy, které nejsou zpracované prostřednictvím YSI jsou většinou inspirované, jako by je psal začáteční uživatel a nebo rovnou napsané stejně, jen krapek vylepšené. Samozřejmě, že by to šlo napsat lépe(což je dokonce i účelem tohohle topicu -> všechno to jde udělat lépe). Jak tohle souvisí s dcmd? ~> Je to v patřičné kapitole. Navíc je to jedna z problematik, která zrovna jde zpracovat lépe přes YSI(y_va). To mne zaujalo, jak to funguje? ~> Není k nalezení dokumentace, která to dopodrobna výborně vysvětlila, takže se spíše teoretizuje. Ale většina je té možnosti, že na podobném způsobu jako "packed" string. Toto je celkem haluz. Nepochopitelná. ~> Ne, jenom trošku jinak vysvětlená: Alebo použijete stock (by Lorenc_ tuším) s emit a argumentami stock SendClientMessageFormatted(playerid, color, fstring[], {Float, _}:...) { #define BYTES_PER_CELL 4 const STATIC_ARGS = 3; new n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL; if(n) { new message[144],arg_start,arg_end; #emit CONST.alt fstring #emit LCTRL 5 #emit ADD #emit STOR.S.pri arg_start #emit LOAD.S.alt n #emit ADD #emit STOR.S.pri arg_end do { #emit LOAD.I #emit PUSH.pri arg_end -= BYTES_PER_CELL; #emit LOAD.S.pri arg_end } while(arg_end > arg_start); #emit PUSH.S fstring #emit PUSH.C 144 #emit PUSH.ADR message n += BYTES_PER_CELL * 3; #emit PUSH.S n #emit SYSREQ.C format n += BYTES_PER_CELL; #emit LCTRL 4 #emit LOAD.S.alt n #emit ADD #emit SCTRL 4 if(playerid == INVALID_PLAYER_ID) { #pragma unused playerid return SendClientMessageToAll(color, message); } else { return SendClientMessage(playerid, color, message); } } else { if(playerid == INVALID_PLAYER_ID) { #pragma unused playerid return SendClientMessageToAll(color, fstring); } else { return SendClientMessage(playerid, color, fstring); } } } Počky, počky, to je kravina. GetPlayerPoolSize akorát...(více) ~> Přepíšu. Ty kontroly u timerů nejsou zrovna ideální ukázka, u obojího se totiž můžeš vyprdnout na timery a použít gettime. ~> Ano, ale já se snažil nějaký příklad, který zná snad každý. Tipy se mi zdály jako nejlepší volba, která lze rychle vytvořit a u čeho jde vidět dobře rozdíl. Navíc, jak jsem už říkal, první je jen ukázka, jako by na tom dělal někdo jiný. Určitě by to nebyl můj výsledný script bez použití YSI. Akorát teda jedna velká výtka – je to strašně dlouhé. ~> Njn. U něčeho bylo hold potřeba jít do podrobností. Taky ten topic byl záměrně rozdělen na kapitoly. Například aby uživatel, co je zatvrdlí na dini tak se podívá jen na ukládání+načítání a pročte si ho a pochopí, v čem je y_ini lepší oproti dini, že tam není tak extra rozdíl atd. To samé uživatelé, co používají dcmd. Taky rovnou skočí na kapitolu příkazy, aby viděli rozdíl mezi dcmd a ycmd. A nemusí to číst celé.. Link to comment Share on other sites More sharing options...
Globální moderátor HighPrint 177 Odesláno: 17. Duben, 2016 Globální moderátor Share Odesláno: 17. Duben, 2016 Y_Less se vždycky snažil přebrat C/C++ věci, takže bych si dovolil možná i tvrdit, že se jedná o nějakou napodobeninu vector boolů. V sa-mpu zabírá bool jako všechny proměnné 4bajty, to znamená, že se to všechno smrskne do jednotlivých bitů. Takže když to zkrátíme, New: 1 cell = 32 bits = 32 bools = 32 využití Old: 1 cell = 32 bits = 1 bool = 1 využití Old s char: 1 cell = 32 bits = 4 bools = 4 využití Link to comment Share on other sites More sharing options...
DNLS 31 Odesláno: 17. Duben, 2016 Share Odesláno: 17. Duben, 2016 Já sem původně šel normálně z DCMD že jo, wikina ti to vyhledá jako "Fast Commands" ale y_commands je prostě boží, nic jinému se tomu nevyrovná, hned jedu svý a nemusím psát to pitomý public OnPlayerCommandText Link to comment Share on other sites More sharing options...
Globální moderátor Hip 198 Odesláno: 17. Duben, 2016 Globální moderátor Share Odesláno: 17. Duben, 2016 fuuu tak dlouhé teda.Kdo se bude chtít učit, tak si to přečte celé Jinak moc pěkné, hodně mě zaujaly dialogy. Malinká chybka -> "vespání!" (CTRL/CMD + F) Link to comment Share on other sites More sharing options...
ATomas 299 Odesláno: 18. Duben, 2016 Share Odesláno: 18. Duben, 2016 Predpokladam ze YSI je jako dini cele postavene na fopen fwrite fread fclose ze ? Tak proc bych mel sakra pouzivat YSI nebo dini kdyz muzu pouzivat zakladni funkce, ktere jsou nejrychlejsi 2 Link to comment Share on other sites More sharing options...
Paulee 16 Odesláno: 18. Duben, 2016 Share Odesláno: 18. Duben, 2016 Hodně pěkné . Já jsem si to pročetl celé, protože mě to zajímalo, co na tom lidi furt vidí. A vidím, že na tom něco bude Zatím uvažuji jen o y_va, protože to formátování je dost přestává bavit. GJ. (Repík neuškodí). Link to comment Share on other sites More sharing options...
Scydo 397 Odesláno: 18. Duben, 2016 Author Share Odesláno: 18. Duben, 2016 kdyz muzu pouzivat zakladni funkce, ktere jsou nejrychlejsi ~> Protože všichni to neumí tak dobře s nimi, jako pracovat s dini. A pokud myslíš, že jsou základní files nejlepší, tak ať. Nikde o nich v topicu nepíši, že je lepší si na to raději stáhnout include. Především je to pro ty zatvrdlé dinisáky, co tvrdí, že je desítky let starý include nejlepší, a že jiný by si neuměli představit, plus: pro remcaly co tvrdí, že YSI je satanistické dílo, co nejde pochopit.. Link to comment Share on other sites More sharing options...
DNLS 31 Odesláno: 18. Duben, 2016 Share Odesláno: 18. Duben, 2016 ATomas.... Pro někoho je to lepší, ale třeba pro mě, je lepší prostě jen napsat #include a_samp #include y_commands YCMD:prikaz(playerid, params[], help) { SendClientMessage(playerid, -1, "Napsal si příkaz /prikaz"); return 1; } Link to comment Share on other sites More sharing options...
Hlavní moderátor vEnd 279 Odesláno: 18. Duben, 2016 Hlavní moderátor Share Odesláno: 18. Duben, 2016 ATomas.... Pro někoho je to lepší, ale třeba pro mě, je lepší prostě jen napsat #include a_samp #include y_commands YCMD:prikaz(playerid, params[], help) { SendClientMessage(playerid, -1, "Napsal si příkaz /prikaz"); return 1; } Ale on mluvil o souborech, ne o příkazech, v tom je rozdíl. Link to comment Share on other sites More sharing options...
DNLS 31 Odesláno: 18. Duben, 2016 Share Odesláno: 18. Duben, 2016 Ale on mluvil o souborech, ne o příkazech, v tom je rozdíl. Aha, tak to je moje chyba. Link to comment Share on other sites More sharing options...
ATomas 299 Odesláno: 18. Duben, 2016 Share Odesláno: 18. Duben, 2016 (upraveno) ~> Protože všichni to neumí tak dobře s nimi, jako pracovat s dini. A pokud myslíš, že jsou základní files nejlepší, tak ať. Nikde o nich v topicu nepíši, že je lepší si na to raději stáhnout include. Především je to pro ty zatvrdlé dinisáky, co tvrdí, že je desítky let starý include nejlepší, a že jiný by si neuměli představit, plus: pro remcaly co tvrdí, že YSI je satanistické dílo, co nejde pochopit.. Ja jsem zase zatrvrdly file-sista (pawno/include/file.inc). Tak jako tak respekt za ten tutorial. Takhle krasne spracovany tutorial tu vidim asi poprve. Zarovnavat to do tabulek a formatovat se s nadpisama. S tim bych se treba ja nezdrzoval Edited 18. Duben, 2016 by ATomas 3 Link to comment Share on other sites More sharing options...
Scydo 397 Odesláno: 19. Duben, 2016 Author Share Odesláno: 19. Duben, 2016 Já sem původně šel normálně z DCMD že jo, wikina ti to vyhledá jako "Fast Commands" ale y_commands je prostě boží, nic jinému se tomu nevyrovná, hned jedu svý a nemusím psát to pitomý public OnPlayerCommandText ~> Tak, ono je to pochopitelné, jelikož podle wiki jsou oba (dcmd a zcmd) rychlejší, než strtok. Ale podle mě je to i v rychlosti práce s ním. Nemluvě o tom, že samotný článek, je docela starý, takže v té době se na rychlost ještě tak nebral ohled, spíše už lidi byly nadšení jen z toho, že něco takového existuje. fuuu tak dlouhé teda. Kdo se bude chtít učit, tak si to přečte celé Jinak moc pěkné, hodně mě zaujaly dialogy. Malinká chybka -> "vespání!" (CTRL/CMD + F) ~> Každého zaujme hold něco jiného. Ale rozhodně souhlasím. I mě po prvé překvapilo, když jsem po letech zjistil, že jdou přidávat dialogy bez nutnosti dialogid. Ale stejně u mě vítězí iterátory, protože využití je fakt enormně početné. ~> Chyba byla opravená, ale stejně jich tam je ještě dost. Hodně pěkné . Já jsem si to pročetl celé, protože mě to zajímalo, co na tom lidi furt vidí. A vidím, že na tom něco bude Zatím uvažuji jen o y_va, protože to formátování je dost přestává bavit. GJ. (Repík neuškodí). ~> Tak, to jsou zatím jenom ty základní includy z knihovny, o kterých by se hodilo vědět pro někoho, kdo má zájem pracovat na GM s YSI. Samozřejmě, je tam mnohem více zajímavějších includů, například y_testing se hodí na testování scriptů(obsahuje i měření času), y_debug zase, kdyby nám ten script nefungoval, y_races na práci se závody, y_files na práci se složkami(ne, se soubory), y_vehicledata, který zase obsahuje kategorie vozidel (něco jako má wiki), y_properties, se kterým lze dělat nemovitosti, y_users, který obsahuje fce na práci s registrací, loginem... je toho tam prostě hromada. ATomas.... Pro někoho je to lepší, ale třeba pro mě, je lepší prostě jen napsat #include a_samp #include y_commands ~> Pokud načítáš z alternativní cesty (YSI\y_commands), tak by ses měl začít zaměřovat na načítání ze hlavní cesty (YSI_Visual\y_commands). Ne jenom, že je to načítání ze staré verze 3.1, ale když otevřeš ty soubory, tak stejně jediné, co tam uvidíš je právě načítání té hlavní cesty, takže je to i rychlejší.[/font] Ja jsem zase zatrvrdly file-sista (pawno/include/file.inc). Tak jako tak respekt za ten tutorial. Takhle krasne spracovany tutorial tu vidim asi poprve. Zarovnavat to do tabulek a formatovat se s nadpisama. S tim bych se treba ja nezdrzoval ~> Nom děkuju. Dalo to práci. Snad to konečně k něčemu bude. A i pro mě to byla zajímavá zkušenost, protože s tabulkami na fórech jsem pracoval po prvé v životě. Takže to byl na nějakou dobu i boj ... Link to comment Share on other sites More sharing options...
niko777112 1 Odesláno: 6. Srpen, 2016 Share Odesláno: 6. Srpen, 2016 Otázka ktorá neviem či sa hodí sem: ako efektívne pracovať s ysi a mysql? Link to comment Share on other sites More sharing options...
Scydo 397 Odesláno: 6. Srpen, 2016 Author Share Odesláno: 6. Srpen, 2016 Otázka ktorá neviem či sa hodí sem: ako efektívne pracovať s ysi a mysql? Pokud máš nějaké údaje, které chceš ukládat jen do scriptfiles ne nějak je rvát na web, tak můžeš. Link to comment Share on other sites More sharing options...
niko777112 1 Odesláno: 6. Srpen, 2016 Share Odesláno: 6. Srpen, 2016 Práveže to chcem vyťahovať len na web 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