Task.wait(1) not working properly in module scripts

So here’s my problem. I’m trying to create a module script that creates a “Connection” (Just what I’m naming it) when an explosion hits players, then waits a small amount of time, and then delete that connection after. My problem is, this only seems to actually work when the wait time is very small, otherwise it just waits forever (Or too long for me to be patient enough to see when it will stop waiting). And even with small times, it is not always consistent. I have come to understand that an explosion can handle itself and there isn’t really any need for this, but now I’m simply trying to figure out what’s the problem to have a better understanding of how module scripts work with task.wait(). Here is my script:

function hitManager.DeleteConnectionString(waitTime, attackName, player)
	print("WE ARE DELETING THE CONNECTION FOR "..player.Name)
	task.wait(waitTime)
	print("HERE IS A CHECK TO SEE IF IT GETS PASS THE WAIT")
	local attackObjectFolder = RS.HitManagerFolder:FindFirstChild(attackName)
	attackObjectFolder:FindFirstChild(player.Name):Destroy()
end

Everything that happens before task.wait(waitTime), in other words that one print statement, always works. But when waitTime is 1 second or less it randomly chooses when to work, and when it’s greater than 1 second it just doesn’t work at all. Also, the more players caught in the explosion, the less consistent it is (I’m assuming this has major play in the issue). Any ideas on how to fix it or if there’s better ways for me to handle delays in module scripts?

Seems it might be confusing so in short, everything before task.wait(waitTime) works and everything after doesn’t.

no offense, my brain is having an error with the explanation, also are you sure that waitTime is 1 second? besides 1 second is pretty small

Ok let me edit it, I thought I might’ve yapped too much. But yes haha I’m sure.

1 Like

Well I’m not some genius when it comes to module scripts but your calling hitManager.DeleteConnectionString, usually when doing “.” in module script functions the first value will be self, again I’m not very sure exactly how that would change this in the slightest.

I have a normal script that calls this function from a module script (I have several scripts using this and feel like a module script is better than copying and pasting this same code over and over again). Is this bad practice?

correction: its when you do Module:Function() (colon), not Module.Function()

1 Like

How do the scripts execute this function? Is there a variable used in the first argument that is nil or any other value other than a number?

Ended up using debris to delete the item instead of doing a wait() and then destroy(). But would still be nice to know what was going on.

Code changed to:

function hitManager.DeleteConnectionString(waitTime, attackName, player)
	local attackObjectFolder = RS.HitManagerFolder:FindFirstChild(attackName)
	game.Debris:AddItem(attackObjectFolder:FindFirstChild(player.Name), waitTime)
end

This deletes the connection just fine.

2 Likes

I call it like this for example:

hitManager.DeleteConnectionString(2, explosion, caught)

The 2 in this situation is the waitTime, the explosion is of course the object used as the explosion, and caught is whatever character currently detected in the explosion.

I can’t seem to reproduce your error at all. This would normally imply that the data for waitTime is incorrect, but if debris service works, that probably isn’t it. I could look into it more if you could create a minimum possible script which reproduces the error, but I think that would likely be a huge waste of time since debris service works.

But basically task.wait() should work just fine in a module script.

I’m predicting it has something to do with the way I’m handling how it’s being called. In my normal script, I use a for loop to search for every object in range and then I call this function for each one. The for loop could be why I’m receiving this issue because along with the task.wait() I think it might be causing some type of unintentional delay. You know, it’s like I’m trying to call the for loop without waiting but at the same time it gets forced to wait whenever it reaches task.wait() in the module script, which is why I think it was simply the fact that I was calling task.wait() in such a manner. Here’s the normal script (I’m still currently building it so the empty spaces is where I plan to put different code):

local RunS = game:GetService("RunService")
local RS = game:GetService("ReplicatedStorage")
local SSS = game:GetService("ServerScriptService")
local players = game:GetService("Players")

local hitManager = require(SSS.GameFunctionalities.HitManager)

local object = script.Parent
local nameSaved = object.Name

while object:GetAttribute("Owner") == nil do
	wait()
end

local centerPosition = object.Position
local playerName = object:GetAttribute("Owner")
local player = players:FindFirstChild(playerName)
local power = player.leaderstats.Stats:FindFirstChild("Fire Power")
local powerValue = power.Value
local baseDamage = 30

local allDefenses = workspace.Map.AllDefenses

RunS.Heartbeat:Connect(function(deltaTime)
	local allPlayers = workspace.PlayersFolder:GetChildren()
	for i = 1, #allPlayers do -- This loop is to check for players
		local caught = allPlayers[i]
		local playerCharacter = workspace:FindFirstChild(caught.Name)
		if playerCharacter ~= nil and playerCharacter.Name ~= player.Name then
			local currentPosition = playerCharacter:FindFirstChild("HumanoidRootPart").Position
			local distanceFromCenter = math.sqrt((currentPosition.X - centerPosition.X)^2 + (currentPosition.Y - centerPosition.Y)^2 + (currentPosition.Z - centerPosition.Z)^2)
			local lockedDistance = object.Size.X/2

			if lockedDistance >= distanceFromCenter then
				local canBeTouched = hitManager.CreateConnection(object, playerCharacter)

				if canBeTouched == true then
					hitManager.DeleteConnectionString(2, nameSaved, playerCharacter)
				end
			end
		end
	end
	
	for i, v in pairs(allDefenses:GetChildren()) do -- This loop is to check for defensive objects (For example, I have earth walls that block explosions and take damage)
		local playerDefenses = v:GetChildren()
		for j, t in pairs(playerDefenses) do
			local caught = t
			local currentPosition = caught.Position
			local distanceFromCenter = math.sqrt((currentPosition.X - centerPosition.X)^2 + (currentPosition.Y - centerPosition.Y)^2 + (currentPosition.Z - centerPosition.Z)^2)
			local lockedDistance = object.Size.X/2
			
			if lockedDistance >= distanceFromCenter then
				local canBeTouched = hitManager.CreateDefenseConnection(object, caught)
				
				if canBeTouched then
					hitManager.DeleteConnectionString(2, nameSaved, caught)
				end
			end
			
		end
		
	end
	
end)

And here is the module script where CreateConnection and DeleteConnection are being called from (You’ll notice inefficient and inconsistent practices but don’t worry I’m fixing them in the process):

local hitManager = {}
local RS = game:GetService("ReplicatedStorage")
local RunS = game:GetService("RunService")
local debris = game:GetService("Debris")


function hitManager.CreateConnection(attackObject, caught)
	if caught.Parent:FindFirstChild("HumanoidRootPart") ~= nil then
		caught = caught.Parent
	end
	
	local attackObjectFolder = RS.HitManagerFolder:FindFirstChild(attackObject.Name)

	
	local timesHit
	
	if attackObjectFolder ~= nil then
		timesHit = attackObjectFolder.TimesHit
	end
	
	if attackObjectFolder == nil and caught:GetAttribute("category") ~= "Defense" then
		local newAttackObject = Instance.new("Folder")
		newAttackObject.Name = attackObject.Name
		newAttackObject.Parent = RS.HitManagerFolder
		attackObjectFolder = newAttackObject
		
		timesHit = Instance.new("IntValue")
		timesHit.Name = "TimesHit"
		timesHit.Parent = newAttackObject
		timesHit.Value = 0
		
		
	end
	
	if attackObjectFolder:FindFirstChild(caught.Name) == nil and caught:GetAttribute("category") ~= "Defense" then
		local playerToAdd = Instance.new("StringValue")
		playerToAdd.Name = caught.Name
		playerToAdd.Value = caught.Name
		playerToAdd.Parent = attackObjectFolder
		timesHit.Value += 1
		return true, timesHit.Value
	end
	
	return false
end

function hitManager.CreateDefenseConnection(attackObject, defense)
	local attackObjectFolder = RS.HitManagerFolder:FindFirstChild(attackObject.Name)

	local timesHit

	if attackObjectFolder ~= nil then
		timesHit = attackObjectFolder.TimesHit
	end
	
	if attackObjectFolder == nil and defense:GetAttribute("category") == "Defense" then
		local newAttackObject = Instance.new("Folder")
		newAttackObject.Name = attackObject.Name
		newAttackObject.Parent = RS.HitManagerFolder
		attackObjectFolder = newAttackObject

		timesHit = Instance.new("IntValue")
		timesHit.Name = "TimesHit"
		timesHit.Parent = newAttackObject
		timesHit.Value = 0
	end
	
	if attackObjectFolder:FindFirstChild(defense.Name) == nil and defense:GetAttribute("category") == "Defense" then
		local defenseToAdd = Instance.new("StringValue")
		defenseToAdd.Name = defense.Name
		defenseToAdd.Value = defense.Name
		defenseToAdd.Parent = attackObjectFolder
		timesHit.Value += 1
		return true
	end
	
	return false
end

function hitManager.DeleteConnectionString(waitTime, attackName, player)
	print("WE ARE DELETING THE CONNECTION FOR "..player.Name)
	task.wait(waitTime)
	print("HERE IS A CHECK TO SEE IF IT GETS PASS THE WAIT")
	local attackObjectFolder = RS.HitManagerFolder:FindFirstChild(attackName)
	attackObjectFolder:FindFirstChild(player.Name):Destroy()
end

return hitManager

Essentially you can imagine this as a custom debounce system that’s individualized for specific objects. I’m using folders as the “Connections” to make sure a player can’t be rapidly “hit” a trillion times per contact by adding the player to this folder upon contact and then having them removed from this folder after a short period of time. Of course this is also for the defenses that may get hit. If a connection is there, an object can’t be hit again. If it isn’t, it can be. Of course I plan to have some other stuff happen before the connection is deleted. But as you can see, I simply pass the time I would like for the script to wait before destroying the connection in the deleteConnectionString function, but it seems task.wait() isn’t working well with all of this even though debris did. So I’m assuming that task.wait() is stopping the process somewhere and combined with the for loop calling the module repeatedly it may be causing some type of confusing or lag behind the scenes. This is because when I use it for hit-n-quit attacks like a fireball which hits one player and gets destroyed (or pierces through the player then keeps moving) the deletion of the connection works fine, even with the task.wait(). And that’s because it’s only being called once and has no for loops involved (Is what I’m assuming). I mean, that would explain why debris works fine since it won’t cause any pause in the for loop considering that no type of wait() function is involved as it has it’s own individual timer for deleting the object, right? I’m not sure if this is the best place to talk about this though given I’ve already found a “Solution” so if possible it would be nice to continue this discussion in messages. I don’t have a complete understanding of how everything works and I’m still learning so please inform me if my understanding of how things work is incorrect.

1 Like

Received a great explanation in my messages. Thanks everyone!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.