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.
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?
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
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.