HU/Debugging: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
No edit summary
mNo edit summary
 
(55 intermediate revisions by 5 users not shown)
Line 1: Line 1:
A szkriptekben gyakran előfordulnak kisebb nagyobb problémák, amelyeket nem veszünk észre!Ez a leírás segít abban hogy gyorsan megtaláld őket!
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==
==Hibakereső konzol==
Az MTA tartalmaz beépített hibakereső konzolt!Hasznos mivel ha elgépelünk valamit és nem vesszük észre ő segítségünkre lehet.Ahhoz hogy tudjuk aktiválni ezt a jogusultságot Adminisztrátor rangot kell viselnünk{ACL}.Ha ez rendben van akkor a "debugscript x" parancsal tudjuk változtatni a visszajelzési szintet!
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
Lehetőségek:
* '''3:''' hibákat, figyelmeztetéseket és információs üzeneteket
* '''1:''' Csak a '''Hibákat''' jelzi
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.
* '''2:''' A '''hibákat''' és a '''Figyelmeztetéseket''' is jelzi
* '''3:''' A '''hibákat''' és a '''Figyelmeztetéseket''' is jelzi illetve az '''Információkat''' amelyeket elrejtünk a szkriptekben!
Ha begépeljük a "debugscript 3" parancsot akkor a fent leírt paramétereket fogja megmutatni.Ez a legcélszerűbb funkció, sokkal egyszerűbb vele a fejlesztés


===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 Koszones(message, player)
function SayHello(message, player)
     if (getPlayerName(player) == "Józsika")
     if (getPlayerName(player) == "Fedor")
         outputChatbox("Szia Józsika")
         outputChatbox("Hello Fedor")
     end
     end
end
end
addEventHandler("onChatMessage", root, Koszones)
addEventHandler("onChatMessage", root, SayHello)
</syntaxhighlight>
</syntaxhighlight>
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'}}[Ezt nem fordítom le]
:{{Debug info|Loading script failed: myResource\script.lua:2: 'then' expected near ´outputChatbox'}}
This means the script could not be parsed because there was a syntax error. It shows the script path relative to the resource directory so you can identify to script where the error originated from. After the filename it shows a colon and a number, this number presents the line number - this is so you can find out where in your script the error is - it is very helpful for large scripts. After that is the error message, which varies depending on the error made. Looking at the error message, we can easily determine that the error originated from the resource '''myResource''' and line two of the script file '''script.lua'''. The error message is very clear, we forgot the "then"! We can easily fix that!
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 32: Line 29:
addEventHandler("onChatMessage", root, SayHello)
addEventHandler("onChatMessage", root, SayHello)
</syntaxhighlight>
</syntaxhighlight>
Now the script will load fine and won't output any errors until a player with the name 'Fedor' says something in the chat. At that moment, the debug console will output:
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)}}
This error means that the function '''outputChatbox''' is a nil value, that is - it doesn't exist! This is because the function is actually called [[outputChatBox]], not [[outputChatbox]] - take care of that capital B.:
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)
Line 44: Line 41:
</syntaxhighlight>
</syntaxhighlight>


Of course, this is just an example and I've only skimmed the surface of error messages. There are plenty of other messages and scenarios, but you should get the general idea.
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.
 
==Server & client debug logging==
====Server====
Navigate to: ''(MTA root folder)>server>mods>deathmatch''


There are two nearly identical files:
==Szerver & Cliens hibakeresési napló==
====Szerver====
Menjen a: ''(MTA mappa)>server>mods>deathmatch'' mappába


*The local.conf is the settings for the "host game" menu item in the main menu of MTA. This is a quick and easy way of starting a temporary server from inside the client. When the client is turned off the server will also turn off.
Van itt két majdnem azonos fájl.


*The mtaserver.conf is used when "MTA Server.exe" is executed from (MTA root folder)>server. This runs the server in its own console window which does not need the client to exist or to be run. This is can be useful if you're interested in hosting servers for a longer time period or if you want to experiment with a real world console.
* 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.


Depending on which way you host, you will want to edit those files. The settings in question are:
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"><!-- Specifies the location and name of the debugscript log file. If left blank, server won't be saving this file. -->
<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>  
<!-- Specifies the level of the debugscript log file. Available values: 0, 1, 2, 3. When not set, defaults to 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>


You want to make sure you have a log name specified. Also you want to specify what level of errors will be logged. If it is 0 nothing will be logged. The levels were explained at the top of this article. If the logging level was changed to 3, then in this case all '''serverside''' script errors log to (MTA root folder)>server>mods>deathmatch>logs>scripts.log
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.


====Client====
====Kliens====
Navigate to: ''(MTA root folder)>server>clientscript.log''
Menjen a: ''(MTA mappa)>server>clientscript.log''


This file logs all '''clientside''' script errors. This is set to log by default, no setup required.
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.


==Debug strategies==
==Hibakeresési stratégiák==
There are several strategies that support finding errors, apart from going through the code. Most of them include outputting debug messages, with have different information depending on the situtation.
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.


===Useful functions===
===Hasznos funkciók===
There are some functions that may come in handy for debugging.
Vannak olyan funkciók, amelyek jól jöhetnek a hibakereséshez.
* [[outputDebugString]] or [[outputChatBox]] for outputting any information (use outputDebugString for technical output)
* [[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()] on a variable to turn the value into a string. Useful if the value is not a number or 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.
* [[getElementType]] to check the type of the MTA element.
* [[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.
* [[isElement]] to check if the MTA element exists.
* [[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.


===Add debugmessages to check ''if'', ''when'' or ''how often'' a section of code is executed===
===Adjon meg debugmessage-t annak ellenőrzéséhez, hogy mikor, illetve milyen gyakran hajtja végre a kód egy részét===
A typical example would be verify whether an ''if''-section is executed or not. To do that, just add any message you will recognize later within the ''if''-section.
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.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
if (variable1 == variable2) then
if (variable1 == variable2) then
Line 90: Line 88:
</syntaxhighlight>
</syntaxhighlight>


Another application would be to check when variable values are modified. First search for all occurences of the variable being edited and add a message just beside it.
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.


===Add debugmessages to check the ''value'' of a variable===
===Adjon hozzá debugmessage-t egy változó értékének ellenőrzéséhez===
Let's say you want to create a marker, but it doesn't appear at the position you expect it to be. The first thing you might want to do is check if the [[createMarker]] function is executed. But while doing this, you can also check the values being used in the [[createMarker]] function in one run.
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.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
outputChatBox("posX is: "..x.." posY is: "..y.." posZ is: "..z)
outputChatBox("posX is: "..x.." posY is: "..y.." posZ is: "..z)
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 116: 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 138: 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 169: 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 193: 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 221: 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 228: 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 257: 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 278: 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 291: 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 302: 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 311: Line 309:
</syntaxhighlight>
</syntaxhighlight>


==Fordította==
'''2018.11.05.''' <font size="3">'''[https://wiki.multitheftauto.com/wiki/User:Surge Surge]'''</font>
'''2017.04.17.''' <font size="3">Kevin</font>
[[Category:Translated/Scripting Concepts]]
[[en:Debugging]]
[[it:Guida al Debug]]
[[it:Guida al Debug]]
[[Category:Scripting Concepts]]
[[ru:Debugging]]
[[ru:Debugging]]
[[zh-cn:脚本调试教程]]
[[zh-cn:脚本调试教程]]
[[Category:Tutorials]]
[[Category:Tutorials]]

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