Deferred Engine Events: Rollout Update

I remember when deferred was first announced and I was very squeamish about using it, now I’m an ardent supporter of it and realise that a lot of my initial fears about deferred were pretty unfounded. It’s crazy how many bugs I’ve avoided simply by switching to deferred and putting defensive architecturing first and foremost in mind when working on my experiences.

It is unfortunate that a host of older experiences are going to break due to the nature of Roblox’s client and that older experiences can’t just run older versions of Roblox like a Unity game or so, but I believe that deferred is the future of the platform and the health of developer code, and is significantly worth adopting early. In the majority of cases, no extra work is required to make code compliant with deferred. Even if immediate continues to be supported, deferred is too good to pass up.

Enabling deferred in default places is a great start, since I’ve been developing with deferred in mind for a while now. There’s still work to be done on some of my existing experiences but I’m happy with how deferred has been treating me so far. Performance is important for my main project and we do a lot of number crunching and heavy computations to make everything come together.

13 Likes

Although I’m happy that Roblox is making an effort to improve development, breaking changes are breaking changes. It wouldn’t be harmful to just leave existing places as is and use this new behavior on new games.

7 Likes

Oh wow, I thought this was already on by default, so I enabled it and it broke my game, and to be completely honest, I don’t know how to fix it.

8 Likes

Forcing deferred events WILL destroy all my games, and probably all popular games to.

It seems reliable on paper, but it is not working out that way. It feels much more random and unpredictable with deferred events. I can’t imagine having to rewrite thousands of lines just for a small performance boost.

8 Likes

What exactly is breaking for you? Do you have race conditions or timing windows that depend on immediate dispatching? I can try to suggest some better approaches. In general it’s a really bad practice to rely on time windows and immediate dispatching.

This goes for everyone who has a problem with this. You need to rethink your game’s control flow if you really depend on immediate dispatching for things to work properly.

11 Likes

What are examples of things that would break?
What is safe?

EDIT: did some research: [Beta] Deferred Lua Event Handling

6 Likes

It breaks games I don’t even maintain as much. even old games that aren’t maintained anymore, I went to test it, and it suddenly break my Freddy Fazbear bin reference I put in my game, The changes should only apply to new places, Just remove the Default option, and only apply it to new places, so no older games that aren’t maintained break in the future

4 Likes

I never coded anything with the idea Engine Events were immediate, now I’m glad I did. :melting_face: If you have experience coding in old game engines, it was well known to never code a game with the expectation of any events or signals or objects being about to fire, access object data or functions immediately, etc. You always planned things out to avoid such headaches. I’m surprised Roblox was running this way for so many years, but better late than never in catching up. :upside_down_face:

5 Likes

Been using deferred events since I started working on my new game and didn’t run into any issues yet and I didn’t have to change anything about the way I code stuff, great work!

4 Likes

Just found an issue in my game, I wrote a small code to allow me to iterate through a table that can take a long time to execute and yield until the next frame if is taking too long to get out of the iteration. Very simple, I count the time is taking each iteration and if is going higher than 0.005 Seconds I yield until the next frame, to continue iterating through the table. Focasds why are you doing this? I do this since it allows other parts of my code to run and doesn’t cause a freeze.

With Deferred Events this code is affected since it can iterate easily through the table and not account for what’s coming the next frame which is a spam of events happening non-stop with no control whatsoever.


What can I do to mitigate this issue? Parallel Luau can’t be used for this since changing properties is what takes most of the time, because of some events or something else internally.


Conflicting Code I Found So Far:

In-Line resumption.

local success = false
Bindable.Event:Connect(function ()
    success = true
end)
Bindable:Fire() -- Causes `Event` to fire
return success

In my game I do not use events as a way to perform this kind of tasks, but I have rare occurrences where I do rely on their previous behavior. Bindable:Fire being included in this deferred behavior is kind of a pain, I wish we had the ability to at least disable that one.


The example about In-Line Resumption opens a bag of issues. Once again, I tend to rely on BindableEvents to trigger automatically to Enable some stuff in the game. Then some other scripts can check the changes, which will not occur until the next frame…

4 Likes

Glad to see optimization to the internal side of things.

2 Likes

If you have a game you actively work on or update. Then it’s probably good practice to keep up with the updates pushed out by Roblox. Most of those workspace settings are great optimization settings if your game is coded for it.

4 Likes

I’m not saying your lying (hell I welcome this update) but can you please provide where you are getting those statistics? Everytime a big update like this comes out y’all provide some random statistic but dont show how you got it…

4 Likes

Relying on immediate events are race conditions. I can’t remake my entire game to use deferred events just to get a small performance boost.

2 Likes

In this example you can fix this if you have the success boolean inside of a table and return the table instead, so you have a live state of what you’re modifying instead of just copying it’s value.

2 Likes

Actual Game Example: I have a BoolValue and a BindableEvent. I currently trigger the BindableEvent to enable the BoolValue and create some extra tasks. After one of those tasks is completed the BoolValue goes to false again.

If I trigger this BindableEvent now, and some parts of the game later in the same frame checks for players who have this BoolValue enabled will run into a false value.


Custom Signal can be used to circumvent this issue, but this just means that BindableEvent becomes useless in this kind of situation, or I just change it to something else.

But once again, this is the issue everyone is talking about which is the need to change multiple parts of your code that were working fine with immediate to allow for a tiny boost in optimization and creates this weird behavior where you change a property, and its respective event triggers the next frame. Many things can happen under the same frame that could check for things that those events change.

1 Like

I understand why it’s a problem but ultimately I’d encourage you to design future code to work with newer patterns. Indirect state is risky, and value objects suck anyway.

You should have some kind of module storing these tasks so you can very discretely index the state of whatever work you’re doing. It goes a long way in making code more maintainable and easier to assess when issues arise. Imagine someone else having to work with your code without guidance from you, would they understand the control flow?

3 Likes

My general solution to preventing stuff from breaking or to make maintenance easier is to just have 1 code library that I use across projects.

All I should have to do is update some functions in my library and everything should be good to go.

I also generally recommend not relying on highly specific things like the order in which things happen.
I just assume that order is never guaranteed.

If you do end up relying on a certain feature or behavior that is highly specific, make sure you generally always have at least one safeguard in place.

As far as I know, this deferred event update doesn’t change a whole lot.

The only thing I’ve seen this update affect so far is scripts that rely on objects being destroyed or parented to nil to perform a clean-up function.

If most of your game code is just .Touched events, buttons being clicked, user input, etc then all should be fine really.

You can still check if objects are being relocated or parented to something else like normal.
You can still check for value changes as normal.

The only thing I’ve really seen being affected by this is object destruction.
But I also saw that Roblox added a Instance.Destroying event.

I think this event is supposed to be a more reliable replacement for scripts that check for objects being parented to nil.

Oh and before you worry, just in case, create a back-up of your game and enable behavior settings one by one just to see if it breaks anything at all.

I see some people panic about game breaking changes, which I fully understand.

But before we speculate or assume, I think one step forward would be to perhaps first enable settings and see if it breaks anything at all, play test some, check the output for potential errors.

After that you can pretty much confirm it, worst case scenario maybe some things do end up not functioning correctly but in that case reverting the settings is just a few mouse clicks.

I hope this is helpful to you and others reading this post. :slight_smile:

3 Likes

Also FWIW I made this mistake too when I introduced deferred updates into Mad City’s interior culling system. I had to change the code so it used a state observer instead of passing a copy of the boolean.

2 Likes

I am adapting my game as much as I can with the new features, but this one bothers me a lot because of how it works. Events were something that from the very beginning, at least in Roblox, would trigger as soon as you make a change.

Since Roblox worked in this way, everyone developed with that in mind. For most uses like changing an Instance’s properties is understandable and I believe less users used it as a way to makes changes.

But BindableEvents could have been used as a way to trigger state changes and the same for every other event.

If you run the following code:

workspace.Baseplate:GetPropertyChangedSignal("CanTouch"):Connect(function()
	print(workspace.Baseplate.CanTouch)
end)

for i = 1, 50 do
	workspace.Baseplate.CanTouch = not workspace.Baseplate.CanTouch
end

You will get all trues, when in reality the State of this property changed to False multiple times. I am honestly against this change.

5 Likes