Edit: It turns out my issue is not to do with GetInstanceAddedSignal . Rather, the issue is a Script with RunContext set to Local running twice. Check the marked solution & my reply for more info.
Old post (click to open)
Hi, I’d like to stop GetInstanceAddedSignal from firing twice or find a way to only make my code run once, not twice. The issue is that this is a reported bug and is affecting my workflow; the workarounds I’ve researched don’t seem to work for me:
Many of my scripts use the same system of GetInstanceAddedSignal and GetInstanceRemovedSignal. All the Models are Atomic, the game has Streaming Enabled. The scripts are all local scripts (client-sided) under StarterGui. The code runs fine and works, apart from the fact that it is firing twice because GetInstanceAddedSignal is.
It prints twice, despite there being only one Lava Model:
Code:
Click to open dropdown
local CollectionService = game:GetService("CollectionService")
local resetPlayer_BindableEvent = game.Players.LocalPlayer.PlayerGui:WaitForChild("BindableEventsFolder"):WaitForChild("resetPlayer_BindableEvent")
local objectsLoadedIn_Table = {}
local tagForThisScript = "LavaTag"
local localPlayer = game.Players.LocalPlayer
local function makeObjectModelWhatItIs(objectModel_v)
local objectDebounce = false
local hitbox
local WorldThisObjectIsIn_StringValue
local success, errorMessage = pcall(function()
hitbox = objectModel_v.hitbox
WorldThisObjectIsIn_StringValue = objectModel_v.WorldThisObjectIsIn_StringValue
end)
--print(success,errorMessage)
if success then
hitbox.Touched:Connect(function(hit)
local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if player and player == game.Players.LocalPlayer then
if objectDebounce == false then
objectDebounce = true
resetPlayer_BindableEvent:Fire()
wait(0.5)
objectDebounce = false
end
end
end)
end
end
-- to get future parts:
CollectionService:GetInstanceAddedSignal(tagForThisScript):Connect(function(newpart: Part)
print("Check GetInstanceAddedSignal!")
print(newpart:GetFullName())
if table.find(objectsLoadedIn_Table, newpart) == nil then
table.insert(objectsLoadedIn_Table, newpart)
makeObjectModelWhatItIs(newpart)
end
end)
-- to remove parts as they are unloaded:
CollectionService:GetInstanceRemovedSignal(tagForThisScript):Connect(function(oldpart: Part)
--print("Check GetInstanceRemovedSignal!")
local index = table.find(objectsLoadedIn_Table, oldpart)
if index then
table.remove(objectsLoadedIn_Table, index)
end
end)
This posts doesn’t seem to solve my issue. I’m not using ChildAdded and GetInstanceAddedSignal. I’m only using GetInstanceAddedSignal, and the relevent GetInstanceRemovedSignal as the Model is Atomic and can stream out/in.
This states that I can use CollectionService:GetTagged() as an alternative, but I cannot as the Models in my game are Atomic. They can Stream in and out from StreamingEnabled, which means they won’t show up when using CollectionService:GetTagged() as they aren’t loaded into the game sometimes to have/be tagged.
Does that if-condition checking if it’s already in the connection not work? As in even if the same item is being added multiple times, it still goes through the condition? It may be hairy having to add if-conditions like that in all your scripts but idk how else to handle it firing multiple times
local lastAddedSignalObject
-- to get future parts:
CollectionService:GetInstanceAddedSignal(tagForThisScript):Connect(function(newpart: Part)
if lastAddedSignalObject ~= newpart then
lastAddedSignalObject = newpart
print("Check GetInstanceAddedSignal T2!")
--print(newpart:GetFullName())
if table.find(objectsLoadedIn_Table, newpart) == nil then
table.insert(objectsLoadedIn_Table, newpart)
makeObjectModelWhatItIs(newpart)
end
else
print("duplicate?")
end
end)
Adding a wait or task.wait anywhere in the code doesn’t help either. It still fires twice as Roblox is firing it twice, I assume at the same time.
If I use debounceTest = false and check that, I risk missing an object that is tagged if there are multiple objects that are tagged. I plan on adding more Lava Models around my game, so that doesn’t work. Either way, it still fires twice.
Also, would this not be a debounce in of itself?
if table.find(objectsLoadedIn_Table, newpart) == nil then
table.insert(objectsLoadedIn_Table, newpart)
makeObjectModelWhatItIs(newpart)
end
I’m not sure what the problem is as your code looks like it should work fine (it avoids calling makeObjectModelWhatItIs twice, which was the problem caused by the bug).
A possible alternative solution that fits your purpose can be to make an existence table where it stores what objects are current streamed in.
local exists = {}
-->> not real event names; just for clarity
AddedSignal:Connect(function(Object)
if exists[Object] then
return
end
exists[Object] = true
-->> rest of code
end)
RemovedSignal:Connect(function(Object)
exists[Object] = nil
-->> rest of code
end)
This solution only works for one tag. If you want to extend it to multiple tags, you can create multiple tables or have some sort of lookup method to see if something exists or not.
However, if you’re trying to find a more convenient workaround without having to repeat this same code over and over again, you can try to make a class that handles this for you:
--|| Example idea
local InstanceLoader = require(InstanceLoader)
--> will have the same functionality as the mentioned solution above, but in class form
local TagA = InstanceLoader.new("TagA")
TagA.InstanceAdded:Connect(function(Object)
-->> code
end
Hi, apologies for the delayed response. Anyhow, is what you describe not the same to what I already have?
Code (click to open)
local CollectionService = game:GetService("CollectionService")
local addOrSubtractPlayersHP_RemoteEvent = game.Workspace.RemoteEventsFolder.HP_SystemFolder.addOrSubtractPlayersHPonServer
local objectsLoadedIn_Table = {}
local tagForThisScript = "LavaTag"
local lastAddedSignalObject
local function makeObjectModelWhatItIs(objectModel_v)
local objectDebounce = false
local hitbox
local WorldThisObjectIsIn_StringValue
local success, errorMessage = pcall(function()
hitbox = objectModel_v.hitbox
WorldThisObjectIsIn_StringValue = objectModel_v.WorldThisObjectIsIn_StringValue
end)
--print(success,errorMessage)
if success then
hitbox.Touched:Connect(function(hit)
local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if player and player == game.Players.LocalPlayer then
if objectDebounce == false then
objectDebounce = true
local numToAddOrSubToHp = -1
addOrSubtractPlayersHP_RemoteEvent:FireServer(numToAddOrSubToHp)
wait(0.5)
objectDebounce = false
end
end
end)
end
end
-- to get future parts:
CollectionService:GetInstanceAddedSignal(tagForThisScript):Connect(function(newpart)
if lastAddedSignalObject ~= newpart then
lastAddedSignalObject = newpart
--print("Check GetInstanceAddedSignal T2!")
print(newpart:GetFullName())
if table.find(objectsLoadedIn_Table, newpart) == nil then
table.insert(objectsLoadedIn_Table, newpart)
makeObjectModelWhatItIs(newpart)
else
print("duplicate check 2?")
-- This doesn't even fire
end
elseif lastAddedSignalObject == newpart then
print("duplicate check 1?")
-- This doesn't even fire
end
end)
-- to remove parts as they are unloaded:
CollectionService:GetInstanceRemovedSignal(tagForThisScript):Connect(function(oldpart: Part)
--print("Check GetInstanceRemovedSignal!")
local index = table.find(objectsLoadedIn_Table, oldpart)
if index then
table.remove(objectsLoadedIn_Table, index)
end
end)
Line 4 → Table of things loaded in
Line 46 to 68 → AddedSignal Function w/ respect to table lookup
Line 71 to 77 → RemovedSignal Function w/ respect to table lookup
To recap: This isn’t working as GetInstanceAddedSignal is firing twice on the Client despite the table lookup. Thus, all code is done twice.
I’m confused about what the actual issue is. It was stated that GetInstanceAddedSignal was firing twice, but, what exactly is the issue being caused by the double signal fire? Is makeObjectModelWhatItIs running twice every single time an object is loaded?
Note that this print statement is being fired twice despite only one print statement.
makeObjectModelWhatItIs is being fired twice and print(newpart:GetFullName()) are being fired twice because CollectionService:GetInstanceAddedSignal is being fired twice by Roblox internally.
After extensive testing, I found that the event was firing twice… because the script itself was being run twice. I have a Script with RunContext set to Client in StarterPlayerScripts. This was the code:
print(game["Run Service"]:IsClient(), script:GetFullName())
local CS = game.CollectionService
CS:GetInstanceAddedSignal("test"):Connect(function(a)
print("added", a)
end)
CS:GetInstanceRemovedSignal("test"):Connect(function(a)
print("removed", a)
end)
print("a")
task.wait(3)
print("b")
Instance.new("Part", workspace):AddTag("test")
Indeed, GetInstanceAddedSignal runs twice. However, that’s not due to a faulty connection, but rather (more interestingly) because… the script itself runs twice, in two different locations. One in StarterPlayerScripts, and another instance in PlayerScripts:
Also, I was able to workaround the issue by doing the following:
if script.Parent.Parent.Parent.Name == "PlayerGui" then
-- code here
else
print("Checking if this fired elsewhere!")
print(script.Parent.Parent.Parent.Name)
end
I’ll report the bug via @Bug-Support, but that might take some time. Thank you so much, this issue has been quite the annoyance.
Just to clarify that this is not a bug but rather (unexpected) expected behavior. For the sake of simplicity we didn’t want to have any exceptions to where scripts using the new RunContext could run. Unfortunately that also resulted in some quirks such as the one you see here where the script runs in both StarterPlayerScripts and PlayerScripts.
The correct solution is to parent your script elsewhere or use a LocalScript instead.
Late last year we added some warnings to Studio that should make this more clear, if those aren’t showing then let me know because that certainly would be a bug
Could you share what the “warnings” would look like? I don’t see anything show up in the Output. I also do not see anything in the Properties menu on-hover:
When hovering over a localscript in the object list, there is a message, but it does not mention RunContext:
Adding to the property widget would be good, yes. I assume a message would show up when hovering over the RunContext property itself.
That in combination with the warning in the console would be great at telling people the info. But, I wouldn’t want things to get spammed in the console of course.