This might be of interest:
This broke my game in ways I don’t fully understand. I can’t tell if it’s because this feature is incomplete or something, but it feels like certain things are firing completely out of order now, even where it should make sense either way.
I have a similar optimization situation on updating that can greatly be helped with the introduction of deferred events. Right now, I have a building that needs to keep track of parts that are connected to the ground, either directly or through another grounded part, and mark parts that are no longer connected and are floating in the air. Every time a part is removed from the building, it needs to run its ‘update’ function. The function is fast enough to update smoothly, but the problem lies when multiple parts are removed on the same frame, the building has to update IMMEDIATELY upon every part being removed so the function runs needlessly multiple times. With deferred events, multiple part removals can be deferred to be handled all at once and only require a single update call max per frame.
This image shows many updates happening on the same frame that could easily be condensed to 5 updates total with deferred events.
Overall, I’m excited for this update to get out of Beta and fully released for all to use. This thread has been packed with great information, some mixed emotions or confusion from some members but I think that the more you know about the update the more you will be excited as I am
I don’t know if this is the right place to post glitches about differed events, so please let me know if I’m being disruptive to the thread.
I found a reliable way to reproduce this warning in studio (when signals are differed)
-
Create a part and select it as either move, scale, or rotate
-
Duplicate the part
-
Change selection modes (I.E. from move to select, from rotate to scale, etc.)
You can definitely tell it’s a beta, but I’m excited to see all the creases ironed out as time goes on
Edit: Never mind the previous statement, it seems to happen completely at random when changing selection modes after selecting a new BasePart.
This fundamentally changes Roblox’s event handling model and breaks any code that expects to be notified immediately when an event fires. Basically, most code that uses events.
Once your callback is called, it’s already too late. The caller has already sped way ahead of you and done other things, and you have to account for way more edge cases now. It is now impossible to use events to ensure that something is acted upon in a timely manner; you may as well use spawn
.
Changes in Instance hierarchy are particularly dangerous examples of this, as scripts might want to know when an Instance they control is reparented/etc and act on it quickly, but now scripts that execute before the callback can see invalid/unintended states.
Things like the camera input being off by one frame appear out of thin air as a side effect of this. By the time scripts are notified of the events corresponding to user input, it’s already too late to change things in response before the next frame.
The fix is to notify scripts faster, which is what Roblox already does and has done since the beginning of time. I do not see why it’s required to break every script in Roblox that relies on events, even if you’re going to do it over the course of a few years. You can not expect every experience on Roblox to migrate, especially the ones that aren’t being maintained anymore, or whose developers have long left the platform. This will leave all the hidden gems of Roblox in an incredibly broken state.
If this is needed for Parallel Luau, keep the old system and simply use this new one only for events that are fired in parallel (so basically, events that are fired outside the Actor by code running desynchronized inside it). This will keep every existing script on Roblox working, while preparing for the future of new code running in parallel. Breaking so many things on Roblox outside of Parallel Luau is not required.
Parallel Luau is a beta feature and has no compatibility guarantees yet, and making that change to allow it to function is perfectly acceptable because running Luau in parallel is a new concept that requires some care. It’s expected that it’ll be different than regular scripting.
However forcing this change on existing code and the entire non-parallel Roblox ecosystem is not acceptable for me. I highly recommend that you backpedal a bit on this change and consider confining it only to actually concurrent systems like Parallel Luau. This is detrimental to my code and many others’ outside of parallel execution.
Firing an event is inviting other code to act on it instantly, that’s what events are for. Events should not be queued unless there is reason for not being able to act on it instantly, like in the case of Parallel Luau.
Of course nobody’s going to read my concerns, but I think it’s worth writing them down here. :/
I think I have an actually sensible idea for how this idea could be implemented into the engine, without breaking existing code or removing functionality, and while allowing for Parallel Luau.
Confine deferred behavior to crossing VM boundaries. When you fire an event, callbacks from the same VM will be called immediately as they are now, but callbacks from other VMs will be deferred.
This will preserve the immediate behavior for all current games and all code confined to one Actor, but have deferred behavior for certain things like Instance hierarchy changes propagating up past the Actor or desynchronized threads firing BindableEvents/etc.
It will avoid breaking existing code while allowing events to work in multithreaded code. All the effort towards setting up these defer queues won’t go to waste yet all games on Roblox will not cease to function randomly.
Only those who explicitly opt-in to using Actors or task.desynchronize
will ever have to deal with deferred events. Everything else will be Immediate. Events firing inside the same Actor will be immediate.
Current behavior is preserved. Backwards compatibility is achieved. Yet it paves the road for Parallel Luau.
As far as I can tell, this is the only way to have your cake and eat it too. If you break every existing game, developers will be mad. Developers are currently mad. If you don’t defer events ever then Parallel Luau will take huge performance hits waiting for other VMs whenever you fire events. But if you use this hybrid approach then existing games will continue to function and Parallel Luau can zoom as fast as it wants.
I hope I’m not too late to propose this. I think there is still time to save this feature.
Hey @zeuxcg, a question if you don’t mind:
In regards to events being deferred, are all same events grouped up, or does the deferring not care for what event it is? What I mean is, if 10 different events are invoked for the same instance, would they be deferred? Or do events only get deferred when the same event is called in rapid succession, such as with BindableEvents?
Events are currently always deferred. When you call an event, the callback is no longer invoked, and you will be able to do whatever you want. Then, eventually, at some point, the callback will be invoked, some time in the future. Right on time… (not)
Usually, “some time in the future” is one of the “checkpoints” in the current frame. Your code will still execute, it just won’t execute when you expect it to, and you will no longer be able to use events for efficiently dispatching instant messages.
You can still use it for dispatching messages that will eventually arrive, though. Just not time-sensitive ones.
It’s difficult to test code with this when API events, especially .PlayerAdded
, are completely or to some degree broken and don’t seem to fire at all or they do rarely. My new project becomes half-unplayable with the deferred signal behavior enabled as of now.
I am quite worried with this change, considering that apparently every event will now be deferred (definitely a bit afraid on how this can affect .AncestryChanged
, .Changed
, and such).
When I start my game it stalls for longer than normal and I see this. I have no idea where this is coming from. Is it possible to have this error attach at least some information about where it’s coming from?
Thanks for the report. As a first step we’re looking at linking these errors to the function that’s exceeding the re-entrancy limit. I will update you when this change goes live.
Why must every event be deferred, breaking nearly every script on Roblox all at once? Why not do this only for Parallel Luau?
zeuxcg’s first post in this topic should answer that question on why they need to do it for all events.
Were there any recent changes made to this?
When this was announced, I turned the setting on in a game that I’m working on just to test and see how my game handles it. It didn’t handle it very well (which is my fault, I’m doing some weird stuff with my code and I really need to patch it up).
Fast forward to today, I enabled the setting because I wanted to dig in to some of my scripts and make the game compatible with this change.
For whatever reason, everything seems to work perfectly now. I’m just wondering if this was something I did unintentionally (via making a lot of improvements to my replicator), or if maybe there were any changes made with this feature that might’ve suddenly improved the behavior of my game.
We disabled this feature in live games. At the moment you will only be able to test it in Studio. That may explain why you aren’t seeing it in a live game.
Sorry, could’ve been more clear. It was in studio where I was testing it. From your response though I’m guessing it’s safe to assume that I might’ve inadvertently patched my game, so… yay, I guess.
After enabling this beta, practically all of my PlayerGui scripts broke - and that’s because in the scripts, I do script.Parent
and the like, assuming that the parent is already set before the script is ran… What’s going on here?
I have CharacterAutoLoads set to false, meaning I copy in the UI from StarterGui manually myself, if that helps. This behavior is pretty easy to fix anyway, but I’m just wondering - what’s going on to cause this? Is this a bug, or intended behavior?
Nevermind, this seems to be something completely different - the UI is deleted when my character spawns in, so I’m assuming something else is broken
Fixed!
The issue was that in my previous code to load in a character, I had this:
Player.CharacterAdded:Connect(function(Character)
Character.AncestryChanged:Wait()
-- do stuff
end)
because the character actually isn’t spawned in when CharacterAdded
is normally called. Pretty nice that this deferred event handling actually fixes a bug!
I set the option in my game for later when it goes live I use remote functions for my game to display prompts for users, such as NPC dialogs and popup messages.
Even during Studio, it didn’t affect anything. But, hopefully it will fix a bug where interacting with 2 NPCs would cause 2 dialogs to alternate instead of one having to wait for the other to finish.
Will the immediate behavior not be supported eventually?
Please correct me if I misunderstood something, but if RenderStepped or Heartbeat are deferred, then aren’t they a bit pointless? All of the point with RenderStepped is to fire when there’s a new frame. Will DeltaTime parameter also be changed?
Does it also affect RenderStepped:Wait() or other scripts using RenderStepped?
I am worried that when I use RenderStepped:Wait() to be faster than wait() will now not be faster, or will break due to other events.
I heavily rely onHeartbeat in my Anti-Cheat to check if the player went too far/teleported/no clipped and I am not sure how to transition/change to a non-immediate behavior.