They are not guaranteed to be registered within a certain time frame. You should wrap these calls in a pcall and continuously try it at a time interval until it goes through.
eww
local resetBindable = Instance.new("BindableEvent")
local remote_reset = game.ReplicatedStorage:WaitForChild('remote_reset')
resetBindable.Event:connect(function()
--custom reset logic on server-side
remote_reset:FireServer()
end)
local success = false
while not success do
success = pcall(function()
game:GetService("StarterGui"):SetCore("ResetButtonCallback", resetBindable)
end)
if success then
break
else
print'coregui being slow for ResetButtonCallback'
end
wait(.2)
end
repeat success = pcall(function() setCore() end) wait(0.2) until success
Little bit cleaner
You could make use of name call.
while not pcall(starterGui, "SetCore", "ResetButtonCallback", resetBindable) do
wait()
end
Though of course, this would be I’ll advised.
All that works fine…until one of those items is no longer supported, throwing your script into an infinite yield. I would probably want to add some sort of time-out logic too–something quite large though, like 15 seconds.
local coreCall do
local MAX_RETRIES = 8
local StarterGui = game:GetService('StarterGui')
local RunService = game:GetService('RunService')
function coreCall(method, ...)
local result = {}
for retries = 1, MAX_RETRIES do
result = {pcall(StarterGui[method], StarterGui, ...)}
if result[1] then
break
end
RunService.Stepped:Wait()
end
return unpack(result)
end
end
coreCall('SetCore', 'ResetButtonCallback', false)
I post this every time this comes up. Always keep a utility function around for core calls.
Why is this even a thing?
Because if the game scripts would only run after the corescripts are finished initializing, that means your game scripts are unnecessarily delayed. You don’t want that situation. The errors and the delay in initialization are a minor inconvenience at best and the alternative is worse for all games (even those that don’t interact with core scripts through SetCore).
Really wish the call would do the waiting itself so I don’t need to do a loop …
If we make the assumption (for the purpose of the following question) that Roblox’s code is perfectly organized in such a way that independent things will not yield each other, what does ResetButtonCallback need to yield for? (I assume the 0.001 seconds of actual script runtime can be disregarded?)
SetCore items are not guaranteed to be available within a certain time frame, or ever, for that matter.
You can find the source code of the corescripts here:
https://github.com/Roblox/Core-Scripts/tree/f2965847c9eac9715af9323d76b9ef36d40619bb/CoreScriptsRoot
Now keep in mind that just because something seems to be immediately available in those scripts right now (i.e. no yielding before the point at which a thing is registered), that doesn’t mean they will be in the future. If they add something to the core scripts that needs to perform a web request first, for example, it could be that SetCore items that are almost immediately available now will take longer to become available in the future.
This should not be a problem in your code, because the guarantee that they are available immediately was never given. If you are assuming that right now, that’s your mistake because you assumed wrongly, not the mistake of the implementation.
(And refer back to the post above on why they can’t make the core scripts fully initialize first)
in the wiki guides I read about usage of setcore, for example disabling the reset button, there was no code relating to waiting in a pcall loop for it. lol
There isn’t but there should be. I have to have pcalls for my reset button.
Thanks for sharing the utility function @Fractality_alt!
I noticed that you used RunService.Stepped:Wait() instead of a longer wait like 0.1. Is 8 iterations of RunService.Stepped:Wait() long enough to guarantee setcore is available in time?
From what I have seen, No.
It can take more than 10 seconds to be available so you might want to give it more time
Sorry, a little late of a reply–I was looking back at this thread because of a new thread on this same issue
Your reasoning makes a little more sense to me now, but I’m wondering if it might be better to guarantee that corescripts finish initializing (all their outward interfaces are accessible) before normal scripts run. I think I am okay if there are race conditions between replicatedfirst localscripts and corescripts, although I’d even prefer if replicatedfirst scripts are guaranteed to execute first; do you think this is a good idea?
Also I am thinking events for corescripts.initialized and bools for corescripts.isinitialized would be really useful
I think really all we need is that last bit, events for when they are ready and a method to check that they are ready.
I tried adding this and when I spawned in I could reset. After resetting once, I couldn’t reset anymore. Why did it let me reset the first time?
A little off-topic, but still related to CoreGui not being registered. I am having huge problems with CoreGuiChatConnections not registering at all. I have tried using @Fractality_alt’s utility function to wait for CoreGuiChatConnections to register, but it never does. Even after waiting for thousands of tries, it never gets registered. Extremely annoying for me because I need to fire MessagePosted via creating a new Event and overriding current CoreGuiChatConnections’ MessagePosted event with mine.
I was able to come up with a good core system that has worked for me very well. While wait is often frowned upon, it works really well here, and it doesn’t cause any notable lag for the short amount of time this code is active. When calling this function locally, make sure that you put it in a coroutine.wrap() so whatever else runs after it isn’t halted for the short period of time it takes for this to complete (unless that’s what you want.) It completely stops and frees up your memory when it’s done, thanks to Lua’s Automatic Garbage Collection:
[‘LoadRobloxCore’] = function(CoreType, CoreProperty, Toggle)
repeat
local success = pcall(function()
if CoreType == "SetCore" then
game.StarterGui:SetCore(CoreProperty, Toggle)
elseif CoreType == "SetCoreGui" then
game.StarterGui:SetCoreGuiEnabled(CoreProperty, Toggle)
end
end)
wait(0.02)
until
success
end;
Hope this utility function helps you as much as it’s done for me!