-
Notifications
You must be signed in to change notification settings - Fork 55
Observers addon doesn't correctly handle components already in the component index #231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you ag 8000 ree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
for reference, this is what I've replaced the world_mut.changed = function<T>(_: jecs.World, component: Id<T>, fn: (e: Entity, id: Id, value: T) -> ())
local listeners = signals.emplaced[component]
if not listeners then
listeners = {}
signals.emplaced[component] = listeners
local function on_change(entity: Entity, id: number, value: any)
for _, listener in listeners :: any do
listener(entity, id, value)
end
end
local idr = world.component_index[component]
if idr then
local existing_hook = idr.hooks.on_change
if existing_hook then
table.insert(listeners, existing_hook)
end
idr.hooks.on_change = on_change
end
world:set(component, jecs.OnChange, on_change)
end
table.insert(listeners, fn)
return function()
local n = #listeners
local i = table.find(listeners, fn)
listeners[i] = listeners[n]
listeners[n] = nil
end
end |
Ur proposed solution does not handle when the OnChange hook has been set for a component that has not used for any entity yet. |
Aha, yeah good catch, this should deal with both cases now Though looking at it again there's the possibility of:
The hook they set would disappear, but I don't think it's a big deal since that hook would never have worked anyway? world_mut.changed = function<T>(_: jecs.World, component: Id<T>, fn: (e: Entity, id: Id, value: T) -> ())
local listeners = signals.emplaced[component]
if not listeners then
listeners = {}
signals.emplaced[component] = listeners
local function on_change(entity: Entity, id: number, value: any)
for _, listener in listeners :: any do
listener(entity, id, value)
end
end
local idr = world.component_index[component]
local existing_hook = if idr then idr.hooks.on_change else world:get(component, jecs.OnChange)
if existing_hook then
table.insert(listeners, existing_hook)
end
if idr then
idr.hooks.on_change = on_change
end
world:set(component, jecs.OnChange, on_change)
end
table.insert(listeners, fn)
return function()
local n = #listeners
local i = table.find(listeners, fn)
-- tacked on this change as well, since it's not impossible for a cleanup function to be called multiple times
if i then
listeners[i] = listeners[n]
listeners[n] = nil
end
end
end |
Yep, I think that got it, works in my testing. |
Describe the bug
When using
world:added
,world:changed
, orworld:removed
, if the component does not have an existing hook, but is already in the component index, then the hook component is added without actually overwriting the hooks table within theidr
. This means the callback will never be run.This does not appear to be intended behaviour.
Willing to PR a fix for this as well
Reproduction
Expected Behavior
Observers should work even if set after the component has been used.
Actual Behavior
Observers do not work if the component has been used already, unless it already has a hook set.
The text was updated successfully, but these errors were encountered: