Metatable problem: attempt to index number with '_running'

image

Script:

local Timer = {}
Timer.__index = Timer

function Timer.new()
	local self = setmetatable({}, Timer)
	
	self._finishedEvent = Instance.new("BindableEvent")
	self.finished = self._finishedEvent.Event
	
	self._running = false
	self._startTime = nil
	self._duration = nil
	
	return self
end

function Timer:start(duration)
	if not self._running then
		local timerThread = coroutine.wrap(function()
			self._running = true
			self._duration = duration
			self._startTime = tick()
			while self._running and tick() - self._startTime < duration do
				wait()
			end
			local completed = self._running
			self._running = false
			self._startTime = nil
			self._duration = nil
			self._finishedEvent:Fire(completed)
		end)
		timerThread()
	else
		warn("Warning: timer could not start again as it is already running.")
	end
end

function Timer:getTimeLeft()
	if self._running then
		local now = tick()
		local timeLeft = self._startTime + self._duration - now
		if timeLeft < 0 then
			timeLeft = 0
		end
		return timeLeft
	else
		warn("Warning: could not get remaining time, timer is not running.")
	end
end

function Timer:isRunning()
	return self._running
end

function Timer:stop()
	self._running = false
end

return Timer

I got this timer script from:
https://education.roblox.com/en-us/resources/battle-royale/timers-and-custom-events

I’m not exactly good at metatables, someone please help!

1 Like

Not enough code or context. This is supposed to be in a module and another script is supposed to require this Timer for use - need to see the code that requires this module and uses it. Also need to know what line 18 is referring to in this script.

The Timer class doesn’t look wrong, so it’s more likely the way you’re using it.

The script Is literally the script I’m talking about in this post, which it’s in the topic.

Line 18: if not self.__running then

That’s not what I’m asking for though. The Timer class itself is fine as I’ve just tested in Studio: what I want is the code you’re using that runs this module. I need to see the code you’re using to require the module understand how you’re using the Timer module, which is what’s causing this problem.

Through my tests and reassessing the error, my bets are on that you called the module the wrong way by not using a colon and instead using a period, because it’s trying to index _running from a number. This means that the timer object is not the first argument.

This is how you’re supposed to call the timer:

local Timer = require(script.Parent.Timer)
local Foobar = Timer.new()

Foobar:start(600)

And I suspect you’re calling it like this:

local Timer = require(script.Parent.Timer)
local Foobar = Timer.new()

Foobar.start(600)

Hence why I need to see the code that requires the Timer module. The class is fine, your code isn’t.

1 Like

I can attest to your statement. I have just tested it.

Calling it as Foobar.start(600) will throw the exact error.

Using Foobar.start(Foobar, 600) or Foobar:start(600) fixes this.

For the original poster: Colons are for methods that pass self as the 1st parameter. If you want to use a dot instead, just be sure to use whatever is being passed as self to the 1st parameter. (in this case, Timer.new())

local MatchManager = {}

-- Services
local serverStrg = game:GetService("ServerStorage")

-- Module scripts
local folder = serverStrg:WaitForChild("ModuleScripts")
local plrManager = require(folder:WaitForChild("PlayerManager"))
local gameSettings = require(folder:WaitForChild("GameSettings"))
local timer = require(folder:WaitForChild("Timer"))

-- Events
local events = serverStrg:WaitForChild("Events")
local MatchStart = events:WaitForChild("MatchStart")
local MatchEnd = events:WaitForChild("MatchEnd")

-- Timer
local gameTimer = timer.new()

local function timeUp()
	print("Time is up!")
end

local function timeStart()
	print("Time is started!")
	gameTimer.start(gameSettings.Match)
	gameTimer.finished:Connect(timeUp)
end

function MatchManager.Prep()
	print("Game is starting...")
	plrManager.tpToMatch()
	MatchStart:Fire()
end

MatchStart.Event:Connect(timeStart)

return MatchManager

This is the script that requires this module. It is a module script.

gameSettings.Match has a IntValue, it’s a 5.

Whoops, looks like i had to replace the .start to :start. sorry for wasting everyone’s time!

Took a few hours even though I had already pointed this out, but glad you found your issue. Remember to be wary about how methods are defined and about how you’re calling them. Colon passes the object itself as the first argument to a function.

Yeah, because some parts of the tutorial from Roblox is messed up. Thanks for your time.