Jump to content
Prosíme všetkých užívateľov, ktorý sa chcú opätovne pripojiť na discord aby znovu spárovali svoje účty kliknutím na "Discord" v navigácií a pripojili sa na server Read more... ×

Žebříček


Populární obsah

Showing content with the highest reputation since 22.3.2019 in all areas

  1. 10 points
    Emit #1: Základy Obtížnost: 7/5 Prečo to robiť jednoducho, keď to ide zložito? Tento tutoriál vyžaduje Zeexov Compiler verziu 3.10.9+, pretože používa nový operátor emit (nie direktívu). Osnova/obsah: Disclaimer Globálne Premenné Základné operácie Stack Zlahčováky Operátor emit Záver 1. Disclaimer Emit a amxassembly je určite zaujímavá vec. Je to však podobné atómovej bombe. Je fajn ju mať, ale nikdy ju nechceme použiť. Vyššie jazyky ako PAWN existujú z dobrého dôvodu. Písať kód v assembly je zbytočne zdĺhavé a nebezpečné. Vzniknutý kód je absolútne nečitateľný. Chyby v assembly niesu ako chyby v PAWN, kde vás buď upozorní compiler, alebo vám nefunguje to, čo ste spravili. Pri chybe v emit sa môže stať čokoľvek. Crashe, SendClientMessage začne zobrazovať TextDrawy, 2 + 2 je zrazu 5, mačky naháňajú psy, počítače začnú horieť... Emit vám dokáže spôsobiť chyby v úplne iných častiach serveru a neukázať žiadny náznak, že je to chyba emitu... Ak na to nieste psychicky pripravený, tak radšej prestaňte čítať. Tento tutoríal čítajte na vlastné riziko! Autor nebude zodpovedný za žiadnu škodu, ktorú si spôsobíťe používaním emitu alebo iným používaním týchto informácií! Autor nebude zodpovedný za vaše mentálne zdravie, ak sa pokúsite chápať emity! 2. Globálne premenné Prvá vec, ktorú treba vedieť pri používaní emit sú registre. Registre fungujú podobne ako premenné a pawn ich ma niekoľko 9+. Zatiaľ nás však budú zaujímať len 2: pri a alt. Pri je primárny register. Takmer všetko, čo budeme robiť používa pri. Alt je alternatívny register, ktorý sa používa hlavne keď potrebujeme robiť s 2 číslami. Napríklad ak chceme 2 čísla sčítať. Ďalej musíme vedieť inštrukcie. Inštrukcie sú akési príkazy, ktoré hovoria, čo sa má spraviť. Niektoré inštrukcie za sebou majú .pri alebo .alt, čo určuje, s ktorým registrom chceme pracovať. Napríklad: LOAD.pri Adresa - Načíta hodnotu z adresy Adresa do registra pri LOAD.alt Adresa - Načíta hodnotu z adresy Adresa do registra alt Všeobecne toto zapisujeme ako LOAD.pri/alt Adresa - Načíta hodnotu z [Adresa] do pri/alt Ďalej keď pracujeme s hodnotou na určitej adrese, používame zápis [Adresa]. Takže ešte inak sa to dá zapísať LOAD.pri/alt Adresa - pri/alt = [Adresa] Tento zápis nám hovorí, že zoberieme hodnotu z adresy Adresa a vložíme ju do registru pri alebo alt, podla toho, ktorú inštrukciu použijeme (LOAD.pri alebo LOAD.alt). STOR.pri/alt Adresa - [Adresa] = pri/alt A ako vidíťe, táto inštrukcia STOR nám zase uloží obsah registra na adresu Adresa. Samozrejme sa pravdepodobne pýtate, odkial máte zobrať adresu? Užitočne miesto adresy môžete dať meno globálnej premennej, takže môžeme napríklad spraviť: new a = 1; new b = 2; main() { printf("a = %i, b = %i", a, b); // a = 1, b = 2 // b = a; emit LOAD.pri a; // Načítame a do pri emit STOR.pri b; // Uložíme pri do b printf("a = %i, b = %i", a, b); // a = 1, b = 1 } 3. Základné operácie Samozrejme obvykle nechceme len presúvať hodnoty, ale s nimi niečo počítať. Na to môžeme použiť napríklad niektoré z týchto inštrukcií. CONST.pri/alt Hodnota - pri/alt = Hodnota ADD - pri = pri + alt SUB - pri = pri - alt SUB.alt - pri = alt - pri NEG - pri = -pri SMUL - pri = pri * alt SDIV - pri = pri / alt, alt = pri % alt XCHG - Vymení pri a alt S týmito inštrukciami už môžeme spraviť niečo ako c = a + b; new a = 3; new b = 2; new c; main() { printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = 0 // c = a + b; emit LOAD.pri a; // Načítame a do pri emit LOAD.alt b; // Naćítame b do alt emit ADD // sčítame pri a alt a výsledok vložíme do pri emit STOR.pri c; // uložíme pri do c printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = 5 } A veľa dalších vecí: new a = 3; new b = 2; new c; main() { printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = 0 // c = -a - b; emit LOAD.pri a; emit NEG; emit LOAD.alt b; emit SUB emit STOR.pri c; printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = -5 // c = a * -b; emit LOAD.pri b; // Načítame b do pri, pretože NEG funguje len na pri emit NEG; // pridáme mínus, takže pri = -b emit XCHG; // presunieme pri do alt, takže alt = -b emit LOAD.pri a; // načítame a do pri emit SMUL; // vynásobíme pri * alt, čiže a * -b emit STOR.pri c; // uložíme výsledok do c printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = -6 // a = a + 5; emit LOAD.pri a; // Načítame a do pri emit CONST.alt 5; // Načítame 5 do alt emit ADD; // sčítame emit STOR.pri a; // uložíme výsledok do a } 4. Stack Ok, ale čo ak chceme spraviť a * b + c * d; Ak začnete písať tento kód, zistíte, že nemáte kam uložiť medzihodnotu a * b. Ano, môžete skúsiť podvádzať a uložiť ju do r, ale čo ak miesto r to budete chcieť dať priamo do funkcie? Odpoveď je zásobník. Úlohou zásobníka je pre vás podržať hodnoty, ktoré potrebujete. Predstavte si zásobník ako hŕbu papierov. Vždy keď potrebujete si môžete na vrch papier odložiť a neskôr ho z vrchu zobrať, avšak nesmiete sa v tej hŕbe hrabať. Môžete brať a dávať len na vrch. PUSH.pri/alt - Vloží pri/alt na vrch zásobníku. POP.pri/alt - Vloží hodnotu z vrchu zásobníku do pri/alt. Takže môžeme spraviť napríklad: new a = 3, b = 2, c = 4, d = 4; new r; main() { // r = a * b + c * d; emit LOAD.pri a; emit LOAD.alt b; emit SMUL; emit PUSH.pri; // uložíme výsledok na zásobník emit LOAD.pri c; emit LOAD.pri d; emit SMUL; emit POP.alt; // vybereme výsledok prvého náspbenia zo zásobníku emit ADD; emit STOR.pri r; printf("r = %i", r); // r = 22 } Na stack môžeme vložiť viacero hodnôt, napríklad: new a = 1, b = 2, c = 3, d = 4; new r; main() { // r = a + b + c + d; emit LOAD.pri d; emit PUSH.pri; // STACK = d emit LOAD.pri c; emit PUSH.pri; // STACK = c d emit LOAD.pri b; emit PUSH.pri; // STACK = b c d emit LOAD.pri a; emit PUSH.pri; // STACK = a b c d emit POP.pri; // a // STACK = b c d emit POP.alt; // b // STACK = c d emit ADD; emit POP.alt; // c // STACK = d emit ADD; emit POP.alt; // d emit ADD; emit STOR.pri r; printf("r = %i", r); // r = 10 } Možno sa teraz spýtaťe, čo sa stane ak dám POP viac krát ako PUSH? Mačky začnú nahánať psov, alebo možno váš počítač vybuchne. Kdo vie... 5. Zľahčováky Existuje taktiež veľa inštrukcií, ktoré existujú na zľahčenie písanie, napríklad niektoré inštrukcie majú verziu .C, ktorá použije zadanú hodnotu miesto registra. Napr "ADD.C 5" pripočíta k registru pri 5, čiže pri += 5. ADD.C Hodnota - pri = pri + Hodnota SMUL.C Hodnota - pri = pri * Hodnota PUSH.C Hodnota - Vloží Hodnota na zásobník INC.pri/alt - pri/alt = pri/alt + 1 DEC.pri/alt - pri/alt = pri/alt - 1 ZERO.pri/alt - pri/alt = 0 ZERO Adresa - [Adresa] = 0 ... 6. Operátor emit Možno viete, že bežne sa nepoužíva emit ale #emit. emit ani v bežnom compilery pribalenom v samp nieje. Tak prečo ho používam tu? emit má totiž niekoľko výhod. Je napríklad možné písať inštrukcie do {} takto. emit { const.pri 5 const.alt 5 add stor.pri r } Vďaka tomu nemusíte neustále písať emit. Ďalej bežný emit "vracia" hodnotu uloženú v pri, takže môžete napísať: new a = emit const.pri 4; printf("%i, %i", a, emit const.pri 7); // 4, 7 A taktiež umožnuje písať inštrukcie oddelené čiarkou do () takto: printf("%i", emit(const.pri 2, const.alt 4, add)); // 6 Toto vám umožní oveľa lahšie integrovať emit so svojim kódom. Taktiež to umožnuje používať emit v Makrách cez #define. Nakoniec emit narozdiel od #emit robí určité kontroly pri kompilácii. Ak napríklad dáte lokálnu premennú do LOAD.pri, tak vám napíše error. To je hlavný dôvod, prečo som zvolil operátor emit pre tento tutoriál miesto #emit. Ak však nepotrebujete žiadnu z týchto výhod, všetko v tomto tutoriály sa dá použiť taktiež s #emit. 7. Záver V ďalšom diely tohto tutoriálu sa vrhneme na funkcie a lokálne premenné, taktiež si povieme viac o stacku.
  2. 9 points
  3. 9 points
    Je dosť neprofesionálne a nevhodné zverejňovať súkromné konverzácie.
  4. 7 points
    Obtížnost: Obsah: 1. Úvod 2. Kdy proměnné využíváme? 3. Konkrétní příklady 4. Závěr 1. Úvod: Rozhodl jsem se zkusit napsat novou formu návodů. Bude se jednat o pokus-omyl, uvidím, jak se takový návod ujme. Mělo by se jednat o jakési doplnění návodů, které již na fóru jsou o jistou praxi. Protože teorie je super, ale pokud člověk vůbec nechápe, na co se co má používat, tak s Pawnem začít vůbec nemůže, protože ho odradí množství informací, které z návodu nedostal a sám si je nedomyslí. Před čtením tohoto návodu doporučuji přečtení čistě teoretických návodů k základům Pawn, abyste rozuměli, co se v kterých částech kódu má dít. Naleznete je zde: https://pawno.cz/index.php?/forum/149-pawn-pro-začátečníky/ Zejména pak bude potřeba teoretický návod k proměnným. https://pawno.cz/index.php?/topic/53319-1-proměnná/ 2. Kdy proměnné využíváme? Proměnnou můžeme využít v případě, kdy si chceme uložit jakoukoliv informaci pro další použití. stock JmenoHrace(playerid) { new UlozeneJmeno[24 + 1]; //Deklarovali jsme si proměnnou s velikostí pro string/řetězec 25. (24 je maximální délka nicku + nulový znak) GetPlayerName(playerid, UlozeneJmeno, sizeof(UlozeneJmeno)); //Pomocí funkce GetPlayerName zjistíme nick hráče s id "playerid". //To se nám uloží do proměnné UlozeneJmeno. //Operátor sizeof() vrací velikost datového typu nebo objektu v bytech. V tomto případě 24 + 1 = 25. //Jedno místo v proměnné je vyhrazeno pro nulový znak. return UlozeneJmeno; //Příkaz return znamená navrátit. //V tomto případě nám funkce navrátí proměnnou ve formě stringu/řetězce, která se nazývá UlozeneJmeno. } Tuto funkci nyní můžeme využít kdekoliv ve scriptu, aniž musíme znovu a znovu proměnnou deklarovat. 3. Konkrétní příklady: Příklady budou s minimálním počtem komentářů, k pochopení, co se děje v kódu si přečtěte teoretické návody, které jsem poslal výše. Již jednou zmíněná funkce pro zjištění hráčova jména: stock JmenoHrace(playerid) { new UlozeneJmeno[MAX_PLAYER_NAME + 1]; //MAX_PLAYER_NAME má v základním includu a_samp hodnotu 24, stejně je ale nutno počítat s nulovým znakem. GetPlayerName(playerid, UlozeneJmeno, sizeof(UlozeneJmeno)); return UlozeneJmeno; } //Do proměnné UlozeneJmeno se nám uloží nick hráče, který poté pomocí příkazu return navrátíme. Odeslání zprávy do chatu i s údaji (pozn.: Nutná funkce JmenoHrace): public OnPlayerCommandText(playerid, cmdtext[]) { if(!strcmp(cmdtext, "/pozdravit")) { new StringZpravy[40]; format(StringZpravy, sizeof(StringZpravy), "Hráč %s zdraví", JmenoHrace(playerid)); SendClientMessageToAll(-1, StringZpravy); return 1; } return 0; } //Abychom mohli odeslat zprávu, která bude obsahovat proměnnou, musíme si ji naformátovat. //K tomu potřebujeme vytvořit proměnnou pro samotnou zprávu. (StringZpravy) Změna textu, když hráč napíše zprávu (pozn.: Nutná funkce JmenoHrace): public OnPlayerText(playerid, text[]) { new StringZpravy[145]; format(StringZpravy, sizeof(StringZpravy), "Hráč {FF0000}%s {00FF00}píše: {FFFFFF}%s", JmenoHrace(playerid), text); SendClientMessageToAll(0x00FF00FF, StringZpravy); return 0; } //Opět potřebujeme zprávu naformátovat. Naformátovanou zprávu uložíme do proměnné StringZpravy a poté ji odešleme. //Jak vidíte, lze ve zprávách použít i barvy ve složených závorkách. Pro systém omezení použití (pozn.: Nutná funkce JmenoHrace): new bool:PouzilKit[MAX_PLAYERS]; public OnPlayerCommandText(playerid, cmdtext[]) { if(!strcmp(cmdtext, "/kit")) { if(PouzilKit[playerid]) { SendClientMessage(playerid, -1, "Kit už jsi použil."); return 1; } else { new StringZpravy[50]; format(StringZpravy, sizeof(StringZpravy), "Hráč %s použil kit", JmenoHrace(playerid)); SendClientMessageToAll(-1, StringZpravy); GivePlayerWeapon(playerid, 24, 100); GivePlayerWeapon(playerid, 26, 100); GivePlayerWeapon(playerid, 32, 250); GivePlayerWeapon(playerid, 35, 5); PouzilKit[playerid] = true; return 1; } } return 0; } public OnPlayerSpawn(playerid) { PouzilKit[playerid] = false; return 1; } //Logická globální proměnná PouzilKit bude obsahovat informaci true/false, která se nastaví po použití příkazu /kit. //Poté můžeme kontrolovat, zda hodnota je true či false a podle toho vykonat další kód. Pro omezení počtu zabití (pozn.: Nutná funkce JmenoHrace) (pozn.: POZOR NA FAKEKILL): new ZabilHracu[MAX_PLAYERS]; public OnPlayerDeath(playerid, killerid, reason) { ZabilHracu[killerid]++; if(ZabilHracu[killerid] < 5) { SendClientMessage(killerid, 0xD00000FF, "Nezabíjej ostatní!"); } else { new StringZpravy[60]; format(StringZpravy, sizeof(StringZpravy), "Hráč %s byl vyhozen za zabíjení hráčů.", JmenoHrace(killerid)); SendClientMessageToAll(0xD00000FF, StringZpravy); ZabilHracu[killerid] = 0; Kick(killerid); } return 1; } //Globální proměnná s celým číslem nám přičte jedna pokaždé, když hráč zabije jiného hráče. //Podle hodnoty údaje uloženého v proměnné budeme vykonávat další kód. 4. Závěr: Doufám, že takový formát návodů se uchytí. Připomínám, že návod nemá vystihnout, jak proměnné deklarovat, ale jejich praktické využití. Za konstruktivní kritiku budu rád.
  5. 5 points
    Emit #2: Funkcie a stack Obtížnost: 7/5 Aneb ako to ten compiler robí? Tento tutoriál vyžaduje Zeexov Compiler verziu 3.10.9+, pretože používa nový operátor emit (nie direktívu). Osnova/obsah: Stack a STK register Lokálne premenné Volanie funkcii a FRM register Parametre funkcii Alokácia lokálnych premenných Volanie native funkcií Praktická motivácia Záver 1. Stack a STK register Stack si vlastne môžete predstaviť ako veľký kus pamäte. Ako veľký sa určuje pri kompilácii amx pomocou #pragma dynamic Kde presne máte uložené veci na stacku zistíte pomocou STK registru. STK je jeden z tých 7+ daľších registrov, ktoré som minule spomenul, ale ďalej neriešil. STK ukazuje na poslednú hodnotou, ktorú ste na stack vložili. Je taktiež dôležité spomenúť, že stack je otočený opačne, takže predchádzajúca hodnota je na adrese STK + 4. STK je samozrejme v bajtoch a premenná v PAWN má bežne 4 bajty, takže STK je vždy násobok 4. Taktiež premenná v PAWN sa volá cell a jej veľkosť sa často zapisuje ako cell size. Pre samp vždy cell size = 4. Inštrukcie PUSH a POP sa teda dajú zapísať ako: PUSH.pri/alt - STK = STK - cell size, [STK] = pri/alt POP.pri/alt - STK = pri/alt = [STK], STK + cell size Ako zistíme hodnotu STK? Ako ju zmeníme? Môžeme použiť inštrukcie: LCTRL 4 - pri = STK SCTRL 4 - STK = pri 4 je v týchto inštrukciách register STK. Iné čísla vám dajú iné registre, ale k tým sa dostaneme neskôr. 2. Lokálne premenné Lokálne premenné su v skutočnosti nenápadne uložené na stacku. new a = 3; vo funkcii v skutočnosti nieje nič viac ako emit PUSH.C 3; s tým, že si to miesto, kde sa premenná nachádza compiler zapämatá pod menom a. Ale xhunterx, ako sa k lokálnym premenným dostaneme, keď môžeme pristupovať len k vrchnej hodnote na stacku? No ja som vám trošku klamal. Odstrániť zo stacku môžeme len vrchnú hodnotu, pretože zo stacku vymazávame posnutím registru STK. Nič nám ale nebráni pozrieť sa na akékoľvek miesto na stacku. Na nájdenie týchto premenných nám slúžia inštrukcie: LOAD.S.pri/alt Offset - Načíta lokálnu premennú z Offset do pri/alt STOR.S.pri/alt Offset - Uloží pri/alt do lokálnej premennej z Offset PUSH.S Offset - Uloží hodnotu lokálnej premennej z Offset na zásobník To nám umožní spraviť napríklad: main() { new a = 1; new b = 2; // t = a; a = b; b = a; // Vymeníme a, b emit LOAD.S.pri a; // Načítame a do pri emit LOAD.S.alt b; // Načítame b do alt emit STOR.S.pri b; // Uložíme pri do b emit STOR.S.alt a; // Uložíme alt do a printf("a = %i, b = %i", a, b); // a = 2, b = 1 } 3. Volanie funkcii a FRM register Teraz vieme ako pracovať s lokálnymi premennými, ale ako to vlastne funguje? Na to sa musíme pozrieť, ako sa voláju funkcie. Povedzme že máme: func(a, b, c) { return a + b + c; } main() { new a = 1, c = 3; func(a, 2, c); return 1; } Toto by vyzeralo v asi nejak takto: Test() { //emit PROC; // PROC je automaticky vygenerované na začiatku každej funkcie // Ručne to písať nemusíme, preto je to zakomentované emit CONST.pri a + b + c; emit RETN; // POZOR! Iné ako RET } main() { new a = 1, c = 3; emit PUSH.S c; // Pushneme c na stack emit PUSH.C 2; // Pushneme 2 na stack emit PUSH.S a; // Pushneme a na stack // Všimnite si, že pushujeme v opačnom poradí. Posledný parameter sa pushuje ako prvý. // To je aby k nim funkcia mohla pristupovať v správnom poradí, keďže ona ich uvidí opačne. // c, ktorú sme dali na kopu papierov bude v tej kope najhlbšie. emit PUSH.C 12; // Počet parametrov * cell size emit CALL Test; } V tomto kóde máme 3 nové inštrukcie. CALL, PROC a RETN. Tieto inštrukcie taktiež používajú 2 nové registre FRM a CIP. CIP jednoducho uchováva adresu inštrukcie, ktorá sa práve vykonáva. Tento register sa neustále mení, ako sa vykonávajú inštrukcie. FRM uchováva STK na začiatku funkcie. CALL Adresa - STK = STK - cell size, [STK] = CIP + 8, CIP = Adresa Ak sa na to pozrieťe, prvé 2 časti vyzerajú ako push. A presne to aj robia. Call pushne CIP + 8 na zásobník. CIP + 8 je adresa dalšej inštrukcie po call, keďže samotná inštrukcia je cell (4 bajty) a Adresa je taktiež cell (4 bajty). Nakonie CALL do CIP vloží adresu Adresa. Tým zaistí, že dalšia inštrukcia, ktorá sa bude vykonávať nebude ďalšia inštrukcia v poradí, ale prvá inštrukcia funkcie, ktorú voláme. A prvá inštrukcia funkcie je vždy PROC. PROC - STK = STK - cell size, [STK] = FRM, FRM = STK Znovu dve časti sú push, konkrétne pushneme starú hodnotu FRM na zásobník. Potom do FRM dáme aktuálnu hodnotu STK. Toto nám umožnuje používať inštrukcie ako LOAD.S.pri. Vďaka FRM vieme spočítať, kde sa premenné nachádzajú. A nakoniec nová inštrukcia RETN. RETN - FRM = [STK], CIP = [STK + 4], STK = STK + 12 + [STK + 8] Kde [STK] je stará hodnota FRM od PROC, [STK+4] je adresa dalšej inštrukcie po CALL, [STK+8] je velkosť parametrov funkcie (naše emit PUSH.C 12;) Táto inštrukcia teda spravý niekoľko vecí. Vráti do FRM pôvodnú hodnotu zo zásobníku, ktorú tam uložil PROC Nastavý dalšiu inštrukciu na hodnotu zo zásobníku, teda na hodnotu, ktorú tam uložil CALL, teda na ďalšiu inštrukciu po CALL Vymaže zo zásobníku všetky uložené hodnoty a parametre funkcie. Stack teda vo vnútry funkcie Test v našom príklade vyzerá takto: STACK = Stary_FRM, Navratova_Adresa, Velkost_Parametrov (=12), a, 2, c Pre úplnosť presné definície tývhto inštrukcií sú. LOAD.S.pri/alt Offset - pri/alt = [FRM + Offset] STOR.S.pri/alt Offset - [FRM + Offset] = pri/alt PUSH.S Offset - STK = STK - cell size, [STK] = [FRM + Offset] Mentálne cvičenie: Pre inštrukcie sú mená lokálnych premenných vlastne len Offset. Aký offset má premenná a v tejto funkcii? Bonus: aký offset má b? Test(b) { new a; return a + b; } 4. Parametre Funkcií Ako ste si mohli všimnúť podla posledného mentálneho cvičenia, parametre funkcie majú vlastne taktiež svoj offset voči FRM. A naozaj aj na ne môžeme pristupovať aj k parametrom funkcie. Napríklad funkcia z cvičenia sa dá napísať aj takto: Test(b) { new a; emit LOAD.S.pri a; emit LOAD.S.alt b; emit ADD; emit RETN; // Návratová hodnota je uložená v pri } 5. Alokácia lokálnych premenných Ako som už písal, lokálne premenné sa alokujú obyčajným pushom. Ak máte new a; vznikne emit PUSH.C 0; new b = 5; vznikne emit PUSH.C 5; Ako sa ale tieto premenné dealokujú? Mohli by sme použiť vždy POP, ale to by bolo pomalé a neefektívne. Miesto totoho existuje inštrukcia STACK. STACK Size - STK = STK + Size Takže ak chcem dealokovať 10 premenných (10 * cell size = 40 bajtov), napíšem emit STACK 40; Takže napríklad funkcia AllocTest() { new a, b, c, d; { new e, f; // Nieco } // Nieco2 } Bude po compilacii vyzerať nejak takto: AllocTest() { emit PUSH.C 0; emit PUSH.C 0; emit PUSH.C 0; emit PUSH.C 0; { emit PUSH.C 0; emit PUSH.C 0; // Nieco emit STACK 8; } // Nieco2 emit STACK 16; } Všimnite si, že v tomto prípade {} ani nepotrebujem, napísal som ich sem len pre prehľadnosť. Ešte stále tu ale máme veľa PUSH.C 0. Čo ak budeme chcieť vela lokálnych premenných. Môžeme to nejak zlepšiť? V podstate áno, ale je to zložité. Za prvé, FRM je register číslo 5, takže LCTRL 5 nám načíta FRM do pri. MOVE.pri/alt - pri = alt/alt = pri FILL Size - Vyplní rozsah od alt, veľkosti Size hodnotou pri. alt musí byť násobok cell size. Test() { emit STACK -20; // Alokujeme 5 * cell size miesta na stacku emit ADDR.alt -20; // Do alt dáme adresu začiatku premenných. emit ZERO.pri; // Nastaví pri na 0 emit FILL 20; // Vyplníme miesto od STK velkosti 20 nulami, čiže vynulujeme našich 5 premenných // Máme 5 lokálnych premenných emit STACK 20; // uvolníme premenné } 6. Volanie native funkcií Native funkcie môžeme volať pomocou inštrukcie: SYSREQ.C Func - Zavolá native funkciu Func Native funkcie sa však chovajú inak, ako normálne funkcie. Na rozdiel od normalných PAWN funkcií si po sebe neupracú, takže všetky premenné, ktoré ste pushli na zásobník musíte vymazať ručne. Príklad volania native funkcie: CallSCM(playerid, color, const str[]) { emit push.s str; // Pushneme posledný parameter emit push.s color; // Pushneme stredný parameter emit push.s playerid; // Pushneme prvý parameter emit push.c 12; // Pushneme velkosť parametrov emit sysreq.c SendClientMessage; // Zavoláme SendClientMessage emit stack 16; // Upraceme zásobník. 12 pre parametre + 4 pre velkosť. // 4x Push * cell size = 16 emit retn; // výsledok native je taktiež v pri, takže môžeme rovno return } Taktiež je dôležité, aby ste native ktorý takto voláte niekde použili mimo emit. Ak daný native nieje nikde použitý normálne, compiler ho nezpozná a crashne (compiler v3.10.9). 7. Praktická motivácia Často chceme vytvoriť funkciu, ktorá berie premnlivý počet argumentov a posunie ich dalšej funkcii, napríklad format. To však spraviť v PAWN je veľmi zložité. Tu je ukážka jedného možného spôsobu, ako na to: Použijeme priamo parametre, ktoré poslali našej funkcii a oklameme format tak, aby si myslel, že sú to parametre pre neho. Samozrejme prvé 2 parametre musíme zmeniť. stock SendClientMessagef(playerid, color, const msg[], ...) { new p, c, stk, str; emit { // Zálohujeme premenné load.s.pri color stor.s.pri c load.s.pri playerid stor.s.pri p // Nastavíme max velkosť pola pre format, argument 2 const.pri 145 stor.s.pri color // Vytvoríme pole na heape a vložíme ho ako argument 1 pre format heap 145 stor.s.alt playerid stor.s.alt str // Uložíme si kópiu na neskôr // Uložíme STK do zálohy lctrl 4 stor.s.pri stk // Nastavíme STK tak, aby format zobral parametre tejto funkcie // ako si pamatáme, stack vo funkcii vyzerá takto // STACK = ..., c, p, OFRM, RETADDR, PARAMSIZE, playerid, color, msg, ... // A FRM ukazuje na OFRM. Ďalej na volanie funkcie chceme na stacku mať // STACK = PARAMSIZE, playerid, color, msg, ... // To znamená, že musíme zobrať FRM a posunúť ho o 8 bajtov (2 celly) lctrl 5 // Získame FRM add.c 8 // Pridáme 8 sctrl 4 // Vložíme do STK // Teraz môžeme pekne zavolať format sysreq.c format // Keďže native po sebe neupratujú, ani nepoužívajú stack // jediné, čo sa volaním zmenilo je pri (return formatu) a samozrejme obsah str // Vrátime parametre zo zálohy load.s.pri c stor.s.pri color load.s.pri p stor.s.pri playerid // Vrátime STK zo zálohy load.s.pri stk sctrl 4 // Zavoláme normálne SendClientMessage push.s str push.s color push.s playerid push.c 12 sysreq.c SendClientMessage stack 16 // Uvolníme string z heapu prec heap -145 // Alebo aj // load.s.pri str // sctrl 2 // 2 = HEA } return 1; } 8. Záver Na záver by som ešte chcel zabohovať na dokumentáciu pawna. 3 verzie PAWN Implementer's Guide v PDF po ruke v pohotovosti, ani jeden nezodpovedá tomu, ako to reálne funguje. Napríklad podla guide je STK pointer na volné misto nad poslednou hodnotou v zásobníku. To ale jednoduchým testom vidíme, že nieje pravda... Podľa guide taktiež CALL robí [STK] = CIP + 5 (inštrukcia má asi mať velkosť 1 bajt). To ale taktiež nieje pravda. Inštrukcie ako ADDR.pri/alt ani v jednej z týchto príručiek niesu, no compiler ich veselo používa. A samozrejme ak dáte native funkcii adresu, ktorá je pod STK, tak crashne server. Nedokážem nájsť ani vidieť žiadny dôvod, prečo by tomu tak malo byť. Nikde inde sa nič také nedeje. No každopádne tu ano, takže super. Anilen hlášku to nenapíše... Ak niekde nájdem na predaj náhradné nervy, tak sa uvidíme pri časti 3. V tej sa pozrieme na skoky a pointery.
  6. 4 points
    Vypadá to hezky. Zkuste se prosím chovat slušně k sobě navzájem. Podle mě nemá cenu se hádat o to, čí práce je lepší. Tohle je a vždycky bude subjektivní, tak to respektujte.
  7. 3 points
    Já bych řekl že to tady nemá vůbec co dělat
  8. 3 points
    Tu máš tak 25 % práce hotové na ukázku. Zbytek lze z toho dodělat snadno, včetně vytváření in-game: #include <a_samp> #define MAX_HOUSES (100) enum enum_House { //sample code } enum enum_Player { //sample code } new House[MAX_HOUSES][enum_House]; new Player[MAX_PLAYERS][enum_Player];
  9. 3 points
    Napríklad, už tvoja fotka porušuje toto právo @Castie . A inak čo robia prosím vás v tom europarlamente, to fakt nevedia robiť nejaké prospešnejšie vecí k svetu ? Dávajú pokutu googlu za to, že má predinštalované alikácie vo svojom Androide ( akože srsly ?!?!?! ), a teraz toto ? Však tým to už na tie hlavy poriadne je**. Mali by sa skôr uvedomiť, čo je dôležitejšie a nie takéto sr**ky vypúštať do sveta...
  10. 3 points
    Říká někdo, kdo vytváří čím dál více zabugované RP servery. I amatérský pawner jako já po tobě opravoval několik otravných bugů. Co se týče textdrawů, zrovna moc ses nepředvedl. Nemluvím o CL-RP které jsi nedávno vypustil, to předčilo tvou poslední práci chybovostí desetinásobně, dokonce přibyly i gamebreaking bugy. Až vytvoříš něco podobného, pak flamuj ostatní. K tématu: Moc povedený Textdraw. A to si ještě pamatuju doby, kdy jsi odmítal jakékoliv TD dělat s tím ,že to "neumíš". xD
  11. 3 points
    Menší update vzhledu mobilu
  12. 2 points
    Zdravím, sice nevím do jaké sekce to dát tak to postuji zde. Chtěl bych Vám tady ukázat, co se mi povedlo pomocí textdrawu, samozřejmě k tomu mám i funkční script. Budu rád když mi tu necháte Váš názor na tuto práci
  13. 2 points
    https://wiki.sa-mp.com/wiki/OnPlayerCommandText https://wiki.sa-mp.com/wiki/SetPlayerHealth Uzdravení hráče (heal) není vlastně nic více, než jen nastavení života u daného hráče na maximální(tím myslím viditelně, jinak jde nastavit klidně i víc) hodnotu, což je 100. PS: Jelikož jde o datový typ float, nebo-li desetinná čísla, můžeš jeho život upřesnit úplně "do tip ťop" na 100.0. Doporučuji návod: Přidání příkazu není vlastně nic víc než jen porovnání dvou řetězců(stringů nebo lépe textů). public OnPlayerCommandText(playerid, cmdtext[]) { if (!strcmp("/help", cmdtext, true)) { return 1; } Jednoduše řečeno, co to udělá: "Je zadaný příkaz(cmdtext) hráčem(playerid) stejný jako /help? Jestli ano, stane se následující" a tím "následujícím" je blok dalšího kódů pod funkcí(to znamená pod { ) Jelikož chceš toho hráče uzdravit využiješ na to funkci, která se zabývá změnou životů u hráčů a to je SetPlayerHealth. A protože ho chceš uzdravit a ne ho zabít, nastavíš mu život na 100. SetPlayerHealth(playerid, 100.0); Ta 100.0 je nastavitelný parametr, stejně jako playerid. Jelikož ho ale public OnPlayerCommandText zná, tak ho stačí jen napsat a playerid se nahradí patřičným id hráče, co ten příkaz vyvolal. Nemusíš zadávat zrovna 100.0. Můžeš klidně i polovinu 50.0, nebo čtvrtinu 25.0. Doporučuji návod: public OnPlayerCommandText(playerid, cmdtext[]) { if (!strcmp("/heal", cmdtext, true)) { SetPlayerHealth(playerid, 100.0); return 1; // dopln si Tadá.
  14. 2 points
    Kdyby se zde našla skupinka (a časem třeba komunita) lidí, kteří by jevili zájem, není problém sekci pro GTA V zavést. Stačí napsat.
  15. 2 points
    Pravda. Narizuji blbosti, a dulezite veci, ktere by se meli narizovat nechaji at si kazdy zvoli jak chce. Napriklad kdyz se bude rusit stridani casu, tak si kazdy stat muze vybrat jaky cas bude mit. Jako WTF? Tohle je misto kde by s melo neco narizovat, at ma Evropa jeden cas a je jedno jaky, ale vsude stejny.
  16. 1 point
    Já bych řekl, že když se někde ucházíš o místo jako pawner pro server a ještě k tomu přidáš, že "zaměstnavatel" je děcko... tak bych i tuhle reakci docela očekával(i když to druhé varování je už moc). A ještě k tomu jen varování. Já bych to skončil rovnou banem. Dneska je hromada pawnerů a je snadné se jím stát. Takže, že tebe "odmítnou" ať už hrubě nebo ne, je to pro ně lepší, protože furt mají z čeho vybírat...
  17. 1 point
    Mohol by si sem napísať ako? Pre ľudí s podobným problémom, ktorí sem zablúdia.
  18. 1 point
    Zdar, ozvi se mi do SZ ohledně panelu, co přesné od něho čekáš a můžu se na to podívat.
  19. 1 point
    Úplně stejně jako u RCON přihlášení, prostě mu nastav podmínku na AFK po zadání příkazu a pak to zkontroluj.
  20. 1 point
    Ještě pár takovejch hovadin a EU se začne rozpadat. Páni intelgenti, co to vymýšlej by se měli zamyslet nad sebou a ústavní léčbou, ne ještě nad vyhláškou pro ostatní.
  21. 1 point
    Kdyby to někoho zajímalo, tak dnes proběhlo finální hlasování o této směrnici. Evropský parlament si jej odhlasoval, takže do dvou let by ji měl každý stát včlenit do svých zákonů. (1) (2)
  22. 1 point
    var tileArray = new Array(); //nemusím vysvětlovat var probabilityModifier = 0; //jakási pravděpodobnost var mapWidth=135; //velikost var mapheight=65; //velikost var tileSize=10; //velikost pole, pravděpodobvně v pixelech //modifikátory velikosti a četnosti var landMassAmount=2; // scale of 1 to 5 var landMassSize=3; // scale of 1 to 5 $('#stage').css('width',(mapWidth*tileSize)+'px'); //místo vykreslení //cyklus projede každou dalždici na mapě for (var i = 0; i < mapWidth*mapheight; i++) { var probability = 0; var probabilityModifier = 0; if (i<(mapWidth*2)||i%mapWidth<2||i%mapWidth>(mapWidth-3)||i>(mapWidth*mapheight)-((mapWidth*2)+1)){ // kraje mapy budou voda, takže pravděpodobnost na zeleň je 0 probability=0; } else { probability = 15 + landMassAmount; //pravděpodobnost je jakási konstanta 15 + množství zeleně if (i>(mapWidth*2)+2){ //zjišťuje jaké políčka jsou okolo a na základě toho se rozhodne co to bude za políčko (tím se docílí toho, že nebude miliarda mikroostrovů) // Conform the tile upwards and to the left to its surroundings var conformity = (tileArray[i-mapWidth-1]==(tileArray[i-(mapWidth*2)-1]))+ (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth]))+ (tileArray[i-mapWidth-1]==(tileArray[i-1]))+ (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth-2])); if (conformity<2) { tileArray[i-mapWidth-1]=!tileArray[i-mapWidth-1]; } } //pravděpodobnostní modifikátor, zda se bude v "ostrově" pokračovat, nechceme přeci jednu velkou zelenou placku probabilityModifier = (tileArray[i-1]+tileArray[i-mapWidth]+tileArray[i-mapWidth+1])*(19+(landMassSize*1.4)); } rndm=(Math.random()*101); //zde je náhoda, která určuje tu náhodnost tileArray[i]=(rndm<(probability+probabilityModifier)); //finální podmínka která řekne co to bude za políčko } //jen vykreslení for (var i = 0; i < tileArray.length; i++) { if (tileArray[i]){ $('#stage').append('<div class="tile earth '+i+'"> </div>'); } else{ $('#stage').append('<div class="tile water '+i+'"> </div>'); } } Nemusí to tak být, je to popsané tak, jak jsem to v rychlosti pochopil já CREDITS: http://jsfiddle.net/AyexeM/zMZ9y/
  23. 1 point
    Ahoj, zkus tento sám jsem ho kdysi používat Just System dal jsme ti odkaz přímo na stažení máš tam napsáno co všechno obsahuje atd... tak se na to můžeš kouknout
  24. 1 point
    Jde to stáhnout, dokonce jsem to zkoušel teď na mobilu
  25. 1 point
    Hunterov úvod do bezpečnej komunikácie Pokračovanie môjho návodu Hunterov úvod do bezpečnosti. Tentokrát sa zameriavam na bezpečnú komunikáciu cez internet. V tomto zozname som vybral len aplikácie, ktoré stoja za zváženie a majú rôzne výhody a nevýhody. Aplikácie, ktoré sú podobné alebo horšie ako uvedené som nespomínal, keďže nieje dôvod ich používať. 1. E-Mail 1.1 Proton mail Protonmail je email zameraný na bezpečnosť. Používa sa pomocou prehliadača alebo mobilnej aplikácie. Výhody: + Skoro každý má e-mail + E2E Šifrovanie, takže ani protonmail nemôže vidieť vaše správy + Hostované vo švajčiarsku, kde právo na súkromie je zakotvené v ústave Nevýhody: - Bezpečnosť v prehliadači je pochybná v porovnaní s aplikácoiu - Ak ten, s kým komunikujete nepoužíva proton mail, tak je šifrovanie zložitejšie a menej bezpečné. 1.2 Enigmail Enigmail je rozšírenie pre Mozilla Thunderbird. Umožnuje šifrovanie mailov pomocou GPG. Výhody: + Skoro každý má e-mail + Funguje s každým providerom e-mailu. + GPG je staré a dobre otestované Nevýhody: - GPG je veľmi zložité na správne použitie, ľahko spravíte kritickú chybu, ktorá znehodnotí vašu bezpečnosť 2. IM s telefónnym číslom 2.1 Signal Signal je aplikácia podobná whatsapp. Používa silné E2E šifrovanie pomocou Signal protokolu, takže provider nevidí obsah vašich správ. Signal neukladá metadáta, jedine čo sa ukladá je: dátum registrácie, dátum posledného prihlásenia. Výhody: + Podobné whatsapp, jednoduché na použitie. + E2E Šifrovanie, takže ani Signal nemôže vidieť vaše správy + Neukladá metadáta Nevýhody: - Hostované v USA, kde ochrana súkromia je porovnateľná s diktatúrami. - Vyžaduje telefónne číslo, ktoré každý, komu napíšete uvidí. 3. IM bez telefónneho čísla 3.1 XMPP XMPP je otvorený federovaný protokol. To že je otvorený znamená, že existuje viacero rôznych aplikácií, ktoré môžu komunikovať jedna s druhou. To že je federovaný znamená, že si môžete vybrať providera alebo hostovať uzol samy rovnako ako u emailu. Osobne používam Gajim ako PC klient, Conversations ako android klienta a dismail.de ako providera. Výhody: + Federovaný, umožnuje si vybrať providera s dobrým súkromím alebo hostovať vlastný server + Umožnuje E2E šifrovanie pomocou rozšírenie, používa variantu Signal protokolu zvanú OMEMO Nevýhody: - Veľmi zložitý na použitie - Klienti majú často nízku kvalitu - OMEMO je len rozšírenie, navyše ho veľa klientov nepodporuje - Neviem nájsť švajčiarsky server 3.2 Wire Wire je aplikácia, ktorá je zadarmo pre súkromné účely a platená pre komerčné použitie. Výhody: + Jasný plán speňaženia, profesionálny prístup + E2E šifrovanie, takže Wire nemôže čítať vaše správy + Jednoduchý na použitie Nevýhody: - Naposledy keď som testoval zabugovaný - Komerčná firma pravdepodobne nebude riskovať svoj biznis proti súdnym príkazom, možná spolupráca s vládou 4. Decentralizované IM 4.1 Tox Tox je decentralizovaná aplikácia, takže žiadna jedna firma nemôže sledovať vašu aktivitu a je velmi zložité Tox zavrieť, podobne ako Torrenty. Tox je otvorený a má viacero klientov podobne ako XMPP. Výhody: + Decentralizovaný + Viac klientov, používam qTox a zdá sa, že má dobrú kvalitu + Samozrejme E2E šifrovanie (v decentralizovanom systéme je nutné). Nevýhody: - Nemôžete posielať správy offline používateľom, keďže neexistuje server, ktorý by ich uchovával - Užívateľa musíte pridať pomocou pseudo-náhodného textu a nie zapamätateľného užívateľského mena. 5. YOLO kategória 5.1 Deamonsaw Deamonsaw je aplikácia, ktorá využíva sociálnu kryptografiu a každý môže hostovať vlastný server. Server neukladá žiadne informácie. Výhody: + Extrémna bezpečnosť a súkromie + Celkom pekná aplikácia Nevýhody: - Najnovšia verzia nieje open-source - Socialna kryptografia je otravná - Neukladá správy, takže keď ste offline sa vám stratia - Žiadny rozumný človek by niečo takéto nikdy nepoužíval 6. Sociálne siete 6.1 Mastodon Mastodon je federovaná sociálna sieť podobná twitteru. Výhody: + Veľmi pekná stránka, možno krajšia ako twitter + Federovaná, takže sa môžete sami rozhodnúť, komu zveríte svoje dáta + Môžeťe svoje dáta stiahnuť a nahrať na iný uzol, ak zmeníte názor Nevýhody: - Ako sociálna sieť nemá E2E šifrovanie, takže musíte veriť uzlom a neposielať citlivé údaje - Chvíľu trvá si zvyknúť na štýl stránky, ktorý je veľmi odlišný od twitteru. 6.2 Diaspora* Diaspora* je federovaná sociálna sieť, ktorá chce konkurovať Facebooku. Myšlienka je síce pekná, ale zatiaľ to nieje konkurencieschopné. Výhody: + Celkom jednoduchý systém podobný Google+ + Federovaná, takže sa môžete sami rozhodnúť, komu zveríte svoje dáta + Môžeťe svoje dáta stiahnuť a nahrať na iný uzol, ak zmeníte názor Nevýhody: - Ako sociálna sieť nemá E2E šifrovanie, takže musíte veriť uzlom a neposielať citlivé údaje - Nemá skupiny, ktoré sú dôležitou súčasťou FB - Celkovo pomerne nedokončená sociálna sieť, čo sa funkcií týka 7. Doplnkové 7.1 Privatebin Privatebin je služba podobná pastebinu, avšak umožňuje E2E symetrické šifrovanie (zamknutie na heslo). Môžete hostovať vlastný server, alebo použiť verejný. Okrem bežného zdieľania je taktiež vďaka funkcii vymazania po prvom prečítaní vhodný na zdieľanie informácií vo verejnom prostredí. Napríklad ak by som chcel v chate na pawno.cz niekomu dať svoj email (a neexistovali by súkromné správy), stačilo by ho vložiť do pastu a nastaviť na jedno prečítanie. Potom ho poslať do pawno chatu. Ten komu som ho chcel poslať by si ho prečítal a ak by niekdo neskôr prišiel a chcel ho získať, už by bol smazaný. Výhody: + E2E šifrovanie, heslo + kľúč v linku + Jednoduché hostovanie vlastného serveru aj na free hostingoch. + Umožňuje vymazať paste po prvom prečítaní a zároveň nastaviť dobu vypršania. + Šifruje E2E aj keď nezadáte heslo, heslo je automaticky vložené do linku. Nevýhody: Nevidím žiadne 7.2 Ghostbin Ghostbin je služba podobná pastebinu a privatebinu. Umožňuje E2E symetrické šifrovanie (zamknutie na heslo). Má krajšie formátovanie kódu ako privatebin, avšak horšiu bezpečnosť. Výhody: + E2E šifrovanie + Pekná prodpora pre rôzne programovacie jazyky. Nevýhody: - Bez hesla nešifruje, takze silné heslo je extra dôležité (na rozdiel od privatebinu) 8. Čo tu chýba V tomto návode chýba služba na zdieľanie súborov. Počul som dobré veci o OnionShare a zaujímavo vyzerá aj Magic Wormhole. Nič menej keďže som tieto aplikácie osobne neskúšal, netrúfam si ich tu odporúčať alebo hodnotiť. Taktiež tu chýba cloudové riešenie. Ja osobne momentálne preferujem Nextcloud, ale taktiež ho nemám dostatočne dlho na to, aby som hodnotil. Zaujal ma aj Seafile. Podobné je owncloud. Možno aj Least Authority S4 a spideroak.
×