Without knowing the rest of your module it’s not immediately obvious that this would or wouldn’t work. It’s therefore not that useful for the forum at all.
Regarding the avoidance of built-in functions, you should in future specify all design constraints in the original post, including any functions to avoid, otherwise it’s not possible for others to actually review your code properly.
It’s also a good idea to provide any dependent code, for example the code of utilities.wait as the exact code in that function strongly dictates the review of code that depends on it.
Consider Promises! I’ve recently started taking a deep stab with Promises for a lot of my work and I recently encountered an issue where I needed delays. Choosing to start learning the Promise pattern was an amazing choice and it provides good alternatives for spawn, delay and yield, plus more.
You can easily work Promises into a lot of your code and chaining would really help you. For example, I recently created a tool that only equips after a few seconds go by. Promises helped where delay would make for some horrible results.
Promise.delay(3):andThen(function ()
-- equip logic here
end)
If you need a similar implementation (since Promises have a scheduler of their own for accurate timing), you really just need Heartbeat (RunService) and os.clock to make a simple timer. You can then use these to make both waits and delays.
I have been stepping my foots at same place (hope this expression ain’t weird. Direct translation from japaense) from learning how and what promise would help me. I understand that they are useful for having measurements of failures / success with yielding functions (with potential failures) , however didn’t know there was simple usage like this too.