Task.delay vs RunService with os.time()

In my game, I have crystals that can be harvested from the mines. After all of a crystal’s energy has been harvested, the crystal disables and waits x number of seconds before regenerating, allowing it to be harvested again. The current system works something like this:

local ServerScriptService = game:GetService("ServerScriptService")
local RunService = game:GetService("RunService")

local settings = require(ServerScriptService:WaitForChild("SETTINGS"))

local Crystals = {
	index = {},
}
Crystals.__index = Crystals

--[[

Creates a new crystal object based on the crystal model.

]]--

function Crystals.new(crystal: Model)
	if Crystals.index[crystal] then
		return Crystals.index[crystal]
	end

	local object = {}
	setmetatable(object, Crystals)

	object.info = settings.Crystals.Types[crystal.Parent.Name]
	object.state = true
end

--[[

Allows the crystal to be collected after the regen period.

]]--

function Crystals:Resume()
	self.state = true
end

--[[

Disables the crystal during the regen period.

]]--

function Crystals:Pause()
	self.state = false
	
	task.delay(self.info.RegenTime, function()
		self:Resume()
	end)
end

return Crystals

Notice how the Crystals:Pause() function utilizes task.delay to go about the regeneration process. Now look at the following:

local ServerScriptService = game:GetService("ServerScriptService")
local RunService = game:GetService("RunService")

local settings = require(ServerScriptService:WaitForChild("SETTINGS"))

local Crystals = {
	index = {},
}
Crystals.__index = Crystals

--[[

Creates a new crystal object based on the crystal model.

]]--

function Crystals.new(crystal: Model)
	if Crystals.index[crystal] then
		return Crystals.index[crystal]
	end

	local object = {}
	setmetatable(object, Crystals)

	object.info = settings.Crystals.Types[crystal.Parent.Name]
	object.timestamp = os.time()
	object.state = true
end

--[[

Allows the crystal to be collected after the regen period.

]]--

function Crystals:Resume()
	self.timestamp = os.time()
	self.state = true
end

--[[

Disables the crystal during the regen period.

]]--

function Crystals:Pause()
	self.timestamp = os.time()
	self.state = false
end

--[[

Checks if any crystal's need resumed.

]]--

RunService.Heartbeat:Connect(function()
	local t = os.time()
	
	for i, v in Crystals.index do
		if ((not v.state) and ((t - v.timestamp) <= v.info.RegenTime)) then
			v:Resume()
		end
	end
end)

return Crystals

Notice how now we are utilizing timestamps and one RunService:Heartbeat connection to regenerate the crystals, rather than task.delay. What I would like input on is should I keep the task.delay system, or should I utilize the RunService in the context provided, or is there a better way to go about this?

The reason I am asking is because I have been having random issues with certain crystals not regenerating properly, and while I don’t think it has to do with the task.delay I have been unable to find another reason.

Thank you for any help in advance!

the task.delay method looks fine, assuming the delay can’t be interrupted

try task.spawn(function()end) and manually assert task.wait(), could work.

other than that, the code is pretty spotless, i would check code where/when you trigger a regen state

the 2nd method would not be good at all as you spend cpu looping through whatever many crystals exists and on every heartbeat aswell, depending on how many crystals there will be, this could impact performance.

1 Like