[Beta] Deferred Lua Event Handling

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?

image

2 Likes

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.

2 Likes

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.

1 Like

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. :upside_down_face:

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 :upside_down_face:

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!

4 Likes

I set the option in my game for later when it goes live :slightly_smiling_face: 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. :cold_sweat:

It’s going to be fine, it’s literally in the post:

I don’t know if I would rely on this, it’s feasible they add a new invocation point that breaks this accidental fix :upside_down_face:

Yes I am aware of that.
I asked if it is the same for RBXScriptSignal:Wait().

And whether deltaTime is changed too.

RenderStepped:Wait() will yield the thread until the RenderStepped signal is fired, and because RenderStepped is an invocation point, nothing should change.

1 Like

Hey, when cloning an object with scripts in it, the scripts start running when they are in nil rather than when they are parented properly. My game custom-loads ScreenGui objects by cloning them into the PlayerGui everytime the player spawns, and the scripts are by default located in those ScreenGuis in StarterGui.
Here is my code for parenting them:

LocalPlayer.CharacterAdded:Connect(function(Character)
	for _, v in next, StarterGui:GetChildren() do
		local Found = PlayerGui:FindFirstChild(v.Name)

		if not Found then
			v:Clone().Parent = PlayerGui
		else
			Found:Destroy()
		end
	end
end)

image
When I clone Global and parent it to PlayerGui, that script runs in nil - I need to add script.AncestryChanged:Wait() everywhere to address this behavior. Is this supposed to be expected, or is it a bug?

2 Likes

I also had to do the same to fix this problem, does seem like a bug.

Exactly. If we didn’t speak out about the new materials, we probably wouldn’t have a (possible) choice to toggle them on/off. If we didn’t speak out about Experimental Mode, we probably wouldn’t have the choice to play older games (which Roblox forced FE on anyway). I’m tired of Roblox forcing updates on us and giving us about about a week or two to fix any issues that may arise from the change before forcing it on our games.

3 Likes

Oh no, the new materials are definitely going to be forced. Experimental mode was removed years ago. Immediate event handling is going to be removed in a few years whether you like it or not. And that’s only because Roblox is waiting for the backlash to die down before they fully remove the old, more consistent and reliable behavior.

They’re tired of having these contracts with developers. They don’t want to be held to all these standards when they could just have everything go willy nilly instead. They want to make this all implementation detail that can change at any time. Giving developers a stable environment where scripts written only a couple years back will still execute without issue, is too much for them and stifles innovation and makes the engine too hard to maintain.

I’ll have you know in my favorites gallery is a game last updated in 2015 and every once in a while I like to go visit it and relive my old memories. This update will completely kill that game.

7 Likes

Wouldn’t you need to call :Destroy() for nested remotes in order to prevent the memory being eaten up by instances?

Edit: Nevermind, I guess as soon as you call :OnInvoke on a BindableFunction, the thread starts to leak. Good catch! for now, I guess I’ll use BindableEvents and keep my event behavior to immediate until task.spawn and task.defer are released.

Experimentally, no. As long as there are no lingering connections or references, it seems to be freed from memory via garbage collection.

local t = setmetatable({}, {__mode = 'v'})
do
    local bf = Instance.new'BindableFunction'
    bf.OnInvoke = function() end
    table.insert(t, bf)
end
for i = 1, 3 do
    print(next(t))
    wait(3)
end

The only thing I can see happening here is if the nested-fastspawned-thread never exists. In this case, you only get one extra BindableFunction per persistent thread, so having leaking bindables would only be caused if you have leaking threads in the first place.

1 Like