Üzenetek megjelenítése

Ez a szekció lehetővé teszi a felhasználó által írt összes hozzászólás megtekintését. Vedd figyelembe, hogy csak azokba a fórumokba írt hozzászólásokat látod, amelyekhez hozzáférésed van.


Témák - krisk

Oldalak: 1 2 [3] 4 5 ... 7
31
Képek / Videók / Board James - legjobb kisfilm ever
« Dátum: 2013. Április 04. - 18:49:50 »
Ezt most azonnal meg kell néznetek. Nem akarom lelõni a poént:
 

32
Általános / Rougelike Dungeon-Crawler
« Dátum: 2013. Március 02. - 21:16:21 »
\"QE8VC0tvAwMBUAgYFAVQ\"
Ez a már korábban ismertetett telnet-SAMP hibrid továbbfejlesztése: samp plugin segítségével rougelike dungeon-cralwer: a pályát véletlenszerûen generálja.
Ez egy debug mód, a valósban a labirintusnak csak egy része (a player körüli, alapértelmezettként 5x5-ös terület), ez elég nagy, hogy egy szobában kb. elláss, de nem elég nagy, hogy minden szörnyet ki tudj védeni.
X: kõfal, a pálya széle
+ (kék): sárfal, a termek széle
+ (piros): ajtók
#: járatok
( : kincs
. : padló
T: (egyelõre debug) csapda
k: kulcs (egyelõre nincs hasznuk)
<: feljárat (pálya kezdete)
>: lejárat (pálya vége, új pálya generálása)
@: játékos
A játék menti a statisztikáid (sqlite), amiket ki is ír a pálya aljára (debug módban ez sem látszik). A csapdák léte titok, sokfajta lehet (a nagy T csak a debug miatt van úgy).
A lejárat (a következõ pályára vezetõ warp) látható a betöltési táv kétszeresérõl, tehát ha jó nyomon vagy, megtalálhatod hamar.
A feljárat (spawn-hely) a térképen folyamatosan látszik, így tájékozódási pontot nyújt, ha esetleg eltévednél (elég nehéz, annyira azért nem jó az algoritmus).

33
[mod]x+1. ilyen téma, zárok[/mod]

34
Fórum Archívum (Témák/Fórumok) / Re:Mit nem lehet megcsinálni...
« Dátum: 2013. Március 01. - 06:17:20 »
Idézetet írta: Anthony date=1362106910\" data-ipsquote-contentapp=\"forums\" data-ipsquote-contenttype=\"forums\" data-ipsquote-contentid=\"34366\" data-ipsquote-contentclass=\"forums_Topic
Nekem ér válaszolni? :D
 
Költõi kérdés volt :D (amúgy legelsõ sor)
Ahhoz képest, hogy Kye nem akarja \"játékmotorrá\" tenni a SAMPot, a pluginokkal el tudnám képzelni, hogy valaki egyszer ír egy SAMP webszervert.

35
Fórum Archívum (Témák/Fórumok) / Mit nem lehet megcsinálni...
« Dátum: 2013. Február 28. - 21:32:02 »
Vajon melyik szerver alkalmazásból lett átalakítva ez a telnettel játszható szöveges kalandjáték  :hmmm:?
\"QE8VCUtvAwMBUFJERAVQ\"

36
Beszélgetés / TAS
« Dátum: 2013. Február 09. - 14:32:28 »
Mi a véleményetek a TAS végigjátszásokról? (Aki nem tudná: a TAS egy olyan speedrun, tehát gyors végigjátszás, amiben emulátor, glitchek, frame-by-frame trükkök és egyéb dolgok segítségével méggyorsabb eredményeket érnek el. Természetesen az emulátoros gyorsítások/throttlek és a frameskip nem játszik. Ha SAMP hasonlatba akarnám helyezni, akkor parkour / dm glitchek kategóriájában van.)
 

Rockman 12 perc 21.34 másodperc alatt. Ha valaki már játszott vele, az tudja, hogy irtózatosan nehéz játék, mondjuk a TAS-ban lazán levágják a pályák háromnegyedét glitchek segítségével.
 

SMB3, 10:25.6 alatt. Ez meg egy 8 világos játék (mondjuk síppal lehet csökkenteni a világok számát).
Ez nem egy videó topic, csak egy beszélgetés, hogy szerintetek van-e létjogosultsága az ilyen videóknak, valamint hogy mi a véleményetek róluk.

37
Tanuljunk PAWN nyelvet / Új hooking method
« Dátum: 2013. Január 13. - 08:38:09 »
CREDITS
Ez nem az én munkám, és csak egy rövid tutorial lesz. A hivatalos fórumon ipsBruno jött rá erre az új fajta hooking methodra. Az érdekesség az, hogy senki se tudja, hogy mûködik, mivel az #if defined ág a függvény létrehozása elõtt található: tehát akkor még nem is létezett. De mûködik.
A MÓDSZER
Ismerjük (vagy nem) a y_hookot, az _ALS módszert, az automatás verziót, CallLocalFunction-os verziót, és még rengeteg mást, amivel függvényt lehet hookolni. Ha valaki nem tudná, mi az, valami ilyesmit kell elképzelni:
 

// streamer.ini
STREAMER_Startup() {
  // streamer kód
  printf(\"streamer betöltve!\");
  return 1;
}

 
Azt akarjuk, hogy a fenti függvény az OnGameModeInit lényegi lefutása elõtt fusson le. A legegyszerûbb, és sokak által mai napig használt módszer a következõ:
 

//gm.pwn
#include <a_samp>
#include <streamer.ini>
public OnGameModeInit() {
  STREAMER_Startup();
  // gm kód
  return 1;
}

 
Ez szép és jó, de könnyen találhatunk hiányosságokat is: például mindig bele kell írni a kódba, és mindig a GameModeInit legelsõ soraként. Ez több hasonlóan beágyazott függvénykönyvtárnál problémás lehet.
Na: erre talált egy új modszert a fenti fórumozó:
 

//streamer.ini
public OnGameModeInit()
{
  // streamer kód
  printf(\"Streamer betöltve!\");
  #if defined GameModeInit
     return GameModeInit();
  #else
     return true;
   #endif
}
#define OnGameModeInit GameModeInit
#if defined GameModeInit
    forward GameModeInit();
#endif

 
A GM-ben pedig meghívjuk a következõt:
 

//gm.pwn
#include <a_samp>
#include <streamer.ini>
public OnGameModeInit () {
    print(\"Játékmód betöltve\");
    return true;
}

 
Ezzel ugyanazt a hatást értük el, elõször a \"Streamer betöltve!\" majd a \"Játékmód betöltve!\" kimenet jelenik meg. A legjobb az egészben az, hogy akkor is mûködik, ha sosem hívódott meg a játékmódban az OnGameModeInit, nem warningol, és persze, hogy nem használ sem automatát, sem CallLocalFunctiont, mivel az egész direktívákból áll, a fordítónak szinte semmi dolga nincs az egésszel: amitõl hihetetlen gyors lesz.

38
KEZDJÜK A RIZSÁVAL
Igen, tudom, hogy van egy teljesen ugyanilyen leírás a hivatalos fórumon, és azt is, hogy ugyanazt fogom gyakorlatilag elmondani kétszer. Viszont fontosnak érzem, hogy azt az alapot kicsit felturbózzam, és megérthetõvé tegyem azok számára is, akik esetleg nem értik elsõre, hogy mi az a LIFO, heap, stack, és a többi. Épp ezért, és az emészthetõség miatt nem állt szándékomban a formális szaknyelv használata.
Ez után pedig térjünk rá, hogy ez a cikk lényegében kinek jó: akit érdekel. Ettõl a módod gyorsabb nem lesz, kevesebb bug biztos nem lesz benne, nem is lesz stabilabb, tehát tényleg csak azoknak ajánlom, akiket érdekel, hogy valójában hogy is fut le a kódjuk, amit írnak.
AMX
Mint ahogy az a deAMX topicban is elhangzott, az AMX rövidítés jelentése Abstract Machine Executor, vagyis absztrakt gép végrehajtó, értve ez alatt azt, hogy ez az a kód, amivel az absztrakt gép végrehajtja az utasításokat.
AZ ABSZTRAKT GÉPEK
Mi is egy absztrakt gép? Mint azt bizonyára mindenki tudja, a legfontosabb elméleti gép, automata az ún. Turing-gép. Gyakorlatilag egy olyan automata, amely végtelen sok memóriával rendelkezik. De mi is egy automata?
Elõször is szögezzük le, hogy a Turing-gép nem létezik, csak egy elméleti modell. Ezért használunk rá nagyon egyszerû, leíró nyelvezetet. A Turing-gép egy olyan gép, amelyhez egy végtelen hosszú papírszalag tartozik. Minden papírszalagon \"betûk\"/\"szimbólumok\" (ez a hivatalos megfogalmazás) találhatók. Egyszerûség miatt tekintsük ezeket nullának és egynek. A gépbe be van programozva egy adott utasítássorozat, amit végrehajt a szalagon, ezt a logikai vezérlõegységbe programozták be.
Például tegyük fel, hogy a szalagunkra ez van írva: 0[0]11. Az olvasófej a második nullán áll. Tegyük fel, hogy az az utasítássorozat van beprogramozva, hogy
 

1: HA 0 AKKOR 1
2: HA 1 AKKOR 0
3: EGYEL ELÕRE
4: UGRÁS 1-RE

 
A következõ utasítás a szalagon lévõ karaktereket 0100-ra változtatja, és nem áll meg. Amennyiben nem ugranánk vissza egyre a következõ változó értéke már nem lenne módosítva.
MIÉRT ELÕNYÖS AZ AMX?
Az absztrakt gép egy számítógép virtuálisan. Ennek több elõnye van az x86 assemblyvel (tehát a \"tényleges\" natív assemblyvel) szemben:
 
  • Több platformon, több architektúrán elfut: a p-kód miatt minden operációs rendszeren és a 8-bitestõl a 64-bites processzorig átportolták.

  • A p-kódnak több elõnye is van: a modern operációs rendszerek nem engednek a CODE szegmensbe írni és a DATA szegmenst lefuttatni.

  • Sokkal egyszerûbb a programot a saját \"mini-számítógépen\" (sandbox) futtatni: egy natív assemblyben írt program rekurzív utasítása könnyen kifagyaszthatja az alkalmazást, és megrongálhatja a rendszer STACK-jét.


A REGISZTEREK
Az AMX regisztereket használó absztrakt gép. A regiszterek a processzorok elidegeníthetetlen részei a Neumman-elvek óta. Ennek elõnye az, hogy az absztrakt gép utasítása jobban \"rásimul\" a natív kódra, tehát a futásidõ csökken, valamint az utasítások száma csökkenthetõ.
Az AMX egy kétregiszteres struktúra, két számításra alkalmas regiszter található meg: a PRI és az ALT.
Az alábbi kódot:
 
a = bö 2;

 
Az AMX assemblyjében így kaphatjuk meg:
 

load.pri b ;betöltjük a b változót az elsõdleges (PRI) regiszterbe
const.alt 2 ;betöltjük a \"2\" konstanst az alternatív (ALT) regiszterbe
add ;az add utasítás a következõt csinálja: PRI = PRI + ALT
stor.pri a ;az a változóba eltároljuk a PRI értékét

 
A REGISZTEREK LISTÁJA
Regiszter rövidítéseRegiszter teljes neveHasználata
PRIPrimary RegisterALU, logikai és számolási mûveletek
ALTAlternative registerMásodlagos regiszter a bonyorultabb mûveletekhez
FRMStack frame pointerEgy függvény lefutása elõtti stack állapotot tárolja
CIPCode instruction pointerA végrehajtandó utasítás (az AMX-ben szinte mindig a main()-ra mutató pointer)
DATDATA pointerA DATA szegmens kezdetére mutató pointer
CODCODE pointerA CODE szegmens kezdete
STPSTACK topA STACK teteje / legalacsonyabb memóriacíme
STKSTACK indexA STACK jelenlegi helyzete
HEAHEAP pointerA HEAP teteje
MEMÓRIAKÉP
Az AMX fájl memóriaképét, vagyis a memóriában elfoglalt helyét mutatja be az alábbi táblázat. A HEAP és a STACK alapvetõen nincs a bináris fájlban, elõállítását az AMX végzi a PREFIX adatok alapján.
Ahhoz, hogy a lenti memóriaképnek megfelelõ bináris kódot kapj, használd a #pragma compress 0 direktívát a scriptedben.
LEGALACSONYABB MEM.-CÍM
PREFIX
CODE
DATA
HEAP ⇊
STACK ⇈
LEGMAGASABB MEM.-CÍM


A prefix
A prefix rész a kód legelején terül el, és elsõdleges feladata általános metaadatok, pointerek, és a függvények listáját tárolni. A memóriatérképe a következõ (az X-el jelölt dinamikusan változik az adat mennyiségétõl függõen):
(a teljes táblázat megtalálható a pawn-imp guide-ben, én ezt a verziót Y_Lesstõl szereztem, köszönöm)
MÉRETMemóriaterületLeírás
4MéretA fájl mérete
2Ismeretlen
1Fájl verzióAz AMX verziója
1Minimum VM verzió
2FlagekA fordítónak fordítás közben megadott paraméterek
2Defsize
4COD offsetA CODE szegmens kezdetének helyzete
4DAT offsetA DATA szegmens kezdetének helyzete
4HEA offsetA HEAP szegmens kezdetének helyzete
4STP offsetA STACK szegmens kezdetének helyzete
4CIPA main() függvvény memóriacíme (vagy -1)
4Publikus függvények listájára mutató pointer
4Natívák listájára mutató pointer
4Libek listájára mutató pointer
4Publikus változók listájára mutató pointer
4Public tagek listájára mutató pointer
4Names táblára mutató pointer
XPublic lista
XNative lista
XLib lista
XPubvar lista
XTag lista
XName tábla
A listák egy eleme a következõképp épül fel:
MÉRETMemóriaterületLeírás
4Függvény/változó pointerA függvény kezdetére/vált. helyére mutató pointer
4Név pointer
A Names tábla a stringeket tartalmazza: ömlesztve, tömörítve ábrázojla.
A stringek NULL-delmitáltak (tehát a minden string végén szereplõ \\0 karakter jelzi a string végét), és tömörítettek. A konstansok (különösen a stringkonstansok) a DAT szegmensben tárolódnak, tehát irrelevánsak jelen esetben.


A code szegmens
A TEXT vagy CODE szegmens egy olyan szegmens egy bináris fájlban, vagy a memóriában, amely a futtatható utasításokat tartalmazza. A CODE szegmensnek a memóriában általában csak 1 példányra van szüksége, mivel megosztható. A CODE szegmens szinte mindig csak olvasható, hogy  megakadályozható legyen az, hogy a program véletlen a saját utasításait módosítsa.


A data szegmens
A DATA szegmens a program virtuális memóriájának egy része, az egész program számára elérhetõ (ti. globális) változókat tárolja.


A heap
A heap, vagy \"halom\" a memória dinamikusan használható része. A \"halom\" igen deskriptív: hiszen gyakorlatilag a halomra akármikor hozzáadhatunk vagy elvehetünk valamit anélkül, hogy az egész összedõljön. Ha egy új dinamikus változót hozunk létre, lényegében a heap-bõl vesszük el a területet.
Mivel a létrehozott változónak lefoglalt memóriaterület sosem ismeretes elõre, a new statement mindig egy pointerrel tér vissza a heapban tárolt pozícióval.
A PAWN nyelv nem használ dinamikus változókat, minden változót vagy a DATA (glob), vagy a STACK (lok) szegmensek tárolnak, ezért például a memory leak-ek nem lehetségesek. Azért ide megemlítem, ha valakinek van kedve a memory leakekhez, hogy Y_Less malloc függvénykönyvtárával lehetõséged van \"dinamikus\" memóriát kiosztani (azért idézõjelbe, mert ez sem igazi dinamikus memória, és ez sem a heapben van, csak egyfajta workaround).


A stack
A STACK, hivatalos magyar nevén \"verem\", deskriptívabb nevén \"rakás\" egy memóriakezelési szerkezet. Mielõtt jobban megvizsgáljuk, nézzük meg az alábbi példát:
Tegyük fel, hogy van egy rakás téglád egymáson. Mivel a téglák nehezek és rakásban vannak (tehát mindegyik tégla a másik tetején), ezért lényegében három dolgot tehetsz a téglákkal anélkül, hogy összedõljenek:
 
  • Ránézel a legfelsõ téglára

  • Leveszed a legfelsõ téglát

  • Felraksz egy újabb téglát


A stack egy olyan memóriakezelési struktúra, ami változókat tárol, hasonlóan a tömbökhöz. Viszont míg a tömbökben tetszés szerinti elemet elérhetsz, addig a stack ennél limitáltabb. Lényegében a fenti három dolgot teheted meg a stackkel:
 
  • Megnézed, mi a felsõ érték, vagy top

  • Leveszed a legfelsõ értéket, vagy pop

  • Felraksz egy újabb értéket, vagy push


Ahogy a téglás hasonlat is mondja: ha valaki egy téglát rárak a rakásra, akárki, aki levesz egy téglát a legfelsõt fogja levenni. Ez a LIFO-elv: last in-first out. A legelsõ felrakott elem lesz a legelsõ, amit levesznek.
Ez, bár szép analógia, lehetne egy jobbat is létrehozni. Vegyünk egy adott számú postaládát: mindegyik egymás fölött, mindegyik csak egy dolgot tarthat magában, mindegyik üresként kezdi, és persze mindegyik az alatta lévõvel össze van ragasztva, így a számuk nem változik. A kérdés: ha a postaládák száma nem változtatható, hogyan kapunk egy stacket? Jelöljük meg egy matricával a legmagasabban lévõ üres postaládát. Minden a matrica alatt lévõ postaláda a stack tagja, minden a matrica fölött lévõ postaláda nem a stack tagja.
Ez szinte azonos azzal, hogy mûködik a stack. A stack egy elõre meghatározott mennyiségû memória: a postaládák memóriacímek, és a levelek a memóriacím alatt lévõ adatok. A \"matrica\" a fentebb említett STK regiszter: Stack Index/Stack Pointer, ami mindig a legnagyobb elérhetõ stack címre mutat. Az egyetlen különbség a postaládás hasonlat és a valós stack közt az, hogy ha az adatot el akarjuk tüntetni, nem kell \"kiüríteni\" a postaládát: elég a matricát egyel lejjebb helyezni és az a memóriarész onnantól nem a stack tagja, amíg a következõ memóriarész felül nem írja.
Miket rakunk a stackbe? Változókat, paramétereket, és függvényhívásokat.
Mivel a globális változók a DATA szegmensbe kerülnek, ezért nekünk lényegében csak azzal kell foglalkoznunk, mi történik a lokális változókkal: tehát a függvényeken belül meghívottakkal.
Példaképp tekintsük meg az alábbi kódot:
 

main() { new a=4; foo(a,2); }
foo(a,b) { }

 
Ez, a nem mûködõ, viszont példaként tökéletesen használható kódrészlet tökéletes példa a stack bemutatására. Mikoris a main() függvény meghívja a foo függvényt, az alábbi játszódik le (ezt szaknyelven a Standard Entry Sequence-nek  hívjuk):
Az egyszerûség kedvéért a main()-t fogjuk hívni a meghívó függvvénynek míg a foo()-t a meghívott függvvénynek.
 
  • A main() ráhelyezi a foo() függvény visszatérési pointerét, vagyis azt, hogy a függvény lefutása után a foo() függvény a main()-en belül hova ugorjon vissza.

  • Ezután a main() függvény betölti foo() függvény paramétereit a stackbe fordított irányban (ez az ún. C-declaration order vagy cdecl).

  • Ezután következik a main() függvény stack frame pointerének helyzete, szintén rákerül a stackre.

  • A fenti adat memóriacíme tárolódik el a Stack Frame Pointerben (FRM regiszter). A pointernek több célja is van: egy részrõl meghatározza, hol kezdõdik az a stack szegmens, ahová a függvényünk (foo()) a helyi változóit fogja tárolni.
    Más részrõl be kell lássuk, hogy az STK (a stack tetejére / legalacsonyabb memóriacímére mutató pointer) nem megbízhatóan adja vissza a változók helyét, hiszen új változók felvétele esetén a stack is feljebb kerül az STK-val együtt. Ez a FRM elsõdleges használati területe: nevezetesen, hogy a függvényekben használt lokális változók létrehozásához a pontatlan STK helyett a függvény lefutása során kötött FRM-t használjuk.
    Mivel a stack memóriacímei csökkennek (lásd a memóriaképet), egy lokális változó (ami a mostani pointer fölött fog lenni) memóriacíme mindig a pointerhez képest negatív, míg a paraméterek értéke mindig pozitív lesz.
    Harmadrészrõl az FRM alatt lévõ memóriacím (tehát a main() függvény ugyanilyen framejére mutató pointer) megadni azt a területet, ahova a függvény lefutásakor vissza kell léptetni a STK-t (érvénytelenítve ezzel az összes lokális változót).

  • Ezután természetesen a függvény lefut, és minden lokális változó rákerül a stackre.


Minden stackre helyezett elem esetén természetesen frissítõdik a STK regiszter helye (ami a stack legfelsõ elemét mutatja).
Ha a függvény megáll, lefut a fenti ellentéte, a Standard Exit Sequence
 
  • A STK (stack tetejére / legalacsonyabb memóriacímére mutató pointer) értéke frissül a FRM értékére, megszûntetve ezzel a lokális változók elérésnek lehetõségét.

  • A FRM a mostani helyzete alatt található értékére frissül (ami pont a meghívó függvény ugyanolyan FRM értéke).

  • A main() függvény visszatérési pointerét leszedi a stackrõl és odaugrik, és folytatódik a kód végrehajtása.


Zárásnak még annyit: hogy azért is futnak a több-threades programok gyorsabban, mert mindegyiknek külön stackje van.


A heap és a stack, stack overflow
Lehetõség van arra, hogy a stack számára elõre lefoglalt memóriát túllépjük, és beleírjunk a heap-be: ez általában nagy mennyiségû változó esetén következik be, ezt nevezzük stack overflownak.
Ez azért lehetséges, mert a heap és a stack ugyanazt a memóriaterületet kapja, de ellentétes irányban kezdõdnek: a heap egyre növekvõ, míg a stack egyre csökkenõ memóriacímeket kap.
A stack overflow tényérõl a fordító tájékoztatást ad: mégpedig kiírja, hogy az egyes szegmensek mennyi bájtot foglalnak el, és hogy a HEAP/STACK szegmensnek mekkora a maximális mérete, és mekkora az a méret, amit igényelne ahhoz, hogy minden változó elférjen benne. Ez azért lehetséges, mivel a stack mérete a fordítás során már ismert. Jogosan felmerülhet a kérdés, hogy akkor miért nem kap az AMX automatikusan több memóriát a programhoz: ez a mennyiség limitált és alapjában véve nem túl nagy, tehát megeshet, hogy egy normálisabb módhoz is növelni kell. Ezt a #pragma dynamic direktívával lehet megtenni.


(és ennyi, frissítések várhatóak)

39
Fórum Archívum (Témák/Fórumok) / Re:Legális Hosting, Illegális Hosting?
« Dátum: 2013. Január 07. - 16:37:57 »
[mod]Inaktív topic. L&A.[/mod]

40
Általános / Központi Stat- vagy szerverrendszer
« Dátum: 2013. Január 02. - 17:06:27 »
Azon gondolkdotam, megérné-e csinálni egy központi statrendszert különbözõ típusú szerverekhez. Ez a következõképp zajlana: lenne egy központi web ahova be kéne regisztrálni, mint egy szeró UCPje. Lenne felhasználóneved, jelszavad. Bizonyos szerverek jelentkezhetnének a rendszerbe, akik kapnának egy API ID-t, és egy filterscriptet. Innentõl ha olyan szerveren, ahol ilyen rendszer van beépítve, olyan játékos játszik, akinek a rendszerre van accja, a statjait automatikusan követné és frissítené. A banokat is tárolná és az egész hálózatra érvényesítené, stb.
Persze ebben erõsen bent van az exploit lehetõsége, ezért minden szerver gondosan meg lenne válogatva, és külsõ kapcsolat le lenne tiltva az egyéb szervereknek. A statok esetén a szerverek súlyozva lennének, valamint a tulajok maguk dönthetik el, hogy a ban listát használják-e az õ szerverükön, valamint minden funkciót a szerverek egyesével beállíthatnának, és ezek egy listán látszódnának is.
A kérdés az lenne, hogy szerintetek egy ilyen rendszert érdemes lenne-e megscriptelni, és milyen mûfajon belül lenne értelme?

41
BEVEZETÉS
Mostanában a SAMP fórumon nagyon fellendült a gépi kód alacsony szintû programozása. Mivel egy ideje én is foglalkozok ezzel, és a DeAMX mûködése a kezdõ scriptereknek rejtély, ezért írtam meg a tutorialt. A tutorial, hiszen kezdõknek készült, koránt sem teljes és nem feladata a megfelelõ szaknyelv használata.
Remélem, aki PAWN-ban scriptel, az tisztába van azzal, hogy a PAWN, mint olyan, egy programozási nyelv. Az általunk kifejezett utasításokat gépi kódokká alakítja. Míg az emberek a szöveges nyelvet egyszerûbben, és hatékonyabban tudják kezelni, a gépek a számokat preferálják. Ezt nevezzük gépi kódnak.
Ellentétben a közhiedelemmel, a gépi kód nem teljesen értelmetlen zagyvaság, hiszen akkor a számítógép se értené meg. Ellenben igen nehéz olvasnia egy ismeretekkel nem rendelkezõ felhasználónak. Ahhoz, hogy megértsük a problémát, tudnunk kell, mit nevezünk magas és alacsony szintû programnyelveknek. A magas szintû programnyelvek az emberek számára érthetõbbek, jobban programozhatóak, viszont a fordításuk erõforrásigényesebb, a program futása az alsóbb rétegek miatt általában lassabb. Az alacsonyabb szintû nyelvek az ember számára kevésbbé érthetõbbek, viszont gépi kóddá elõbb fordítódnak (hiszen közelebb állnak hozzájuk), és gyorsabbak.
A PAWN, mint olyan, egy magas szintû nyelv, az ember számára könnyen olvasható, és megérthetõ.
 

   new var = 15;
   while (var > 0)
   {
      var = var - 1;
   }

 
A fenti scriptet, ha lefordítjuk, egy futtatható fájlt kapunk (AMX). Az AMX gépi kód, ezért megértése lehetetlen, ha nem ismerjük a felépítését. Ebben segít nekünk az ún. assembly nyelv. Az assembly a legalacsonyabb szintû programozási nyelv: a gépi kód felett állva az egyik legbonyorultabb, de leggyorsabban forduló és a gép számára legésszerûbb nyelv.
A PAWN fordító -a kapcsolójával az AMX helyett ASM (assembler) kódot kapunk. Ha valakit érdekel, nyisson egy parancssort rendszergazdaként, navigáljon el a pawno mappájába, majd üsse be a pawncc fájlnév -a parancsot, ahol a fájlnév értelemszerûen a kódunk neve. Ne feledjük, hogy az assembly minden architektúrán változik, az AMX-nek (ami egy absztrakt gép, tehát egy szimulált számítógép) más fajta assemblyje van, mint egy x86-os processzornak. Ha a gépi kódot szeretnétek megtekinteni változatlanul, dobjatok egy #pragma compress 0-t a módban, és a tiszta kódot kapjátok meg a hex editorban. Én is így csináltam a gépi kódokhoz a példákat.
A fenti PAWN kód így néz ki az AMX assemblyjében:
 

break
push.c f
break
l.0   
break
load.s.pri fffffffc
move.alt
zero.pri
jsgeq 1
break
load.s.pri fffffffc
add.c -1
stor.s.pri fffffffc
jump 0
l.1

 
És miért mondjuk azt, hogy a gépi kódhoz a legközelebb áll? Egészen egyszerûen azért, mert minden egyes utasítás a gépi kódban megfelel egy két hexadecimális számból álló opkódnak, az utánna álló paraméterek pedig az opkód után álló hexadecimális számoknak.
 

89 00 00 00 |           // break

 


27 00 00 00 | 0F 00 00 00 // push.c f

 
Látszódik a fenti két kódrészletbõl, hogy az assemblybõl gépi kódot képezni nem éppen komoly munka. Az utasítást az elsõ négy, míg a paramétereket az utolsó négy bájtban tárolja el. Még ha az utasítás (vagy szebben fogalmazva opkód) csak 1 bájtot (0x00 - 0xFF) foglal el, a maradék három bájtot a kötelezõ formátum miatt nullákkal kell kitölteni. Az utasítás négy bájtja és a paraméterek négy bájtja közé húztam egy vonalat, ez az eredeti gépi kódban nincs ott. Látható hogy a break utasítás opkódja 89, a többi nulla csak a kötelezõ 4 bájt kitöltésére van.
Ugyanígy a második példánál a 27 a push.c opkódja, majd a 4 üres bájt a kötelezõ formátum miatt van. A paramétere 0F, a maradék három bájt a kötelezõ formátum miatt itt is zérus.
A VÁLTOZÓK MIZÉRIÁJA
Amennyiben valaki már próbált DeAMX-el kódot visszafejteni, rájöhetett, hogy nem éppen jönnek vissza a változónevek, helyette értelmetlen var0, var4, var16, és egyéb értékeket kap. A helyzet a következõ: a számítógépek nem szeretik a szöveget: bonyorultak, sok memóriát foglalnak, lassítják a kódot, az embereknek viszont jobban megjegyezhetõ, mint egy rakat hexadecimális szám. Viszont a PAWN kód nem arra van, hogy visszafejtsed.
 

load.s.pri fffffffc    03 00 00 00 FC FF FF FF
add.c -1               57 00 00 00 FF FF FF FF
stor.s.pri fffffffc    11 00 00 00 FC FF FF FF

 
A fenti kód betölti az 0xfffffffc memóriacím alól a változót, csökkenti az értékét eggyel, majd eltárolja az új értéket a memóriacímben. Mellé írtam a gépi kód azon részét, ahol ez lejátszódik. Láthatjuk, hogy a load.s.pri opkódja a 03, követi három üres bájt, majd az FC FF FF FF felel meg a 0xFFFFFFFC-nek. A gépi kódoknál a hexadecimális számok bájtonkénti fordított sorrendben kerülnek be a listára (lásd Anthony kommentjét). Tehát egy ABCDEF12 hexadecimális szám mint 12 EF CD AB kerül bele a gépi kódba. Ezt hívjuk programozási szaknyelven kis endiánnak.
A második sorban látjuk, hogy az add.c opkódja 57, követi három üres bájt, majd a -1 signed integer hexadecimális megfelelõje: 0xFFFFFFFF. Arról, hogy ez hogyan lesz végül is, ha valaki tájékozódni akar, javaslom Anthony tutorialját a bináris mûveletekrõl.
Végül a módosult értéket ugyanabba a memóriacímbe elraktározzuk.
A lényeg, hogy a fenti kód hasonlít ehhez. Mert hogy pont ugyanaz a kettõ:
 

var = var - 1;

 
És akkor mégis mi az a 0xfffffffc, és miért ez, nem \"var\"?
MEMÓRIACÍMEK, MEMÓRIA LEFOGLALÁSA
Arról már volt szó, hogy a számítógép nem szereti a szöveget, és a PAWN nem arra lett tervezve, hogy visszafejtsék. Ezért eldobja azt, ami nem kell. Vegyük példának az alábbi kódot:
 
new var1;
new var2;
new var3;
new var4;

 
Ezt a DeAMX a következõképpen adja vissza:
 

new var12;
new var8;
new var4;
new var0;

 
Az assembly kódba ugyan nem került bele a három változó, hiszen sosem lettek használva, de kommentekben megtalálhatjuk a nyomát:
 

;$lcl var1 fffffffc
;$lcl var2 fffffff8
;$lcl var3 fffffff4
;$lcl var4 fffffff0

 
Láthatjuk, hogy mind a három változó pontosan 4 bájtot (1 cellát/2 szót) foglal el, hiszen a memóriacímek négyesével növekednek (0, 4, 8, C, 10, 14, 18, 1C, 20, ...).
Ez azért van, mivel a korábbi példákból észrevehetjük, hogy a változó korábbi regiszterbe való betöltésekor és módosításakor is egészen pontosan 4 bájtba kellett beírnunk a szám értékét, levonhatjuk tehát a következtetést, hogy a PAWN integer alapból 32 bit = 4 bájt hosszú. Ez azért van, mivel a PAWN-ban minden alapból 1 cella hosszú (ami elméletileg megegyezne a processzorod architektúrájával, a SAMP azonban csak 32 bit hosszú cellákat használ). Minden adattípus a PAWN-ban maximum 4 bájt hosszú.
Ezt próbálja meg a DeAMX ábrázolni, mikor a változónknak var0, var4, var8, var12, var16... neveket ad. A konkrét számok, és a látszólagos fordított kiosztásuk oka a relatív memóriacímekben rejlik, mégpedig abban, hogy az. ún stack memóriacímei, ahol a függvények lokális változói tárolódnak, lentrõl felfele kerülnek kiosztásra: ezekrõl kissé bõvebben az AMX és memóriaképe c. tutorial foglalkozik.
Ugyanez a helyzet a függvényekkel: memóriacímek alapján azonosítják õket. Az egyetlen kivétel az eljárások esete (callback), melyeknek a helyzete elõre nem tudható, ezért a függvény neve és a függvényre mutató pointer tárolódik el a scriptben.
TAGEK
Miért van az, hogy a
 

new Float:var = 5.7;

 
változó ez lesz fordítás után:
 

new var0 = 1085695590;

 
?
A megoldás itt is egyszerû: a tagek csak a fordító számára érdekesek, a gépi kódnak nem. A tagek csak a fordító számára fontosak, hogy egyféle mûveletet különbözõ adatokkal különbözõképpen használjon. Miután a fordítás megtörtént az adatok rögzítõdnek az IEEE 754 szabványnak megfelelõen (egy szabvány ami leírja a lebegõpontos számok bináris ábrázolását). Mikor a DeAMX visszafejti a kódot, mivel mind a lebegõpontos számok, mind az integerek ugyanúgy tárolódnak, nem tudja, hogy az adott cím alatt integer, vagy float van, ezért integerré alakítja.
A szabvány felépítését nem fogom részletezni, mivel egyrészt bonyorult, másrészt érdektelen a tutoriallal kapcsolatban. Ha valakit nagyon érdekel, keressen rá az interneten a szabványra.
ANTI-DEAMX
Végül egy gyors mondat az anti-deamx-rõl: ezek mindegyike a compiler hibáját használja ki, egyik sem hivatalos, és ha a SAMP-hoz új compiler jönne ki, akkor egyik se érne sokat.
A loopos példa Y_Less tutorialjából van. Észrevételeket szívesen látok.

42
Fórum Archívum (Témák/Fórumok) / krisk
« Dátum: 2012. December 18. - 21:05:16 »
Nem vagyok a bemutatkozások híve, nem is nagyon tudok mit magamról mondani, de mivel sok ember írt ilyet, és még nekem nem volt, ezért most megírom.
A nevem titok. Veszprém megyében lakom de életvitelszerûen Székesfehérváron élek. A személyes életemet nem szeretném itt megosztani, mert az nem egy internetes fórum témája, de: a jobb szememre születésem óta súlyos tompalátó vagyok, ez abban realizálódik, hogy 20 centinél távolabb egyáltalán nem látok; azon kívül, hogy nem tudok 3D filmeket nézni, eddig nem akadályozott semmiben (a 3d film amúgy is basszná a szemem, ahogy az alacsony FPS-û játékok is).
SAMP-ozni már 0.1 óta elkezdtem, de rendszeresen a 0.2x megjelenése óta játszom. Szinte az egész pályafutásom alatt csak RP szervereken játszottam: a Fay-on kezdtem, ott egy ideig az új modjukat is írtam, aztán LT, aztán Paradise, aztán Core, aztán Foothills, meg pár saját projekt (w0llfram). Az én véleményem a SAMP RP-vel kapcsolatban az, hogy az egyes asztali RPG elemeket (olyanokat, mint karakterlap vagy élettörténet) csak módjával lenne szabad egy normális modba berakni, a játékosoknak kéne tudniuk eljátszani a szerepüket mindenféle szabályzat nélkül. Ennek látszólag ellentmondhat a tény, hogy én magam is írtam egy asztali RP-jellegû modot, de az nem titkoltan arra szolgált, hogy azok, akik ezt kívánják, megkaphatják.
A SAMP fórumos karrieremet valamikor 2010 környékén kezdtem. 2013 januárjában kaptam elõször lokális moderátor rangot a Szerverek alfórumba (miután megpályáztam azt), majd Csabi kinevezett lokális moderátornak a Beszélgetések alfórumba. 2013 július elsejétõl pedig mint Globális Moderátor vagyok jelen.
Hobbijaim:
 
  • elsõdleges hobbim a programozás, a végsõ célom hogy x86 Assemblyben egy középfokon tudjak programozni; kicsit ehhez köthetõ a különbözõ játékok hackelése (fõleg NES játékok), valamint különbözõ játékok modolása. PAWN-ban elég jól tudok már programozni, írtam is pár leírást (például a SAMP fórum elsõ teljes PAWN tutorialját), illetve tervezek is írni a PAWN mélyebb részeirõl

  • az angol nyelv, az angol és amerikai irodalom, valamint az amerikai történelem és kultúra. Sikerült 2013 áprilisában letennem a CAE (Cambridge English: Advanced) nyelvvizsgát, A jeggyel (CEFR C2)
    Kedvenc angol íróim közé tartoznak George Orwell (különösen az 1984), Herman Melville és P.G. Wodehouse. Aki jobban tud angolul és fogékony a klasszikus irodalomra, annak melegen ajánlom Homérosz, Vergilius, és Platón (különösen a Szókratész védõbeszéde) próza verzióit (a verses verziókban a magyar aláz) prózában, sokkal jobban olvashatók angolul (szerintem)

  • repülés, IVAOn, VATSIMen irányítás

  • írás (mint magyarul, mint angolul)

  • félrefordítások gyûjtése

  • különbözõ linux rendszerek karbantartása (a régi általánosba még mindig sokszor bejárok ezügyben)

  • diákpolitika (iskolai DÖK)


Kedvenc játékaim: a kedvenc sorozatom messze a GTA sorozat, ezen felül bizonyos régifajta szöveges kalandjátékok/RPG-k (pl. MUD), a Quantic Dreams játékai (Heavy Rain, Indigo Prophecy), Battlefield sorozat.
Van már egy elég hosszan elhúzódó projektem, hogy elkezdek egy szövegalapú RPG-szerûséget írni, de még nem szántam rá magam, hogy elkezdjem.
Mostanában a Malibun játszok, az mellett pedig LSRP-n ismét jelentkeztem rendõrségre (olyan március környékén ki**sztak inaktivítás miatt).
Kedvenc zenéim: sok van, általában fõleg rock-metal vonalon mozgok, de hallgatok countryt és raget is (fõleg Joplint). Nem vetek meg semmilyen fajta zenét sem, ha tetszik, hallgatom.
Ide kéne írjak listát, hogy kiket ismerek, kikkel vagyok jóba, és a többi, de inkább kihagyom, aki tudja, az úgyis tudja.

43
A FÜGGVÉNY
A tickcount egy olyan függvény, ami a rendszer elindulása óta eltelt idõvel tér vissza ezredmásodpercekkel.
tickcount(&granularity=0)
&granularity: a visszatérés alkalmával ez az érték adja meg az egy másodpercben lévõ \"tick\"-ek számát. Az UNIX rendszerek esetén ez \"100\", vagyis az érték csak minden 10. ezredmásodpercben frissül. Mivel a függvény így is-úgy is ezredmásodpercekkel tér vissza, ez az érték csak a pontosság ellenõrzésére használható.
A ROSSZ PÉLDA
Rengeteg RP scriptben láttam (sõt, sokáig én magam is ezt csináltam), hogy amikor egy cselekvést minden x másodpercre akartak korlátozni, a cselekvés végrehajtása után az elõzõleg deklarált bool változónak hamis értéket adtak, majd elindítottak egy x másodperces timert, melynek lefutása után az érték ismét igaz lett.
Vegyük példának az alábbi kódot:
 
new bool:JatekosMegteheti[playerid] = true; // ez az a változó, ami meghatározza, hogy a játékos (már) használhatja-e (újra) a cselekvést.
MagaACselekvés(playerid) { // ez a függvény maga a cselekvés, amit a játékos csak adott idõközönként tehet meg. Lehet parancs, pickup felvétele, akármi egyéb
   if(JatekosMegteheti[playerid]) { // amennyiben a játékos használhatja a cselekvést...
      // ide jön maga az eredmény
      JatekosMegteheti[playerid] = false; // beállítjuk a változót hamisra, így mostmár nem teheti meg.
      SetTimerEx(\"Engedelyez\", 10000, false, \"d\", playerid); // elindítunk egy timert, ami 10 másodperc múlva lefut.
      return 1;
  } else { // amennyiben a játékos nem használhatja...
      SendClientMessage(playerid, -1, \"Ezt a cselekvést még nem ismételheted újra!\"); // kiírjuk, hogy nem használhatja a cselekvést még (várnia kell a timer lefutására)
    return 0;
  }
}
public Engedelyez(playerid) { //ha letelt a 10 másodperc
    JatekosMegteheti[playerid] = true; //a játékosnak újra megengedjük, hogy használja a cselekvését
}

 
Az alábbi kód a MagaACselekvés függvényt korlátozta le: amennyiben valaki lefuttatja a függvényt, a tömbben, ami tárolja a cselekvés végrehajthatóságát (JatekosMegteheti), át lesz állítva az érték hamisra, majd a 10 másodperces timer visszaállítja igazra. A két cselekvés közt nem használható a függvény.
A JÓ PÉLDA
A tickcount() függvény segítségével ezt a kódot egyszerûbbé tehetjük. Ha a függvényt kétszer meghívjuk, és kivonjuk az utóbbit az elõbbibõl, máris kapunk egy intervallumot a két idõpont közt.
 
new UtolsoEngedelyezes[MAX_PLAYERS]; //ebben fogjuk tárolni az utolsó engedélyezés tickcountját
MagaACselekvés(playerid) { // ez a függvény maga a cselekvés, amit a játékos csak adott idõközönként tehet meg. Lehet parancs, pickup felvétele, akármi egyéb
    if(tickcount() - UtolsoEngedelyezes[playerid] > 10000) { //Ez az ág akkor fut le, ha a jelenlegi tickcount és az utolsó ellenõrzés tickcountjának különbsége nagyobb mint 10000. Vagyis a két mérés között több, mint 10 másodperc telt el.
     //Ide jön a cselekvés
     UtolsoEngedelyezes[playerid] = tickcount(); // Frissítjük a változót a legfrissebb értékkel.
     return 1;
   } else { // ha nem telt el még 10 másodperc
      SendClientMessage(playerid, -1, \"Ezt a cselekvést még nem ismételheted újra!\");
      return 0;
  }
}

 
TICKCOUNT(), MINT IDÕMÉRÕ
A fenti függvényt akár idõmérõként is használhatjuk. Ha egy cselekvés elején (pl. egy verseny rajtján) beleírjuk egy változóba, majd a végén az aktuális értékbõl kivonjuk az eredetit,  megkaphatjuk, hogy a cselekvés mennyi idõbe tellett.
 

new VersenyKezdeteIdo[playerid];
VersenyKezdete(playerid) {
   VersenyKezdeteIdo[playerid] = tickcount();
   // elkezdõdött a verseny
}
VersenyVege(playerid) {
  // végetért a verseny
  new versenyido = tickcount() - VersenyKezdeteIdo[playerid];
  new str[100];
  format(str, 128, \"A versenyt %i ezredmásodperc alatt teljesítetted.\", versenyido);
  SendClientMessage(playerid, -1, str);
}

 
Az ezredmásodperceket pedig már különbözõ scriptek segítségével percekbe vagy órákba konvertálhatjuk.
A HÁTRAMARADT IDÕ LEKÉRDEZÉSE
Mintegy befejezésként tekintsük meg a \"jó példa\" változói alapján, hogy hogy kérhetjük le, az adott cselekvés hány ezredmásodperc múlva lesz végrehajtható:
 
new mennyiido = 10000 - (tickcount() - UtolsoEngedelyezes[playerid])

 
Ahol a 10000 a cselekvések közti minimális szünet mennyisége.
Ez a leírás még koránt sem teljes, javítások és bõvítések várhatóak
EDIT: ADATBÁZISBAN ELTÁROLANDÓ ADATOK
Ha ugyenzt a tickcountos mókát az adatbázisodban is akarod használni, akkor egy új, hasonló idõmérõ függvényt kell bevezetni, ez pedig a gettime().
A gettime() egy unix timestamp függvény, azaz az 1970-01-01 00:00:00Z óta eltelt másodpercekkel tér vissza.
A mûködési elve hasonló a fentiekben bemutatottakhoz, azzal a nagy különbséggel, hogy mivel adatbázisban tároljuk, ezért a szerver futásidejével visszatérõ függvény nyilván nem jó erre a célra.

44
Játékok / IF projekt
« Dátum: 2012. November 01. - 17:06:24 »
Üdv!
Már elképesztõen hosszú ideje tervezgetem egy saját játék készítését, de mivel a grafikai munkálatokhoz nekem sem idõm, sem energiám, sem türelmem nincsen, ezért egy ideig halogattam, és fõleg GTA:SA-ban alkottam sok kicsi, meg nem jelenõ single-jellegû projektet. Aztán a MUD 1-rõl, az egyik legjobb RPG-rõl jutott eszembe, hogy ezt meg lehet csinálni grafika nélkül is. Ezt is halogattam egy csomó ideig, aztán egy személyes esemény közeledte miatt úgy gondoltam, itt az ideje ebbe is belevágni. A múlt héten megbarátkoztam az ADRIFT nevû IF (interaktív fikció)-készítõ programmal, és nekiállok a játéknak, vagy inkább egy Heavy Rain-szerû interaktív könyvnek (nem összetévesztendõ a \"lapozós\" RPG-vel, de hasonló, csak itt tényleg interakcióba léphetsz a dolgokkal, nem csak két lehetõség közül választhatsz). A genre egyik alapvetõ alapelve, hogy nem halhatsz meg, ezért a játéknak gyakorlatilag nincsen \"jó\" és \"rossz\", csak többféle befejezése.
Itt egy példa az interakció mélységére, és ez még semmi: ebben a szobában minden egyes tárgyat megvizsgálhatsz, megnézheted az ablakokat, kinyithatod és becsukhatod õket, a két órával az idõt is megtekintheted, a jegyzettömböt és a tollat magaddal viheted, berakhatod a szekrénybe, az ágy alá, a gardróbból kivett ruhákat felveheted, és a többi. És természetesen minden ilyen interakciót kb. 2 perc beállítani a szoftverben, a legtöbb idõt a szöveg megfogalmazása veszi el. Ezért ilyen f***a az IF interaktív könyvekre.
Mint ahogyan ezt írtam már korábban, ez elsõsorban egy személyes projekt, tehát nagy valószínûséggel nem fog megjelenni a közeljövõben, maximum egy demó verzió (és amúgy is angolul van az egész), de azért kíváncsi vagyok, hogy mit gondoltok az ilyen jellegû játékokról.

45
Pluginok és Programok / Nativechecker
« Dátum: 2012. Szeptember 22. - 08:10:33 »
Nem tudom, ismeritek-e, de én most, miután a pluginokat végigböngésztem, találtam rá. A nativechecker egy nagyon egyszerû plugin, de roppant hasznos: lényege, hogy az idegesítõ \"File or function is not found\" hiba helyett konkrétan elmondja, hogy mi, hol hiányzik.
Windows:
http://solidfiles.com/d/5c0a/
Linux:
http://solidfiles.com/d/0c45/
Source:
http://solidfiles.com/d/8433/
Készítette: wyu.

Oldalak: 1 2 [3] 4 5 ... 7
SimplePortal 2.3.7 © 2008-2024, SimplePortal