HU/Debugging: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
mNo edit summary
 
(31 intermediate revisions by one other user not shown)
Line 2: Line 2:


==Hibakereső konzol==
==Hibakereső konzol==
Az MTA tartalmaz egy beépített hibakereső konzolt, mely a scriptekből, vagy az MTA-ból származő hibákat jelenítni meg. Vegye figyelembe, hogy Admin hozzáféréssel kell, hogy rendelkezzen (hacsak nem módosítja ezt az ACL-ben), megnyithatja a hibakereső konzolt a ''debugscript *x*'' beírásával, ahol az x a hibakeresési szintet jelöli:
Az MTA tartalmaz egy beépített hibakereső konzolt, mely a scriptekből, vagy az MTA-ból származó hibákat jeleníti meg. Vegye figyelembe, hogy Admin hozzáféréssel kell, hogy rendelkezzen (hacsak nem módosítja ezt az ACL-ben), megnyithatja a hibakereső konzolt a ''debugscript *x*'' beírásával, ahol az x a hibakeresési szintet jelöli:
* '''1:''' csak hibákat  
* '''1:''' csak hibákat  
* '''2:''' hibákat és figyelmeztetéseket  
* '''2:''' hibákat és figyelmeztetéseket  
Line 9: Line 9:


===Példa===
===Példa===
Ebben a kódban elrejtettünk két darab hibát:
Ez a példa tartalmaz két hibát:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function SayHello(message, player)
function SayHello(message, player)
Line 20: Line 20:
Ha ezt a kódot lefuttatjuk akkor ezt a hibaüzenetet fogjuk kapni:
Ha ezt a kódot lefuttatjuk akkor ezt a hibaüzenetet fogjuk kapni:
:{{Debug info|Loading script failed: myResource\script.lua:2: 'then' expected near ´outputChatbox'}}
:{{Debug info|Loading script failed: myResource\script.lua:2: 'then' expected near ´outputChatbox'}}
Ez azt jelenti, hogy a scriptet nem lehet elemezni, mert szintaktikai hiba volt benne. Ez megmutatja a script elérési útját a resource könyvtárból, így azonosítani tudja azt a scriptet, ahonnan a hiba származik. A fájlnév után egy kettőspontot és egy számot jelenít meg, ez a szám azt a sorszámot jeleníti meg, ahol megtalálhatja hol van a hiba a script-ben. Azután pedig a hibaüzenet, mely a létrejövő hibától függően változik. Ha megnézzük a hibaüzenetet, akkor könnyen megállapíthatjuk, hogy a biba a '''myResource''' könyvtárból származik, és a '''script.lua''' fájljának a második sorából. A hibaüzenet tisztán mutatja, hogy elfelejtettük a "then"-t! De ezt könnyedén kijavíthatjuk!
Ez azt jelenti, hogy a scriptet nem lehet elemezni, mert szintaktikai hiba volt benne. Ez megmutatja a script elérési útját a resource könyvtárból, így azonosítani tudja azt a scriptet, ahonnan a hiba származik. A fájlnév után egy kettőspontot és egy számot jelenít meg, ez a szám azt a sorszámot jeleníti meg, ahol megtalálhatja hol van a hiba a script-ben. Azután pedig a hibaüzenet, mely a létrejövő hibától függően változik. Ha megnézzük a hibaüzenetet, akkor könnyen megállapíthatjuk, hogy a hiba a '''myResource''' könyvtárból származik, és a '''script.lua''' fájljának a második sorából. A hibaüzenet tisztán mutatja, hogy elfelejtettük a "then"-t! De ezt könnyedén kijavíthatjuk!
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function SayHello(message, player)
function SayHello(message, player)
Line 29: Line 29:
addEventHandler("onChatMessage", root, SayHello)
addEventHandler("onChatMessage", root, SayHello)
</syntaxhighlight>
</syntaxhighlight>
Most a script szépen be fog töltődni és semmilyen hibaüzenetet nem fog visszaadni mindaddig, míg egy 'Fedor' nevű játékos nem ír ki valamit a chat-ba, ebben a pillanatban a hibakereső konzól ezt fogja kiírni:
Most a script szépen be fog töltődni és semmilyen hibaüzenetet nem fog visszaadni mindaddig, míg egy 'Fedor' nevű játékos nem ír ki valamit a chat-ba, ebben a pillanatban a hibakereső konzól ezt fogja visszaadni:
:{{Debug error|myResource\script.lua:2: attempt to call global 'outputChatbox' (a nil value)}}
:{{Debug error|myResource\script.lua:2: attempt to call global 'outputChatbox' (a nil value)}}
Ez az error azt jelenti, hogy a '''outputChatbox''' egy nil érték, az-az, nem létezik. Ez azért van, mert a funkciót [[outputChatBox]]-nak hivják, és nem [[outputChatbox]]-nak. Figyeljen a nagy 'B' betűre:
Ez az error azt jelenti, hogy az '''outputChatbox''' egy nil érték, az-az, nem létezik. Ez azért van, mert a funkciót [[outputChatBox]]-nak hivják, és nem [[outputChatbox]]-nak. Figyeljen a nagy 'B' betűre:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function SayHello(message, player)
function SayHello(message, player)
     if (getPlayerName(player) == "Józsika") then
     if (getPlayerName(player) == "Fedor") then
         outputChatBox("Szia Józsika")
         outputChatBox("Hello Fedor")
     end
     end
end
end
Line 45: Line 45:
==Szerver & Cliens hibakeresési napló==
==Szerver & Cliens hibakeresési napló==
====Szerver====
====Szerver====
Menj be a: ''(MTA mappa)>server>mods>deathmatch'' mappába
Menjen a: ''(MTA mappa)>server>mods>deathmatch'' mappába


Van itt két majdnem azonos fájl.
Van itt két majdnem azonos fájl.


* A local.conf a beállításokat tartalmazza a „host játék” menüpont beállításait a főmenübe. Ez egy gyors módja a szerver indításának. Ha a host lecsatlakozik akkor a szerver is kikapcsol!
* A local.conf fájl a "host game" menü item-re vonatkozó beállításokat tartalmazza, mely az MTA főmenüjében van. Ez egy gyors és egyszerű módja az ideiglenes szerver indításának a client oldaláról. Ha a client (host) leáll, akkor a server is leáll.
*A mtaserver.conf akkor használjuk, amikor „MTA SERVER.EXE” fájlal indítjuk a  szervert!(MTA mappája)> server. Ez a saját szerver  konzol, szóval ha a host lecsatlakozik akkor nem kapcsol le. Ez akkor lehet hasznos, ha érdekel a szerver hosting hosszabb ideig.
*Az mtaserver.conf akkor van használatban, amikor az "MTA Server.exe" végrehajtódott az (MTA fő mappa)>server-ből. Ez futtatja a szervert a saját konzolablakában, mely nem igényli a client meglétét vagy futtatását. Ez akkor lehet hasznos, ha hosszabb időre szeretne szervert futtatni.


Itt be lehet állítani a logok mentési helyét!
Attól függen, hogy milyen módon futtat, aszerint kell szerkeszteni ezeket a fájlokat. A kérdéses beállítások a következők:


<syntaxhighlight lang="xml"><!-- Itt beírhatja a log helyét! Ha üresen hagyod akkor a szerver megspórolja a helyet! -->
<syntaxhighlight lang="xml"><!-- Megadhatja a debugscript log fájl helyét és nevét. Ha üresen hagyja, akkor a server nem fogja elmenteni ezt a fájlt -->
<scriptdebuglogfile>logs/scripts.log</scriptdebuglogfile>  
<scriptdebuglogfile>logs/scripts.log</scriptdebuglogfile>  
<!-- Itt lehet beállítani a debug szintjét! Lehetséges értékek: 0, 1, 2, 3. Ha nincs beállítva, akkor automatikusan 0.  -->
<!-- Megadhatja a log fájl debug szintjét! Lehetséges értékek: 0, 1, 2, 3. Ha nincs beállítva, akkor automatikusan 0.  -->
<scriptdebugloglevel>0</scriptdebugloglevel></syntaxhighlight>
<scriptdebugloglevel>0</scriptdebugloglevel></syntaxhighlight>


Te biztos akarsz lenni hogy van egy file a megadott néven. Meg tudod határozni, hogy milyen szintű hibák kerüljene knaplózásra. Ha ez 0 akkor semmi nem lesz rögzítve. A szintek magyarázata a cikk tetején található. Ha a naplózási szint megváltozott 3-ra, akkor ebben az esetben minden „” „szerveroldalon” „” lévő szkripthibákat elnaplóz.
Bizonyosodjon meg arról, hogy megvan-e adva a log név. Azt is meg tudja határozni, hogy a hibák melyik szintje legyen naplózva. Ha ez 0, akkor semmi nem lesz naplózva. A szintek magyarázata a cikk tetején található. Ha a naplózási szint megváltozott 3-ra, akkor ebben az esetben minden szerver oldali script hibát a (MTA mappa)>server>mods>deathmatch>logs>scripts.log fájlba fogja naplózni.
(MTA mappa)>server>mods>deathmatch>logs>scripts.log


====Kliens====
====Kliens====
Menj a: ''(MTA mappa)>server>clientscript.log''
Menjen a: ''(MTA mappa)>server>clientscript.log''


Ez a file az összes '''kliensoldali''' szkript hibákat naplózza. Ő alapértelmezés szerint fent van, nincs szükség telepítésre!
Ez a file az összes '''kliensoldali''' script hibákat naplózza. Ez alapértelmezetten naplózásra van beállítva, nincs szükség beállításra.


==Hibakeresési stratégiák==
==Hibakeresési stratégiák==
Line 73: Line 72:
===Hasznos funkciók===
===Hasznos funkciók===
Vannak olyan funkciók, amelyek jól jöhetnek a hibakereséshez.
Vannak olyan funkciók, amelyek jól jöhetnek a hibakereséshez.
* [[outputDebugString]] vagy [[outputChatBox]] ([[outputDebugString]] a műszaki kimenet)
* [[outputDebugString]] vagy [[outputChatBox]] bármilyen információ kiírásához (használja az outputDebugString a technikai kiíráshoz)
* [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] Hasznos, ha az érték nem szám vagy string.
* [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] egy változó, amely az értéket egy string-re változtatja. Hasznos, ha az érték nem egy szám vagy egy string.
 
* [[inspect]] visszaad egy az ember számára olvasható stringet bármilyen adattípusról, beleértve a táblákat, nem elemi felhasználói adatokat, mint az ACL groupok, felhasználók, elemeke, stb.
* [[getElementType]] ellenőrizni, hogy milyen típusú az MTA elem.
* [[iprint]] hasonló az ellenőrzéshez, kivéve, hogy annyi paramétert vesz igénybe, amennyi szökséges, majd kiírja őket a debugscript-be.
* [[isElement]] ellenőrizni, hogy a MTA elem létezik.
* [[getElementType]] ellenőrzni az MTA elem típusát.
* [[isElement]] ellenőrzi, hogy az MTA elem létezik-e.


===Adjon meg debugmessage-t annak ellenőrzéséhez, hogy mikor, illetve milyen gyakran hajtja végre a kód egy részét===
===Adjon meg debugmessage-t annak ellenőrzéséhez, hogy mikor, illetve milyen gyakran hajtja végre a kód egy részét===
Line 96: Line 96:
createMarker(x,y,z)
createMarker(x,y,z)
</syntaxhighlight>
</syntaxhighlight>
This would output all three variables that are used as coordinates for the marker. Assuming you read those from a map file, you can now compare the debug output to the desired values. The [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] will ensure that the values of the variables can be concatenated (put together) as a string, even if it's a boolean value.
Ez mind a három változót kiírja, melyek a marker kordinátájaként lettek használva. Feltételezve, hogy kiolvassa ezeket a map fájlból, most már össze tudja hasonlítani a debug kiírást a kívánt értékekkel. A [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] gondoskodni fog arról, hogy a változók értékei összefűzhetőek legyenek stringként, még akkor is, ha ez egy logikai érték.


==Example==
==Példa==
Imagine you created a [[Colshape|collision shape]] somewhere and you want an action to perform after the player stays for ten seconds inside it, you would do this:
Képzelje el, hogy valahol létrehozott egy [[Colshape|collision shape]]-t, és szeretné, ha valami végrehajtódna miután a játékos tíz másodpercig benne marad:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function colShapeHit(player)
function colShapeHit(player)
Line 114: Line 114:
addEventHandler("onColShapeLeave", root, colShapeLeave)
addEventHandler("onColShapeLeave", root, colShapeLeave)
</syntaxhighlight>
</syntaxhighlight>
When a player enters the colshape, debugscript outputs the following message:
Amikor a játékos belép a colshape-be, a debugscript a következő üzenetet fogja kiírni:
:{{Debug error|..[path]: attempt to index global 'colshapeTimer' (a nil value)}}
:{{Debug error|..[path]: attempt to index global 'colshapeTimer' (a nil value)}}
This means you tried to index a table that does not exist (because the table is a nil value, it doesn't exist). In the example above, this is done when storing the timer id in the table. We need to add a check if the table exists and if it does not exist we should create it.
Ez azt jelenti, hogy megpróbált rámutatni egy olyan táblára, ami nem létezik (mert a tábla egy nil értékű, nem létezik). Ez akkor történik, amikor a timer id-jét a táblába akarja helyezi. Hozzá kell adnunk egy ellenőrzést, hogy a tábla létezik-e, és ha nem, akkor hozzon létre egyet.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 136: Line 136:
</syntaxhighlight>
</syntaxhighlight>


Now we will still receive a warning when a player enters the colshape, waits for the message and leaves it again:
Még mindig figyelmeztetést fogunk kapni, amikor a játékos belép a colshape-be, várjon az üzenetre, majd lépjen ki belőle (colshape-ből):


:{{Debug warning|[..]: Bad argument @ 'killTimer' Line: ..}}
:{{Debug warning|[..]: Bad argument @ 'killTimer' Line: ..}}


Except for that (we will talk about that later) everything seems to work fine. A player enters the colshape, the timer is started, if he stays the message occurs, if he leaves the timer is killed.
Ettől eltekintve (erről majd később beszélünk) minden jónak tűnik. A játékos belép a colshape-be, a timer elindul, ha ott marad az üzenet megjelenik, ha kilép, a timer megsemmisül.  


===A more inconspicuous error===
===Egy kevésbé észrevehető hiba===
But for some reason the message gets outputted twice when you stay in the colcircle while in a vehicle. Since it would appear some code is executed twice, we add debug messages to check this.
De valami oknál fogva az üzenet kétszer jelenik meg amikor a colkörben marad egy autóban ülve. Úgy tűnik, hogy valamennyi kód kétszer hajtódik végre, ezért debug üzenetet adunk hozzá, hogy ezt ellenőrizze.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 167: Line 167:
</syntaxhighlight>
</syntaxhighlight>


Now we notice that both handler functions get executed twice when we are in a vehicle, but only once when we are on-foot. It would appear the vehicle triggers the colshape as well. To confirm this theory, we ensure that the ''player'' variable actually holds a reference to a player element.
Most észre vesszük, hogy mindkét handler functions kétszer hajtódik végre, amikor egy járműben vagyunk, de csak egyszer, ha gyalogosok vagyunk. Úgy tűnik, hogy a jármű meghívja a colshape-t is. Az elmélet megerősítése érdekében biztosítjuk, hogy a ''player'' változó valójában egy játékoselemre hivatkozzon.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 191: Line 191:
</syntaxhighlight>
</syntaxhighlight>


The debug messages tell us that one of the ''player'' variables is a player and that the other one is a vehicle element. Since we only want to react when a player enters the colshape, we add an ''if'' that will end the execution of the function if it's '''not''' an player element.
A debug elmondja nekünk, hogy az egyik ''player'' változó az egy játékos, a másik pedig egy jármű elem. Mivel csak arra akarunk reagálni, ha egy játékos lép be a colshape-be, ezért hozzáadunk egy ''if''-et, mely megakadájozza, hogy a function lefusson, ha ez nem egy játékos elem.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 219: Line 219:
</syntaxhighlight>
</syntaxhighlight>


Now the script should work as desired, but it will still output the warning mentioned above. This happens because the timer we try to kill when a player leaves the colshape will not exist anymore when it has reached the 10 seconds (and therefore executed after the 10th second has completed). There are different ways to get rid of that warning (since you know that the timer might not exist anymore and you only want to kill it if it exists). One way would be to check if the timer referenced in the table really exists. To do this, we need to use [[isTimer]], which we will use when we kill the timer:
Most a scriptnek a kívánt módon kell működnie, de továbbra is kiírja a fent említett hibaüzenetet. Ez azért van, mert az időzítő, melyet ki akarunk kapcsolni mikor egy játékos elhagyja a colshape-et, már nem létezik mikor elérte a 10 másodpercet (és ezáltal lefutott a tizedik másodperc után). Különböző módokon tudunk megszabadulni ezektől a figyelmeztetésektől (mivel tudjunk, hogy a timer már nem létezik, és csak akkor akarjuk megsemmisíteni, ha létezik). Az egyik mód az, hogy ellenőrizzük, tényleg létezik-e a táblázatban szereplő timer. Ehhez használnunk kell az [[isTimer]]-t, amit akkor fogunk használni, amikor megsemmisítettük a timert:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
if (isTimer(colshapeTimer[player])) then
if (isTimer(colshapeTimer[player])) then
Line 226: Line 226:
</syntaxhighlight>
</syntaxhighlight>


So the complete working code would be:
Tehát a teljes működő kód így nézne ki:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function colShapeHit(player)
function colShapeHit(player)
Line 255: Line 255:
</syntaxhighlight>
</syntaxhighlight>


==Teljesítménybeli problémák elhárítása==


==Debugging Performance Issues==
Ha a szervere több erőforrást használ el, mint kelle, vagy csak azt szeretné, hogy a scriptjei hatékonyak legyenek, megtalálhatja a probléma forrását egy nagyszerű eszköz használatával, amely az alapértelmezett resource csomaggal együtt érkezik: [[Resource:Performancebrowser|performancebrowser]]. Elindíthatja  a  ''''start performancebrowser''''-el. Ha ez nem létezik, akkor letöltheti a legfrissebb resourcet a [https://github.com/multitheftauto/mtasa-resources GitHub repository]-ról. Ez az eszköz hihetetlen mennyiségű információt nyújt a teljesítménybeli hibakereséshez. Memória szivárgások, elem szivárgások, CPU igényes scriptek könnyedén megtalálhatóak a teljesítményböngészőn keresztül. Ha a ''''d'''' opciót használja a Lua időzítőben, akkor láthatja, hogy mely function-ök használja a CPU-t.
 
If your server is using up more resources than it should or you just want to make sure your scripts are efficient, you can find the source of the issue by using a great tool that comes with the default resource package called [[Resource:Performancebrowser|performancebrowser]]. You can start it with ''''start performancebrowser''''. If it doesn't exist then you can get the latest resources from the [https://github.com/multitheftauto/mtasa-resources GitHub repository]. This tool provides an incredible amount of information for performance debugging. Memory leaks, element leaks and CPU intensive scripts are all easily findable via performancebrowser. If you use the ''''d'''' option in Lua timing you can see which functions are using up the CPU.


To access performancebrowser you will need to go to your web browser and enter the address: http://serverIPHere:serverHTTPPortHere/performancebrowser/ Note that the / at the end is required. So for example: http://127.0.0.1:22005/performancebrowser/ You will then need to login with an in-game admin account or any account that has access to ''''resource.performancebrowser.http'''' and ''''resource.ajax.http''''. Most of the information you will need are in the categories Lua timing and Lua memory, look for values that are much higher than other values.
A teljesítményböngésző eléréséhez megkell nyitni a web böngészőt, és beírni a következő címet: http://serverIPHere:serverHTTPPortHere/performancebrowser/ Vegye figyelembe, hogy a vége az szükséges. Például: http://127.0.0.1:22005/performancebrowser/ Be kell jelentkeznie egy játékbeli admin felhasználóval, vagy egy olyan felhasználóval mely jogosult a ''''resource.performancebrowser.http'''' és ''''resource.ajax.http'''' belépéshez.  
A legtöbb szükséges információ a Lua időzítőben és a Lua memória kategóriákban található, olyan értékeket keressen, amelyek sokkal magasabbak, mint a többi érték.


===Examples of scripts that could cause performance problems===
===Példák olyan scriptekre, amelyek teljesítményproblémákat okozhatnak===


Adding data to a table but never removing it. This would take months/years before it causes a problem though.
Adatok hozzáadása egy táblához, de nem távolítja el sosem. Ez hónapokba/évekbe telhet, mielőtt problémákat okozna.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
local someData = {}
local someData = {}
Line 276: Line 276:
</syntaxhighlight>
</syntaxhighlight>


Element leaking is possible if you use temporary colshapes for whatever reason and may not destroy them. This would cause bandwidth, CPU and memory performance issues over time.
Az elem szivárgás lehetséges, ha ideiglenes colshape-eket használ, és nem távolítja el azokat. Ez idővel sávszélességi, CPU és memória teljesítménybeli problémákat okozhat.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function useTemporaryCol()
function useTemporaryCol()
Line 289: Line 289:
</syntaxhighlight>
</syntaxhighlight>


High CPU usage resulting in the server FPS dropping so much that the server is unplayable. In under 24 hours this can create havoc on a very busy server. The amount of "refs" in the Lua timing detect this type of build up, surprisingly the Lua timing tab didn't help in this case but Lua memory did.
Magas CPU igényes szerverek FPS dropokat eredményezhetnek, amitől a szerver játszhatatlanná válik. Ez egy forgalmas szerveren 24 órán belül nagy károkat okozhat. A "refs" mennyisége a Lua időzítőben felismeri az ilyen fajta scripteket, meglepő módon a Lua időzítő nem segített ebben az esetben, de a Lua memória igen.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
addEventHandler("onPlayerJoin", root, function()
addEventHandler("onPlayerJoin", root, function()
Line 300: Line 300:
</syntaxhighlight>
</syntaxhighlight>


A function uses up a lot of your CPU because whatever it does takes a long time. This is just some function that takes a long time to complete. Without performancebrowser you'd have no idea its the cause but with performancebrowser you can see that a resource is using lots of CPU in the Lua timing tab. If you then enter: ''''d'''' into the options edit box it will even tell you what file name and first line of the function that is using up so much CPU.
Egy function túl intenzíven használja a processzorját, mert bármit is csinál az sok időt vesz igénybe. Ez csak egy function, ami sok időt vesz igénybe a befejezéshez. Teljesítményböngésző nélkül nem tudná, hogy mi okozza, de a teljesítményböngészővel láthatja a Lua időzítőben, hogy a resource sok CPU-t használ. Ha beírja az Options mezőbe a ''''d''''-t, akkor még a fájl nevét is megmondja, és a function első vonalánál, hogy mennyi CPU-t használ.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function someDodgyCode()
function someDodgyCode()
Line 310: Line 310:


==Fordította==
==Fordította==
* Kevin
'''2018.11.05.''' <font size="3">'''[https://wiki.multitheftauto.com/wiki/User:Surge Surge]'''</font>
* Surge
 
'''2017.04.17.''' <font size="3">Kevin</font>


[[Category:Scripting Concepts]]
[[Category:Translated/Scripting Concepts]]
[[en:Debugging]]
[[en:Debugging]]
[[it:Guida al Debug]]
[[it:Guida al Debug]]

Latest revision as of 20:25, 21 February 2021

Scriptelés során gyakran találkozhat olyan hibákkal, amelyek nem azonnal nyilvánvalóak. Ez az oldal megpróbál rámutatni néhány alapvető stratégiára, hogy megtalálja a hibát.

Hibakereső konzol

Az MTA tartalmaz egy beépített hibakereső konzolt, mely a scriptekből, vagy az MTA-ból származó hibákat jeleníti meg. Vegye figyelembe, hogy Admin hozzáféréssel kell, hogy rendelkezzen (hacsak nem módosítja ezt az ACL-ben), megnyithatja a hibakereső konzolt a debugscript *x* beírásával, ahol az x a hibakeresési szintet jelöli:

  • 1: csak hibákat
  • 2: hibákat és figyelmeztetéseket
  • 3: hibákat, figyelmeztetéseket és információs üzeneteket

A debugscript 3 beírásával az összes üzenet látható. A 3-as és a 2-es szint a legtöbb helyzetben ajánlott. A debugscript-nek engedélyezettnek kell lennie, amikor teszteli a scriptjeit, ez segíteni fog, hogy könnyedén észrevegye és megoldja az esetleges gépelési hibákat, vagy más problémákat.

Példa

Ez a példa tartalmaz két hibát:

function SayHello(message, player)
    if (getPlayerName(player) == "Fedor")
        outputChatbox("Hello Fedor")
    end
end
addEventHandler("onChatMessage", root, SayHello)

Ha ezt a kódot lefuttatjuk akkor ezt a hibaüzenetet fogjuk kapni:

INFO: Loading script failed: myResource\script.lua:2: 'then' expected near ´outputChatbox'

Ez azt jelenti, hogy a scriptet nem lehet elemezni, mert szintaktikai hiba volt benne. Ez megmutatja a script elérési útját a resource könyvtárból, így azonosítani tudja azt a scriptet, ahonnan a hiba származik. A fájlnév után egy kettőspontot és egy számot jelenít meg, ez a szám azt a sorszámot jeleníti meg, ahol megtalálhatja hol van a hiba a script-ben. Azután pedig a hibaüzenet, mely a létrejövő hibától függően változik. Ha megnézzük a hibaüzenetet, akkor könnyen megállapíthatjuk, hogy a hiba a myResource könyvtárból származik, és a script.lua fájljának a második sorából. A hibaüzenet tisztán mutatja, hogy elfelejtettük a "then"-t! De ezt könnyedén kijavíthatjuk!

function SayHello(message, player)
    if (getPlayerName(player) == "Fedor") then
        outputChatbox("Hello Fedor")
    end
end
addEventHandler("onChatMessage", root, SayHello)

Most a script szépen be fog töltődni és semmilyen hibaüzenetet nem fog visszaadni mindaddig, míg egy 'Fedor' nevű játékos nem ír ki valamit a chat-ba, ebben a pillanatban a hibakereső konzól ezt fogja visszaadni:

ERROR: myResource\script.lua:2: attempt to call global 'outputChatbox' (a nil value)

Ez az error azt jelenti, hogy az outputChatbox egy nil érték, az-az, nem létezik. Ez azért van, mert a funkciót outputChatBox-nak hivják, és nem outputChatbox-nak. Figyeljen a nagy 'B' betűre:

function SayHello(message, player)
    if (getPlayerName(player) == "Fedor") then
        outputChatBox("Hello Fedor")
    end
end
addEventHandler("onChatMessage", root, SayHello)

Természetesen ez csak egy példa, és csak a hibaüzeneteknek a felszínét érintettem. Nagyon sok más üzenet és eshetőség létezik, de egy általános elképzelést kell kapnia.

Szerver & Cliens hibakeresési napló

Szerver

Menjen a: (MTA mappa)>server>mods>deathmatch mappába

Van itt két majdnem azonos fájl.

  • A local.conf fájl a "host game" menü item-re vonatkozó beállításokat tartalmazza, mely az MTA főmenüjében van. Ez egy gyors és egyszerű módja az ideiglenes szerver indításának a client oldaláról. Ha a client (host) leáll, akkor a server is leáll.
  • Az mtaserver.conf akkor van használatban, amikor az "MTA Server.exe" végrehajtódott az (MTA fő mappa)>server-ből. Ez futtatja a szervert a saját konzolablakában, mely nem igényli a client meglétét vagy futtatását. Ez akkor lehet hasznos, ha hosszabb időre szeretne szervert futtatni.

Attól függen, hogy milyen módon futtat, aszerint kell szerkeszteni ezeket a fájlokat. A kérdéses beállítások a következők:

<!-- Megadhatja a debugscript log fájl helyét és nevét. Ha üresen hagyja, akkor a server nem fogja elmenteni ezt a fájlt -->
	<scriptdebuglogfile>logs/scripts.log</scriptdebuglogfile> 
	
	<!-- Megadhatja a log fájl debug szintjét! Lehetséges értékek: 0, 1, 2, 3. Ha nincs beállítva, akkor automatikusan 0.  -->
	<scriptdebugloglevel>0</scriptdebugloglevel>

Bizonyosodjon meg arról, hogy megvan-e adva a log név. Azt is meg tudja határozni, hogy a hibák melyik szintje legyen naplózva. Ha ez 0, akkor semmi nem lesz naplózva. A szintek magyarázata a cikk tetején található. Ha a naplózási szint megváltozott 3-ra, akkor ebben az esetben minden szerver oldali script hibát a (MTA fő mappa)>server>mods>deathmatch>logs>scripts.log fájlba fogja naplózni.

Kliens

Menjen a: (MTA mappa)>server>clientscript.log

Ez a file az összes kliensoldali script hibákat naplózza. Ez alapértelmezetten naplózásra van beállítva, nincs szükség beállításra.

Hibakeresési stratégiák

Számos stratégia létezik, amelyek támogatják a hibakeresést. Legtöbbjük közé tartozik a kimenő Hibaüzenetek, a különböző információktól függően helyezkednek el.

Hasznos funkciók

Vannak olyan funkciók, amelyek jól jöhetnek a hibakereséshez.

  • outputDebugString vagy outputChatBox bármilyen információ kiírásához (használja az outputDebugString a technikai kiíráshoz)
  • tostring() egy változó, amely az értéket egy string-re változtatja. Hasznos, ha az érték nem egy szám vagy egy string.
  • inspect visszaad egy az ember számára olvasható stringet bármilyen adattípusról, beleértve a táblákat, nem elemi felhasználói adatokat, mint az ACL groupok, felhasználók, elemeke, stb.
  • iprint hasonló az ellenőrzéshez, kivéve, hogy annyi paramétert vesz igénybe, amennyi szökséges, majd kiírja őket a debugscript-be.
  • getElementType ellenőrzni az MTA elem típusát.
  • isElement ellenőrzi, hogy az MTA elem létezik-e.

Adjon meg debugmessage-t annak ellenőrzéséhez, hogy mikor, illetve milyen gyakran hajtja végre a kód egy részét

Egy tipikus példa igazolja, hogy az if-rész az végrehajtódott-e, vagy sem. Ehhez csak adjon hozzá egy olyan üzenetet, amit majd később fel fog ismerni az if -részben.

if (variable1 == variable2) then
    outputDebugString("variable1 is the same as variable2!")
    -- do anything
end

Egy másik használata a változó értékek módosításának ellenőrzése lenne. Először keresse meg a szerkeszteni kívánt változó összes előfordulását, majd addjon hozzá egy üzenetet.

Adjon hozzá debugmessage-t egy változó értékének ellenőrzéséhez

Tegyük fel, hogy létre szeretne hozni egy markert, de nem abban a pozícióban jelenik meg, mint amire számított. Az első dolog, amit érdemes lehet ellenőrizni, hogy a createMarker függvény lefutott-e. De amíg ezt használja, közben azokat az értékeket is tudja ellenőrizni, amik a createMarker funkcióban vannak használva.

outputChatBox("posX is: "..x.." posY is: "..y.." posZ is: "..z)
createMarker(x,y,z)

Ez mind a három változót kiírja, melyek a marker kordinátájaként lettek használva. Feltételezve, hogy kiolvassa ezeket a map fájlból, most már össze tudja hasonlítani a debug kiírást a kívánt értékekkel. A tostring() gondoskodni fog arról, hogy a változók értékei összefűzhetőek legyenek stringként, még akkor is, ha ez egy logikai érték.

Példa

Képzelje el, hogy valahol létrehozott egy collision shape-t, és szeretné, ha valami végrehajtódna miután a játékos tíz másodpercig benne marad:

function colShapeHit(player)
	-- set a timer to output a message (could as well execute another function)
	-- store the timer id in a table, using the player as index
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit", root, colShapeHit)

function colShapeLeave(player)
	-- kill the timer when the player leaves the colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave", root, colShapeLeave)

Amikor a játékos belép a colshape-be, a debugscript a következő üzenetet fogja kiírni:

ERROR: ..[path]: attempt to index global 'colshapeTimer' (a nil value)

Ez azt jelenti, hogy megpróbált rámutatni egy olyan táblára, ami nem létezik (mert a tábla egy nil értékű, nem létezik). Ez akkor történik, amikor a timer id-jét a táblába akarja helyezi. Hozzá kell adnunk egy ellenőrzést, hogy a tábla létezik-e, és ha nem, akkor hozzon létre egyet.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- set a timer to output a message (could as well execute another function)
	-- store the timer id in a table, using the player as index
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit", root, colShapeHit)

function colShapeLeave(player)
	-- kill the timer when the player leaves the colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",root,colShapeLeave)

Még mindig figyelmeztetést fogunk kapni, amikor a játékos belép a colshape-be, várjon az üzenetre, majd lépjen ki belőle (colshape-ből):

WARNING: [..]: Bad argument @ 'killTimer' Line: ..

Ettől eltekintve (erről majd később beszélünk) minden jónak tűnik. A játékos belép a colshape-be, a timer elindul, ha ott marad az üzenet megjelenik, ha kilép, a timer megsemmisül.

Egy kevésbé észrevehető hiba

De valami oknál fogva az üzenet kétszer jelenik meg amikor a colkörben marad egy autóban ülve. Úgy tűnik, hogy valamennyi kód kétszer hajtódik végre, ezért debug üzenetet adunk hozzá, hogy ezt ellenőrizze.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- add a debug message
	outputDebugString("colShapeHit")
	-- set a timer to output a message (could as well execute another function)
	-- store the timer id in a table, using the player as index
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- add a debug message
	outputDebugString("colShapeLeave")
	-- kill the timer when the player leaves the colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Most észre vesszük, hogy mindkét handler functions kétszer hajtódik végre, amikor egy járműben vagyunk, de csak egyszer, ha gyalogosok vagyunk. Úgy tűnik, hogy a jármű meghívja a colshape-t is. Az elmélet megerősítése érdekében biztosítjuk, hogy a player változó valójában egy játékoselemre hivatkozzon.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- add a debug message, with the element type
	outputDebugString("colShapeHit "..getElementType(player))
	-- set a timer to output a message (could as well execute another function)
	-- store the timer id in a table, using the player as index
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- add a debug message, with the element type
	outputDebugString("colShapeLeave "..getElementType(player))
	-- kill the timer when the player leaves the colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

A debug elmondja nekünk, hogy az egyik player változó az egy játékos, a másik pedig egy jármű elem. Mivel csak arra akarunk reagálni, ha egy játékos lép be a colshape-be, ezért hozzáadunk egy if-et, mely megakadájozza, hogy a function lefusson, ha ez nem egy játékos elem.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- add a check for the element type
	if (getElementType(player) ~= "player") then return end
	-- add a debug message, with the element type
	outputDebugString("colShapeHit "..getElementType(player))
	-- set a timer to output a message (could as well execute another function)
	-- store the timer id in a table, using the player as index
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- add a check for the element type
	if (getElementType(player) ~= "player") then return end
	-- add a debug message, with the element type
	outputDebugString("colShapeLeave "..getElementType(player))
	-- kill the timer when the player leaves the colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Most a scriptnek a kívánt módon kell működnie, de továbbra is kiírja a fent említett hibaüzenetet. Ez azért van, mert az időzítő, melyet ki akarunk kapcsolni mikor egy játékos elhagyja a colshape-et, már nem létezik mikor elérte a 10 másodpercet (és ezáltal lefutott a tizedik másodperc után). Különböző módokon tudunk megszabadulni ezektől a figyelmeztetésektől (mivel tudjunk, hogy a timer már nem létezik, és csak akkor akarjuk megsemmisíteni, ha létezik). Az egyik mód az, hogy ellenőrizzük, tényleg létezik-e a táblázatban szereplő timer. Ehhez használnunk kell az isTimer-t, amit akkor fogunk használni, amikor megsemmisítettük a timert:

if (isTimer(colshapeTimer[player])) then
	killTimer(colshapeTimer[player])
end

Tehát a teljes működő kód így nézne ki:

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- add a check for the element type
	if (getElementType(player) ~= "player") then return end
	-- add a debug message, with the element type
	outputDebugString("colShapeHit "..getElementType(player))
	-- set a timer to output a message (could as well execute another function)
	-- store the timer id in a table, using the player as index
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- add a check for the element type
	if (getElementType(player) ~= "player") then return end
	-- add a debug message, with the element type
	outputDebugString("colShapeLeave "..getElementType(player))
	-- kill the timer when the player leaves the colshape
	if (isTimer(colshapeTimer[player])) then
		killTimer(colshapeTimer[player])
	end
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Teljesítménybeli problémák elhárítása

Ha a szervere több erőforrást használ el, mint kelle, vagy csak azt szeretné, hogy a scriptjei hatékonyak legyenek, megtalálhatja a probléma forrását egy nagyszerű eszköz használatával, amely az alapértelmezett resource csomaggal együtt érkezik: performancebrowser. Elindíthatja a 'start performancebrowser'-el. Ha ez nem létezik, akkor letöltheti a legfrissebb resourcet a GitHub repository-ról. Ez az eszköz hihetetlen mennyiségű információt nyújt a teljesítménybeli hibakereséshez. Memória szivárgások, elem szivárgások, CPU igényes scriptek könnyedén megtalálhatóak a teljesítményböngészőn keresztül. Ha a 'd' opciót használja a Lua időzítőben, akkor láthatja, hogy mely function-ök használja a CPU-t.

A teljesítményböngésző eléréséhez megkell nyitni a web böngészőt, és beírni a következő címet: http://serverIPHere:serverHTTPPortHere/performancebrowser/ Vegye figyelembe, hogy a vége az szükséges. Például: http://127.0.0.1:22005/performancebrowser/ Be kell jelentkeznie egy játékbeli admin felhasználóval, vagy egy olyan felhasználóval mely jogosult a 'resource.performancebrowser.http' és 'resource.ajax.http' belépéshez. A legtöbb szükséges információ a Lua időzítőben és a Lua memória kategóriákban található, olyan értékeket keressen, amelyek sokkal magasabbak, mint a többi érték.

Példák olyan scriptekre, amelyek teljesítményproblémákat okozhatnak

Adatok hozzáadása egy táblához, de nem távolítja el sosem. Ez hónapokba/évekbe telhet, mielőtt problémákat okozna.

local someData = {}

function storeData()
    someData[source] = true
    -- There is no handling for when a player quits, this is considered a memory leak
    -- Using the Lua timing tab you can detect the RAM usage of each resource.
end
addEventHandler("onPlayerJoin", root, storeData)

Az elem szivárgás lehetséges, ha ideiglenes colshape-eket használ, és nem távolítja el azokat. Ez idővel sávszélességi, CPU és memória teljesítménybeli problémákat okozhat.

function useTemporaryCol()
    local col = createColCircle(some code here)
    if (normally this should happen) then
        destroyElement(col)
    end
    -- But sometimes it didn't so the script ended but the collision area remained and over time
    -- you may end up with hundreds to thousands of pointless collision areas. 
    -- The Lua timing tab allows you to see the amount of elements each script has created.
end

Magas CPU igényes szerverek FPS dropokat eredményezhetnek, amitől a szerver játszhatatlanná válik. Ez egy forgalmas szerveren 24 órán belül nagy károkat okozhat. A "refs" mennyisége a Lua időzítőben felismeri az ilyen fajta scripteket, meglepő módon a Lua időzítő nem segített ebben az esetben, de a Lua memória igen.

addEventHandler("onPlayerJoin", root, function()
    -- Code for joiner
    addEventHandler("onPlayerQuit", root, function()
        -- Code for when they have quit
        -- See the problem? It's bound to root which the event handler is being added again and again and again
    end)
end)

Egy function túl intenzíven használja a processzorját, mert bármit is csinál az sok időt vesz igénybe. Ez csak egy function, ami sok időt vesz igénybe a befejezéshez. Teljesítményböngésző nélkül nem tudná, hogy mi okozza, de a teljesítményböngészővel láthatja a Lua időzítőben, hogy a resource sok CPU-t használ. Ha beírja az Options mezőbe a 'd'-t, akkor még a fájl nevét is megmondja, és a function első vonalánál, hogy mennyi CPU-t használ.

function someDodgyCode()
    for i=1, 100000 do
        -- some code
    end
end

Fordította

2018.11.05. Surge
2017.04.17. Kevin