I’m using set_event_listener which has worked great, until today.
I’m getting this error when I’m creating the level, which happens after set_listener() is called:
ERROR:GAMESYS: Failed to setup physics.set_listener() callback
This is the flow in the game:
Set callback. Never throws an error.
Load level. Sometimes throws the error above on large levels.
This made me think the error might actually mean that the event itself couldn’t fire, maybe because of a physics limit. I increased all the values in game.project by a silly amount, and the error still happens.
Posting here before I scratch deeper. Has anyone seen something similar? I’ve only noticed this problem today, and I’ve used this system from the beginning of the project a few months back.
Where do you set the callback? In which script and in which lifecycle function? Do you have physics interact immediately when the level is loaded? Does this also happen the first time you start the game and load your level or only when switching from one level to another?
In the init() function in a script inside the gameworld collection.
Good question, but I think yes, things immediately start colliding.
Oooh, that’s a great question, I didn’t test that before. Loading a level directly never fails. It’s only when a level is reloaded at runtime the listener fails. Also, and this is interesting, it only fails if the previous level was a large one. In this case “large” means lots of tiles. This is consistent.
This lead me to think it’s got something to do with unloading. I use Monarch as a scene manager, so I added a one second delay between hide() and show() the gameworld. But still the same behaviour.
Update
Okay, getting closer. But it makes no sense. Today I added a .gui file to the gameworld collection. When I remove it set_listener() works!
So, what’s the code run inside the gui? Well, nothing really. In fact, I replaced the gui script file with the empty standard template and the listener still fails.
Now to the weird bit: If I leave the file completely empty, with none of the standard functions inside, or leave the script file path blank, set_listener() works with no errors!
Unsure what to test next! I’m trying to replicate this in a minimal project, but no luck so far.
Update 2
Delaying the call from init() also works. But isn’t ideal, because the player now falls through the ground during that time.
Or, at least, a hack that works. If the set_listener() is set when messages are received, the error doesn’t happen. I still don’t know why the .gui component causes the issue when set_listener() is called on init().
function init(self)
msg.post("#", "set_event_listener")
end
function on_message(self, message_id, message, sender)
if message_id == hash("set_event_listener") then
physics.set_event_listener(physics_world_listener)
end
end
Ok, so you are using a tilemap component, correct?
Ok, what if you call physics.set_event_listener(nil) in the final() of the world that you are unloading?
My guess is that the old callback function (from the world you are unloading) is used for a single frame for collisions happening in the new world that you are loading. Or something similar.
The only difference is the test.script being there or not. Which makes no immediate sense to me…
Update
Breakthrough!
In the same collection I have a camera game object that uses window.set_listener(). Adding window.set_listener(nil) in its final() solves the problem. So it seems it’s got something to do with Defold’s global listeners and possibly unloading or garbage collecting.
This was a tricky one to create a small repro project for. This is as minimal as I could get it and still cause the error. It seems to be linked to the amount of components used and the contents of lifecycle scripts.
The error happens consistently for me, but I’m worried it’s a memory issue and it might not trigger on a different machine.