queryChanged does not work for multiple worlds
Description
Loop starts topoRuntime for all worlds. queryChanged calls useHookState expecting a pristine result for each world. Instead, all worlds receive the same result from topoRuntime, and since the first world to call queryChanged there sets hookState.storage, all future worlds will both:
- Fail to iterate over any pre-existing entities
- Fail to mark _changedStorage[componentToTrack] for that specific world With the result being that no other world will receive the associated data
Steps to reproduce
Minimum Reproduction:
--!strict
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Libraries
local Matter = require(ReplicatedStorage.Matter)
local World1 = Matter.World.new()
local World2 = Matter.World.new()
local World3 = Matter.World.new()
local Worlds = {
World1 = World1,
World2 = World2,
}
local Component = Matter.component("TestComponent")
local Loop = Matter.Loop.new(Worlds)
Loop:setWorlds(Worlds)
Loop:scheduleSystem(function(worlds: {[string]: Matter.World})
for worldId, world in worlds do
print("queryChanged: ", worldId)
for id, record in world:queryChanged(Component) do
print("Component Changed: ", worldId, id, record.new.text)
end
end
end)
local Bindable = Instance.new("BindableEvent")
Loop:begin({
default = Bindable.Event
})
World1:spawn(Component({text = "Test 1"}))
World2:spawn(Component({text = "Test 2"}))
World3:spawn(Component({text = "Test 3"}))
Bindable:Fire()
Worlds.World3 = World3
Loop:setWorlds(Worlds)
Bindable:Fire()
Output:
18:56:13.548 queryChanged: World2 - Server - TestSingleLoopMultipleWorlds:25
18:56:13.548 Component Changed: World2 1 Test 2 - Server - TestSingleLoopMultipleWorlds:27
18:56:13.548 queryChanged: World1 - Server - TestSingleLoopMultipleWorlds:25
18:56:13.549 queryChanged: World1 - Server - TestSingleLoopMultipleWorlds:25
18:56:13.549 queryChanged: World2 - Server - TestSingleLoopMultipleWorlds:25
18:56:13.549 queryChanged: World3 - Server - TestSingleLoopMultipleWorlds:25
queryChanged failed to receive either the Component in World1, or the one in World3 because it processed the one in World2
Expected behavior
I expect queryChanged to work for each world assigned to the Loop and not just the first one called.
It might be possible to do something related to setting unique topoRuntimes for each world in Loop; however, I think a better solution might be to have each world store the storage table as: world._queryChangedHooks[hookState] = storage instead of hookState.storage = storage This would also allow for easy cleanup in queryChangedCleanup.
The potentially larger issue going on here is that using systems within Loop with topoRuntime.start called for all the worlds will make it so any calls to topoRuntime within that system will get the same result for all worlds.
So if you wanted unique values for useEvent/useThrottle/useDeltaTime/other hooks, they'll be the same. I think in general, other hooks getting the same result in a system with multiple worlds is fine, but I think specifically world:queryChanged is world specific and needs world-specific hook results.