Jump to content

[HELP] Setting up a timer to a function.


Moony

Recommended Posts

I've got this:

Spoiler

local function loopVehicles(p)
	local acc = getPlayerAccount (p)
	if not isGuestAccount (acc) and isObjectInACLGroup ("user."..getAccountName (acc), aclGetGroup ( "Admin" ) ) then
		local count = 0
		for i, v in ipairs (getElementsByType ("vehicle")) do
			if v then
				local occupants = countOccupants(v)
				if not occupants or occupants == 0 then
					if getVehicleType(v) == "Trailer" then
						if not getVehicleTowingVehicle(v) then
							destroyElement (v)
							count = count+1							
						end
					else
						destroyElement (v)
						count = count+1
						outputChatBox("Todos los vehículos fueron removidos.", source)
					end
				end
			end
		end
	end
end
addCommandHandler ("cleana", loopVehicles)

local loopRadius = 50
local function localLoopVehicles(p)
	local acc = getPlayerAccount (p)
	if not isGuestAccount (acc) and isObjectInACLGroup ("user."..getAccountName (acc), aclGetGroup ( "Admin" ) ) then
		local x, y, z = getElementPosition (p)
		local localCol = createColCircle (x, y, loopRadius)
		local count = 0
		for i, v in ipairs (getElementsWithinColShape (localCol, "vehicle")) do
			if v then
				local occupants = countOccupants(v)
				if not occupants or occupants == 0 then
					if getVehicleType(v) == "Trailer" then
						if not getVehicleTowingVehicle(v) then
							destroyElement (v)
							count = count+1
							outputChatBox("Los vehículos cercanos fueron removidos.", source)
						end
					else
						destroyElement (v)
						count = count+1
						outputChatBox("Los vehículos cercanos fueron removidos.", source)
					end
				end
			end
		end
		destroyElement(localCol)
	end
end
addCommandHandler ("clean", localLoopVehicles)

function countOccupants(vehicle)
	if vehicle and getElementType(vehicle) == "vehicle" then
		local ppl = getVehicleOccupants(vehicle)
		if not ppl then
			return false
		else
			local counter = 0
			for seat, player in pairs(ppl) do
				counter = counter + 1
			end
			return counter
		end
	end
end

Script found in MTA's community resources. Made by 'Dutchman101'.

I made the timers and the chatbox warnings:

function Warning1()
	outputChatBox("#D2691E[#FF7F50INFO#D2691E]#FFFFFF: #FF0000Todos los vehículos explotados y vacíos serán removidos en 30 segundos.", getRootElement(), 0, 0, 0, true)
	setTimer(function ()
				outputChatBox("#D2691E[#FF7F50INFO#D2691E]#FFFFFF: #FF0000Todos los vehículos explotados y vacíos serán removidos en 5 segundos.", getRootElement(), 0, 0, 0, true)
				setTimer(loopVehicles, 5000, 1)	
			end, 25000, 1)	
end

Translation:
1. "All blown and empty vehicles will be removed in 30s".
2. "All blown and empty vehicles will be removed in 5s".

The 2nd message waits 25 seconds before appearing, and then it should trigger the 'loopVehicles' function.

So I thought that by replacing the <loopVehicles> in the timer above with the entire fuction, I'd get the desired script:

Spoiler

function Warning1()
	outputChatBox("#D2691E[#FF7F50INFO#D2691E]#FFFFFF: #FF0000Todos los vehículos explotados y vacíos serán removidos en 30 segundos.", getRootElement(), 0, 0, 0, true)
	setTimer(function ()
				outputChatBox("#D2691E[#FF7F50INFO#D2691E]#FFFFFF: #FF0000Todos los vehículos explotados y vacíos serán removidos en 5 segundos.", getRootElement(), 0, 0, 0, true)
				setTimer(function ()
	local acc = getPlayerAccount (p)
	if not isGuestAccount (acc) and isObjectInACLGroup ("user."..getAccountName (acc), aclGetGroup ( "Admin" ) ) then
		local count = 0
		for i, v in ipairs (getElementsByType ("vehicle")) do
			if v then
				local occupants = countOccupants(v)
				if not occupants or occupants == 0 then
					if getVehicleType(v) == "Trailer" then
						if not getVehicleTowingVehicle(v) then
							destroyElement (v)
							count = count+1							
						end
					else
						destroyElement (v)
						count = count+1
						outputChatBox("Todos los vehículos fueron removidos.", source)
					end
				end
			end
		end
	end
end, 5000, 1)	
			end, 25000, 1)	
end
addCommandHandler ("cleana", Warning1)

 

In other words, I've got a cleaning function that happens 5 seconds after an output chatbot that happens 25 seconds after the command is entered.
I've got:
- Bad argument at line 6 ('local acc = getPlayerAccount (p)'). Expected element at argument 1, got nil.
- Bad argument at line 7 ('if not isGuestAccount (acc) and [...] then'). Expected element at argument 1, got boolean.
- Bad argument at line 7 ('("user."..getAccountName (acc), aclGetGroup ( "Admin" )'). Expected element at argument 1, got boolean.
- Line 7: attempted to concatenate a boolean value.

Those errors are thrown as soon as the 30 seconds pass (25 + 5 from both warnings). The warnings are visible.

I pictured that if the warnings work and the cleaning script works, joining them as such would work.

Why am I getting those errors?

Link to comment
8 hours ago, Moony said:

I've got:

- Bad argument at line 6 ('local acc = getPlayerAccount (p)'). Expected element at argument 1, got nil.
- Bad argument at line 7 ('if not isGuestAccount (acc) and [...] then'). Expected element at argument 1, got boolean.
- Bad argument at line 7 ('("user."..getAccountName (acc), aclGetGroup ( "Admin" )'). Expected element at argument 1, got boolean.
- Line 7: attempted to concatenate a boolean value.

Those errors are thrown as soon as the 30 seconds pass (25 + 5 from both warnings). The warnings are visible.

I pictured that if the warnings work and the cleaning script works, joining them as such would work.

Why am I getting those errors?

Dear Moony,

I assume that your script is serverside, thus the signature of a command handler function looks like:

local function commandHandler(player, commandName, args...)

In your script above you wrote for the Warning1 command handler:

function Warning1()

but you should have written...

function Warning1(p)

to receive the player that executed the command. I have not inspected further errors in the script so please tell us if you have further questions. :)

  • Thanks 1
Link to comment
15 hours ago, The_GTA said:

Dear Moony,

I assume that your script is serverside, thus the signature of a command handler function looks like:


local function commandHandler(player, commandName, args...)

In your script above you wrote for the Warning1 command handler:


function Warning1()

but you should have written...


function Warning1(p)

to receive the player that executed the command. I have not inspected further errors in the script so please tell us if you have further questions. :)

I can't believe it was that easy. It works now! :)

How did you detect it between so many things in the script?

The knowledge I had seems to be incorrect. I thought that the arguments inside the parentheses next to the function name (header) didn't have an important effect, other than to set the names of the arguments. I had imagined that leaving it blank would be the same as saying "anything can go there".

So why was it stopping the script from workingç?

Link to comment
  • Scripting Moderators
3 hours ago, Moony said:

How did you detect it between so many things in the script?

Due of error codes, it's easy.

Quote

- Bad argument at line 6 ('local acc = getPlayerAccount (p)'). Expected element at argument 1, got nil.

Function expects element (mostly stored in variable or as parameter), your is nil.

Quote

- Bad argument at line 7 ('if not isGuestAccount (acc) and [...] then'). Expected element at argument 1, got boolean.

Similar case, but this time you got boolean (false), let's check what returns getPlayerAccount:

Quote

Returns the player's account object, or false if the player passed to the function is invalid.

Your variable p was nil, and therefore function returned false on it's failure.

  • Like 1
  • Thanks 1
Link to comment
6 hours ago, Moony said:

How did you detect it between so many things in the script?

I looked at your error log and saw that the getPlayerAccount function did receive a nil as first argument. Then after checking your script I realized that p was nil. Finally I tried to search for p in your script and could not find it's definition, thus the error.

Now that the error was known, I tried to repair your script. Since I know that Warning1 is a command-handler in my experience a typical error is forgetting to allocate or misnaming the function parameters in the command-handler signature, like the player. This repair was confirmed by the getPlayerAccount function, which expects a player as first argument.

3 hours ago, majqq said:

Due of error codes, it's easy.

Function expects element (mostly stored in variable or as parameter), your is nil.

Similar case, but this time you got boolean (false), let's check what returns getPlayerAccount:

Your variable p was nil, and therefore function returned false on it's failure.

What majqq has described is very similar to what I'd do. He did check the wiki to find that getPlayerAccount returns false because the first argument was invalid. I think this is a good idea.

6 hours ago, Moony said:

The knowledge I had seems to be incorrect. I thought that the arguments inside the parentheses next to the function name (header) didn't have an important effect, other than to set the names of the arguments. I had imagined that leaving it blank would be the same as saying "anything can go there".

So why was it stopping the script from workingç?

Obviously the "anything can go there" assumption is wrong. A command-handler has this very specific signature:

void commandHandler(player, cmdName, arg1, arg2, ...)

But looking at your first script where you wrote...

local function loopVehicles(p)

I am pretty sure that you knew that, but you still ... forgot to write it correctly for the "Warning1" function. No idea where this error came from ;)

Edited by The_GTA
  • Thanks 1
Link to comment

I'm certian my issue is that I'm not understanding what goes inside parentheses in the function header. Sometimes it's empty, other it's filled with arguments. This is what leaves me absolutely clueless and confused.

I thought that the parentheses had to have the same arguments as the handler, which in this case is:

addCommandHandler ( string commandName, function handlerFunction [, bool restricted = false, bool caseSensitive = true ] )
-- That turns into:
addCommandHandler ( "cleana", Warning1 [, bool restricted = false, bool caseSensitive = true ] )

Which would leave us with a header similar to:

function Warning1 (string commandName, function handlerFunction [, bool restricted = false, bool caseSensitive = true ] ))
-- That turns into:
function Warning1 ("cleana", Warning1 [, bool restricted = false, bool caseSensitive = true ] ))

And that it serves as the same as stating the values beforehand:

command = "cleana"

function Warning1 (command)
-- The function --
end
addCommandHandler (command, Warning1)

And finally, supposing that my thought process is correct, why would I need to clarify 'p' if 'p' is already being clarified in local acc = getPlayerAccount (p)?

I'm struggling a bit putting these doubts into words. If you don't understand, let me know and I'll try to explain myself better.

 

16 hours ago, majqq said:

Due of error codes, it's easy.

Function expects element (mostly stored in variable or as parameter), your is nil.

Similar case, but this time you got boolean (false), let's check what returns getPlayerAccount:

Your variable p was nil, and therefore function returned false on it's failure.

I've seen DB 3 throw a "got boolean" at the end of the error. I noticed you mentioned "false". Does this mean that everytime DB 3 talks about boolean, it's talking about a false statement? I ask this because I learned that boolean can either be 'true' or 'false'.

Edited by Moony
Link to comment
  • Scripting Moderators
5 hours ago, Moony said:

I've seen DB 3 throw a "got boolean" at the end of the error. I noticed you mentioned "false". Does this mean that everytime DB 3 talks about boolean, it's talking about a false statement? I ask this because I learned that boolean can either be 'true' or 'false'.

That's correct, it's either true or false.

5 hours ago, Moony said:

And finally, supposing that my thought process is correct, why would I need to clarify 'p' if 'p' is already being clarified in local acc = getPlayerAccount (p)?

p isn't defined in your code. Test this piece of example code, you should understand after typing /testcmd (server-side code)

function myCommand(player, cmd)
	outputChatBox("player: "..inspect(player).." cmd: "..inspect(cmd))
end
addCommandHandler("testcmd", myCommand)

 

  • Thanks 1
Link to comment
8 hours ago, Moony said:

And finally, supposing that my thought process is correct, why would I need to clarify 'p' if 'p' is already being clarified in local acc = getPlayerAccount (p)?

Because putting 'p' at the right spot into the parantheses of the command-handlers is the only way to request the player that executed said command handler. If you don't specify the p then you tell Lua that you don't care about p and then you cannot possibly expect p to be defined in any way.

8 hours ago, Moony said:

I've seen DB 3 throw a "got boolean" at the end of the error. I noticed you mentioned "false". Does this mean that everytime DB 3 talks about boolean, it's talking about a false statement? I ask this because I learned that boolean can either be 'true' or 'false'.

What majqq said is 100% correct. Let me clarify by adding that getPlayerAccount does never return "true", it is only possible that it returns "false" in certain conditions. And you never want it to return "false" so check the argument before calling getPlayerAccount with invalid things!

Edited by The_GTA
  • Thanks 1
Link to comment
7 hours ago, majqq said:

Test this piece of example code, you should understand after typing /testcmd (server-side code)


function myCommand(player, cmd)
	outputChatBox("player: "..inspect(player).." cmd: "..inspect(cmd))
end
addCommandHandler("testcmd", myCommand)

 

I'm aware it should throw some kind of string result about some player. But nothing's happening. DB 3 is not throwing any errors.

 

Out of context: It's funny how some of my replies have quotes of things I supposedly said.

Link to comment
33 minutes ago, Moony said:

I'm aware it should throw some kind of string result about some player. But nothing's happening. DB 3 is not throwing any errors.

No, majqq's code is perfect. He wanted to show you how it is done properly, basically what the words inside the parenthesis mean. If you look into the chatbox and compare the output to the script (line 3) you will see that "player" and "cmd" have a different string representation. Just let that sink in. If you get this right then you have possibly solved a big knot in the brain.

Link to comment
  • 2 weeks later...

I wanted to revive this little command since I never got it to work.
After tens of small changes, I got it to work. I had to use an old format from another script I had.

Here's the command majqq made:

function myCommand(player, cmd)
	outputChatBox("player: "..inspect(player).." cmd: "..inspect(cmd), source)
end
addCommandHandler("testcmd", myCommand)

 

This is what I did:

function msgServer ()
	outputChatBox ("player: "..inspect(player).." cmd: "..inspect(cmd))
end
addCommandHandler ("sayserver", msgServer)

If I leave the function's arguments empty, it sends: "player nil cmd nil".
If I put what majqq put (player, cmd), it sends: "player: elem:player[Moony] cmd: "sayserver""

Let's see if I get it right:
The inspect function is inspecting the element that triggered the command, which in this case is a player, and that player's name is "Moony". As for the command, it is throwing the simple string that was used to trigger the function.

 

On 16/03/2020 at 06:55, The_GTA said:

[...] If you look into the chatbox and compare the output to the script (line 3) you will see that "player" and "cmd" have a different string representation. Just let that sink in. [...]

I don't quite get the "..have a different string representation". Do you mean that the string "player" is represented as "elem:player[Moony]"?

Link to comment
6 minutes ago, Moony said:

I don't quite get the "..have a different string representation". Do you mean that the string "player" is represented as "elem:player[Moony]"?

Yes. If you typed /testcmd into the chat you would see that (you did). Looking at string representations of variables is a daily driver for debugging MTA:SA Lua scripts.

  • Thanks 1
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...