IT/Guida al Debug: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
mNo edit summary
 
(14 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{IT/MainP}}
[[Category:100%]]
[[Category:IT/Concetti di scripting]]
[[Category:IT/Guide e tutorial]]
Scriptando ti capiteranno presto problemi che non si notano subito. Questa pagina ha lo scopo di elencare qualche strategia di base per trovare l'errore.
Scriptando ti capiteranno presto problemi che non si notano subito. Questa pagina ha lo scopo di elencare qualche strategia di base per trovare l'errore.


Line 11: Line 15:
Questo frammento di esempio ha due errori:
Questo frammento di esempio ha due errori:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
if (getClientName(player) == "Fedor")
if (getPlayerName(player) == "Fedor")
outputChatbox("DISGRACE")
outputChatbox("DISGRACE")
end
end
</syntaxhighlight>
</syntaxhighlight>
Quando lo script tenterà di caricare questa parte di codice, nella console di debug dovrebbe apparire qualcosa del genere:
Quando lo script tenterà di caricare questa parte di codice, nella console di debug dovrebbe apparire qualcosa del genere:
{{Debug info|Loading script failed: C:\<server path>\mods\deathmatch\resources\myResource\script.lua:15: 'then' expected near ´outputChatbox'}}
{{Debug info|Loading script failed: C:\<server path>\mods\deathmatch\resources\myResource\script.lua:15: 'then' expected near 'outputChatbox'}}
Significa che c'è un errore di sintassi. Il ''debugscript'' mostra il percorso dello script che genera l'errore, in modo da conoscere la ''resource'' ('myResource' in questo caso) e ovviamente il nome dello script. Dopo il nome del file mostra la linea dell'errore e poi il tipo di errore. A questo punto è facile, abbiamo dimenticato il 'then':
Significa che c'è un errore di sintassi. Il ''debugscript'' mostra il percorso dello script che genera l'errore, in modo da conoscere la ''resource'' ('myResource' in questo caso) e ovviamente il nome dello script. Dopo il nome del file mostra la linea dell'errore e poi il tipo di errore. A questo punto è facile, abbiamo dimenticato il 'then':
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
if (getClientName(player) == "Fedor") then
if (getPlayerName(player) == "Fedor") then
outputChatbox("DISGRACE")
outputChatbox("DISGRACE")
end
end
Line 27: Line 31:
Significa che la funzione chiamata non esiste: è facilmente spiegabile, visto che il nome esatto della funzione è ''outputChatBox'' (con la ''B'' maiuscola):
Significa che la funzione chiamata non esiste: è facilmente spiegabile, visto che il nome esatto della funzione è ''outputChatBox'' (con la ''B'' maiuscola):
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
if (getClientName(player) == "Fedor") then
if (getPlayerName(player) == "Fedor") then
outputChatBox("DISGRACE")
outputChatBox("DISGRACE")
end
end
Line 48: Line 52:
Prima di tutto ecco alcune funzioni comode per il debug.
Prima di tutto ecco alcune funzioni comode per il debug.
* [[IT/outputDebugString|outputDebugString]] o [[IT/outputChatBox|outputChatBox]] per l'''output'' di informazioni nella console di debug o in chatbox
* [[IT/outputDebugString|outputDebugString]] o [[IT/outputChatBox|outputChatBox]] per l'''output'' di informazioni nella console di debug o in chatbox
* [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] su una variabile per trasformarla in una stringa (per esempio se è una ''float'')
* (in inglese) [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] su una variabile per trasformarla in una stringa (per esempio se è una ''float'')
* [[IT/getElementType|getElementType]] per verificare il tipo di un elemento di MTA
* [[IT/getElementType|getElementType]] per verificare il tipo di un elemento di MTA


Line 63: Line 67:


=== Creare messaggi di debug per verificare il ''valore'' di una variabile===
=== Creare messaggi di debug per verificare il ''valore'' di una variabile===
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.
Diciamo che vuoi creare un ''marker'', ma non sembra essere nella posizione dove dovrebbe trovarsi. La prima cosa che potresti voler fare è controllare se la funzione [[IT/createMarker|createMarker]] è eseguita. Ma nel fare ciò, puoi anche verificare le variabili usate nel [[IT/createMarker|createMarker]] in un colpo solo.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
outputChatBox(tostring(x).." "..tostring(y).." "..tostring(z))
outputChatBox(tostring(x).." "..tostring(y).." "..tostring(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 variables' value can be put together as a string, even if it's a boolean value for example.
Questo mostrerà le 3 variabili usate come coordinate per creare il ''marker''. Assumendo che tu le 'legga' da un file map, puoi controllare in questo modo il loro valore. La funzione [http://www.lua.org/manual/5.1/manual.html#pdf-tostring tostring()] permette di unire con certezza i valori delle variabili in una stringa, anche se per esempio sono dei ''booleani''.


==Example==
==Esempio==
Imagine you created a colshape (collision shape) somewhere and you want a player to stay 10 seconds in it, then perform some action.
Immagina di creare una [[IT/Elemento/Collision shape|colshape]] da qualche parte e di volere che un'azione accada dopo che un [[IT/Elemento/Player|player]] rimanga 10 secondi dentro di essa.
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function colShapeHit(player)
function colShapeHit(player)
-- set a timer to output a message (could as well execute another function)
-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
-- store the timer id in a table, using the player as index
-- settare l'id del timer in una tabella, con il player come ''index''
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"Il player è rimasto 10 secondi nella colshape!")
end
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)


function colShapeLeave(player)
function colShapeLeave(player)
-- kill the timer when the player leaves the colshape
-- elimina il timer quando un player esce dalla colshape
killTimer(colshapeTimer[player])
killTimer(colshapeTimer[player])
end
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)
</syntaxhighlight>
</syntaxhighlight>
When a player enters the colshape, debugscript outputs the following message:
Quando un player entra nella colshape, il debugscript mostra il questo messaggio:
{{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. 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 not create it.
Significa che hai tentato di settare un ''index'' (indice) di una tabella che non esiste. Nell'esempio di sopra, accade quando viene settato l'id del timer nell'''index'' della tabella. Dobbiamo verificare se la tabella esiste e, se non esiste, crearla.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 95: Line 99:
colshapeTimer = {}
colshapeTimer = {}
end
end
-- set a timer to output a message (could as well execute another function)
-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
-- store the timer id in a table, using the player as index
-- settare l'id del timer in una tabella, con il player come ''index''
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
end
Line 102: Line 106:


function colShapeLeave(player)
function colShapeLeave(player)
-- kill the timer when the player leaves the colshape
-- elimina il timer quando un player esce dalla colshape
killTimer(colshapeTimer[player])
killTimer(colshapeTimer[player])
end
end
Line 108: Line 112:
</syntaxhighlight>
</syntaxhighlight>


Now we still get a warning when a player enters the colshape, waits for the message and leaves it again:
Ora riceviamo un errore quando un player entra nella colshape, aspetta dieci secondi e poi la lascia:


{{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.
A parte questo (ne riparleremo più tardi) tutto sembra funzionare bene. Se un player entra nella colshape, il timer è avviato, se resta dentro 10 secondi il messaggio viene mostrato e se esce il timer viene eliminato.


===A more inconspicuous error===
===Un errore ancora meno visibile===
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.
Ma per qualche ragione il messaggio viene mostrato due volte se entri nella [[IT/Elemento/Collision shape|colshape]] mentre sei in un [[IT/Elemento/Veicolo|veicolo]]. Siccome sembra che una parte del codice sia eseguita due volte, aggiungiamo dei messaggi di debug per controllarlo.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 122: Line 126:
colshapeTimer = {}
colshapeTimer = {}
end
end
-- add a debug message
-- messaggio di debug
outputDebugString("colShapeHit")
outputDebugString("colShapeHit")
-- set a timer to output a message (could as well execute another function)
-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
-- store the timer id in a table, using the player as index
-- settare l'id del timer in una tabella, con il player come ''index''
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
end
Line 131: Line 135:


function colShapeLeave(player)
function colShapeLeave(player)
-- add a debug message
-- messaggio di debug
outputDebugString("colShapeLeave")
outputDebugString("colShapeLeave")
-- kill the timer when the player leaves the colshape
-- elimina il timer quando un player esce dalla colshape
killTimer(colshapeTimer[player])
killTimer(colshapeTimer[player])
end
end
Line 139: Line 143:
</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 check the ''player'' variable that '''should''' contain a player element.
Ora ci rendiamo conto che entrambe le funzioni vengono eseguite due volte se siamo in un veicolo, ma solo una volta se siamo a piedi. Sembrerebbe che anche il veicolo chiami gli eventi legati alla colshape. Per confermare questa teoria, controlliamo la variabile ''player'' che '''dovrebbe''' contenere un [[IT/Elemento/Player|elemento player]].


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 146: Line 150:
colshapeTimer = {}
colshapeTimer = {}
end
end
-- add a debug message, with the element type
-- messaggio di debug
outputDebugString("colShapeHit "..getElementType(player))
outputDebugString("colShapeHit "..getElementType(player) )
-- set a timer to output a message (could as well execute another function)
-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
-- store the timer id in a table, using the player as index
-- settare l'id del timer in una tabella, con il player come ''index''
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
end
Line 155: Line 159:


function colShapeLeave(player)
function colShapeLeave(player)
-- add a debug message, with the element type
-- messaggio di debug
outputDebugString("colShapeLeave "..getElementType(player))
outputDebugString("colShapeLeave "..getElementType(player) )
-- kill the timer when the player leaves the colshape
-- elimina il timer quando un player esce dalla colshape
killTimer(colshapeTimer[player])
killTimer(colshapeTimer[player])
end
end
Line 163: Line 167:
</syntaxhighlight>
</syntaxhighlight>


The debug messages tell us that one of the ''player'' variables is a player, the other one 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.
I messaggi di debug ci mostrano che un sola delle variabili ''player'' è davvero un elemento player, l'altra è un elemento veicolo. Visto che vogliamo che lo script reagisca solo quando un player entra nella colshape, aggiungiamo un ''if'' che bloccherà l'esecuzione della funzione se ''player'' '''non''' è un elemento player.


<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
Line 170: Line 174:
colshapeTimer = {}
colshapeTimer = {}
end
end
-- add a check for the element type
-- controllo del ''type'' dell'elemento
if (getElementType(player) ~= "player") then return end
if (getElementType(player) ~= "player") then return end
-- add a debug message, with the element type
-- messaggio di debug
outputDebugString("colShapeHit "..getElementType(player))
outputDebugString("colShapeHit "..getElementType(player))
-- set a timer to output a message (could as well execute another function)
-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
-- store the timer id in a table, using the player as index
-- settare l'id del timer in una tabella, con il player come ''index''
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
end
Line 181: Line 185:


function colShapeLeave(player)
function colShapeLeave(player)
-- add a check for the element type
-- controllo del ''type'' dell'elemento
if (getElementType(player) ~= "player") then return end
if (getElementType(player) ~= "player") then return end
-- add a debug message, with the element type
-- messaggio di debug
outputDebugString("colShapeLeave "..getElementType(player))
outputDebugString("colShapeLeave "..getElementType(player))
-- kill the timer when the player leaves the colshape
-- elimina il timer quando un player esce dalla colshape
killTimer(colshapeTimer[player])
killTimer(colshapeTimer[player])
end
end
Line 191: Line 195:
</syntaxhighlight>
</syntaxhighlight>


Now the script should work as desired, but 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 reached the 10 seconds and is executed. 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 is there). One way would be to check if the timer referenced in the table really exists. To do this, we need a little help function:
Ora lo script dovrebbe funzionare come si desidera, ma continuiamo a ricevere il ''warning'' di cui abbiamo parlato prima. Ciò accade perchè il timer che cerchiamo di eliminare dopo che un player è rimasto 10 secondi nella [[IT/Elemento/Collision shape|colshape]] è già stato eseguito in precedenza e non esiste più. Ci sono diversi modi per risolvere questo ''warning'' (sapendo che il timer non esiste più e che dobbiamo eliminarlo solo se esiste ancora). Un modo sarebbe controllare se il timer riferito a quell'''index'' della tabella esista realmente. Per farlo, abbiamo bisogno di una piccola funzione 'ausiliaria':
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function isTimer(timer)
function isTimer(timer)
Line 203: Line 207:
end
end
</syntaxhighlight>
</syntaxhighlight>
Which we will use when we kill the timer:
Che useremo quando eliminiamo il timer:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
if (isTimer(colshapeTimer[player])) then
if (isTimer(colshapeTimer[player])) then
Line 210: Line 214:
</syntaxhighlight>
</syntaxhighlight>


So the complete working code would be:
Perciò il codice completamente funzionante sarebbe:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function colShapeHit(player)
function colShapeHit(player)
Line 216: Line 220:
colshapeTimer = {}
colshapeTimer = {}
end
end
-- add a check for the element type
-- controllo del ''type'' dell'elemento
if (getElementType(player) ~= "player") then return end
if (getElementType(player) ~= "player") then return end
-- add a debug message, with the element type
-- messaggio di debug
outputDebugString("colShapeHit "..getElementType(player))
outputDebugString("colShapeHit "..getElementType(player))
-- set a timer to output a message (could as well execute another function)
-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
-- store the timer id in a table, using the player as index
-- settare l'id del timer in una tabella, con il player come ''index''
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
end
Line 227: Line 231:


function colShapeLeave(player)
function colShapeLeave(player)
-- add a check for the element type
-- controllo del ''type'' dell'elemento
if (getElementType(player) ~= "player") then return end
if (getElementType(player) ~= "player") then return end
-- add a debug message, with the element type
-- messaggio di debug
outputDebugString("colShapeLeave "..getElementType(player))
outputDebugString("colShapeLeave "..getElementType(player))
-- kill the timer when the player leaves the colshape
-- elimina il timer quando un player esce dalla colshape
if (isTimer(colshapeTimer[player])) then
if (isTimer(colshapeTimer[player])) then
killTimer(colshapeTimer[player])
killTimer(colshapeTimer[player])
Line 250: Line 254:


[[en:Debugging]]
[[en:Debugging]]
[[ru:Debugging]]

Latest revision as of 12:08, 27 August 2009

« Torna alla Pagina principale italiana .

Scriptando ti capiteranno presto problemi che non si notano subito. Questa pagina ha lo scopo di elencare qualche strategia di base per trovare l'errore.

Console di debug

MTA possiede una console ingame per il debug. Puoi aprirla digitando debugscript x nella console, dove x è il livello di debug:

  • 1: solo gli errori
  • 2: gli errori e i warning
  • 3: gli errori, i warning e le info

Perciò, digitando debugscript 3 tutti i messaggi saranno visibili, anche se il livello 2 è raccomandato per la maggior parte dei casi. Dovresti avere il debugscript attivato la maggior parte del tempo che scripti, ti aiuterà a trovare errori di digitazione, insieme ad altri piccoli problemi e a risolverli facilmente.

Esempio

Questo frammento di esempio ha due errori:

if (getPlayerName(player) == "Fedor")
	outputChatbox("DISGRACE")
end

Quando lo script tenterà di caricare questa parte di codice, nella console di debug dovrebbe apparire qualcosa del genere:

INFO: Loading script failed: C:\<server path>\mods\deathmatch\resources\myResource\script.lua:15: 'then' expected near 'outputChatbox'

Significa che c'è un errore di sintassi. Il debugscript mostra il percorso dello script che genera l'errore, in modo da conoscere la resource ('myResource' in questo caso) e ovviamente il nome dello script. Dopo il nome del file mostra la linea dell'errore e poi il tipo di errore. A questo punto è facile, abbiamo dimenticato il 'then':

if (getPlayerName(player) == "Fedor") then
	outputChatbox("DISGRACE")
end

Ora lo script caricherà senza errori e sembrerà funzionare bene, ma quando un player di nome 'Fedor' raggiungerà questa parte dello script, il debugscript darà questo errore:

ERROR: C:\<server path>\mods\deathmatch\resources\d\script.lua:15: attempt to call global 'outputChatbox' (a nil value)

Significa che la funzione chiamata non esiste: è facilmente spiegabile, visto che il nome esatto della funzione è outputChatBox (con la B maiuscola):

if (getPlayerName(player) == "Fedor") then
	outputChatBox("DISGRACE")
end

Ovviamente è solo un esempio, potrebbe esserci un'infinità di altre situazioni, ma dovreste esservi fatti un'idea.

Log del debug

Puoi anche attivare la creazione di un file log del debug modificando il file coreconfig.xml nella tua cartella MTA all'interno di quella di GTA. Devi cercare la riga seguente:

<debugfile/>

E rimpiazzarla con questa, scegliendo la path che preferisci, relativa alla cartella di GTA:

<debugfile>MTA\debugscript.log</debugfile>

Tutti i messaggi di debug da ora in poi verranno aggiunti al file log. Per bloccare questo processo, ripristina la riga precedente.

Strategie di debug

Esistono svariate strategie per trovare gli errori, la maggior parte delle quali prevede l'uso dei messaggi di debug, con informazioni differenti a seconda della situazione.

Funzioni utili

Prima di tutto ecco alcune funzioni comode per il debug.

Creare messaggi di debug per verificare se, quando o quante volte è eseguita una parte di codice

Un esempio tipico potrebbe essere verificare se la sezione di codice dentro un if sia eseguita o meno. Per far questo, aggiungi un messaggio qualsiasi (che in seguito riconoscerai) nella sezione dentro l'if.

if (variabile1 == variabile2) then
	outputDebugString("if eseguito")
	-- fai qualsiasi cosa
end

Un altro uso potrebbe essere verificare se il valore di una variabile è modficato. Prima cerca tutti i punti in cui questo valore è modificato e aggiungi un messaggio di debug proprio sotto di essi.

Creare messaggi di debug per verificare il valore di una variabile

Diciamo che vuoi creare un marker, ma non sembra essere nella posizione dove dovrebbe trovarsi. La prima cosa che potresti voler fare è controllare se la funzione createMarker è eseguita. Ma nel fare ciò, puoi anche verificare le variabili usate nel createMarker in un colpo solo.

outputChatBox(tostring(x).." "..tostring(y).." "..tostring(z))
createMarker(x,y,z)

Questo mostrerà le 3 variabili usate come coordinate per creare il marker. Assumendo che tu le 'legga' da un file map, puoi controllare in questo modo il loro valore. La funzione tostring() permette di unire con certezza i valori delle variabili in una stringa, anche se per esempio sono dei booleani.

Esempio

Immagina di creare una colshape da qualche parte e di volere che un'azione accada dopo che un player rimanga 10 secondi dentro di essa.

function colShapeHit(player)
	-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
	-- settare l'id del timer in una tabella, con il player come ''index''
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"Il player è rimasto 10 secondi nella colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- elimina il timer quando un player esce dalla colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Quando un player entra nella colshape, il debugscript mostra il questo messaggio:

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

Significa che hai tentato di settare un index (indice) di una tabella che non esiste. Nell'esempio di sopra, accade quando viene settato l'id del timer nell'index della tabella. Dobbiamo verificare se la tabella esiste e, se non esiste, crearla.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
	-- settare l'id del timer in una tabella, con il player come ''index''
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- elimina il timer quando un player esce dalla colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Ora riceviamo un errore quando un player entra nella colshape, aspetta dieci secondi e poi la lascia:

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

A parte questo (ne riparleremo più tardi) tutto sembra funzionare bene. Se un player entra nella colshape, il timer è avviato, se resta dentro 10 secondi il messaggio viene mostrato e se esce il timer viene eliminato.

Un errore ancora meno visibile

Ma per qualche ragione il messaggio viene mostrato due volte se entri nella colshape mentre sei in un veicolo. Siccome sembra che una parte del codice sia eseguita due volte, aggiungiamo dei messaggi di debug per controllarlo.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- messaggio di debug
	outputDebugString("colShapeHit")
	-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
	-- settare l'id del timer in una tabella, con il player come ''index''
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- messaggio di debug
	outputDebugString("colShapeLeave")
	-- elimina il timer quando un player esce dalla colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Ora ci rendiamo conto che entrambe le funzioni vengono eseguite due volte se siamo in un veicolo, ma solo una volta se siamo a piedi. Sembrerebbe che anche il veicolo chiami gli eventi legati alla colshape. Per confermare questa teoria, controlliamo la variabile player che dovrebbe contenere un elemento player.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- messaggio di debug
	outputDebugString("colShapeHit "..getElementType(player) )
	-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
	-- settare l'id del timer in una tabella, con il player come ''index''
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- messaggio di debug
	outputDebugString("colShapeLeave "..getElementType(player) )
	-- elimina il timer quando un player esce dalla colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

I messaggi di debug ci mostrano che un sola delle variabili player è davvero un elemento player, l'altra è un elemento veicolo. Visto che vogliamo che lo script reagisca solo quando un player entra nella colshape, aggiungiamo un if che bloccherà l'esecuzione della funzione se player non è un elemento player.

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- controllo del ''type'' dell'elemento
	if (getElementType(player) ~= "player") then return end
	-- messaggio di debug
	outputDebugString("colShapeHit "..getElementType(player))
	-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
	-- settare l'id del timer in una tabella, con il player come ''index''
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- controllo del ''type'' dell'elemento
	if (getElementType(player) ~= "player") then return end
	-- messaggio di debug
	outputDebugString("colShapeLeave "..getElementType(player))
	-- elimina il timer quando un player esce dalla colshape
	killTimer(colshapeTimer[player])
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

Ora lo script dovrebbe funzionare come si desidera, ma continuiamo a ricevere il warning di cui abbiamo parlato prima. Ciò accade perchè il timer che cerchiamo di eliminare dopo che un player è rimasto 10 secondi nella colshape è già stato eseguito in precedenza e non esiste più. Ci sono diversi modi per risolvere questo warning (sapendo che il timer non esiste più e che dobbiamo eliminarlo solo se esiste ancora). Un modo sarebbe controllare se il timer riferito a quell'index della tabella esista realmente. Per farlo, abbiamo bisogno di una piccola funzione 'ausiliaria':

function isTimer(timer)
	local timers = getTimers()
	for k,v in ipairs(timers) do
		if (v == timer) then
			return true
		end
	end
	return false
end

Che useremo quando eliminiamo il timer:

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

Perciò il codice completamente funzionante sarebbe:

function colShapeHit(player)
	if (colshapeTimer == nil) then
		colshapeTimer = {}
	end
	-- controllo del ''type'' dell'elemento
	if (getElementType(player) ~= "player") then return end
	-- messaggio di debug
	outputDebugString("colShapeHit "..getElementType(player))
	-- setta un timer per mostrare un messaggio (potrebbe ugualmente eseguire un'altra funzione)
	-- settare l'id del timer in una tabella, con il player come ''index''
	colshapeTimer[player] = setTimer(outputChatBox,10000,1,"The player stayed 10 seconds in the colshape!")
end
addEventHandler("onColShapeHit",getRootElement(),colShapeHit)

function colShapeLeave(player)
	-- controllo del ''type'' dell'elemento
	if (getElementType(player) ~= "player") then return end
	-- messaggio di debug
	outputDebugString("colShapeLeave "..getElementType(player))
	-- elimina il timer quando un player esce dalla colshape
	if (isTimer(colshapeTimer[player])) then
		killTimer(colshapeTimer[player])
	end
end
addEventHandler("onColShapeLeave",getRootElement(),colShapeLeave)

function isTimer(timer)
	local timers = getTimers()
	for k,v in ipairs(timers) do
		if (v == timer) then
			return true
		end
	end
	return false
end