ScriptPlayer - Play, and Pause certain parts of scripts until they are ready to run again

Let’s say that I have the following scenario:

Scenario

I am running some code that uses something similar to task.spawn() to run, and this function returns something, but what if the script finishes running before the function finishes running? Then there will be no point in the function returning anything.:

function doThingy()
	-- Run Some Code that takes a long time to run
	task.wait(5)
	local toReturn = math.random(-1, 1)
	-- End of the ebove code
	return toReturn
end

-- Run Some code
task.wait(5)
-- End of the above code
local stuff = nil -- Let's just assume that the doThingy function cannot run without task.spawn()
spawn(function()
	stuff = doThingy()
end)
print(stuff) -- This will return nil

What can we do to fix this? We can use coroutine.yield(), and coroutine.resume(), and I have made a modulescript that can do this.

Code for the module script
local module = {}
module.__index = module

function module.new()
	local self = setmetatable({}, module)
	self.thread = nil
	self.threadStatus = nil
	return self
end

function module:pause()
	if coroutine.isyieldable() then
		self.thread = coroutine.running()
		coroutine.yield(self.thread)
	else
		error("This thread is incompatible with ScriptPlayer:pause()")
	end
end

function module:play()
	if not self.thread then
		warn(self.thread)
		warn(self.threadStatus)
		error("We are unable to run ScriptPlayer:play(), because self.thread doesn't exist. The information that we know is displayed above ^.")
	end
	if coroutine.status(self.thread) == "suspended" then
		coroutine.resume(self.thread)
	else
		warn(self.thread)
		warn(self.threadStatus)
		error("We were unable to play the thread. The information that we know is displayed above ^.")
	end
end

return module
Documentation

The modulescript obviously can’t do anything unless you require it, and create a new class for it.

local scriptPlayer = require(script.ScriptPlayer)
local playerInstance = scriptPlayer.new()

Pausing the script:
This can be done by running playerInstance:pause()

local scriptPlayer = require(script.ScriptPlayer)
local playerInstance = scriptPlayer.new()
playerInstance:pause()
print("This will not play, because it is paused")

Playing the script after it has been paused:

local scriptPlayer = require(script.ScriptPlayer)
local playerInstance = scriptPlayer.new()
local function unPauseAfterAWhile()
    task.wait(8)
    playerInstance:play()
end
task.defer(unPauseAfterAWhile)
playerInstance:pause()
print("This will play once it has been un-paused after 8 seconds")
Extra Details / Conclusion

Note: Unpausing a script after it has been paused can be done, just by running playerInstance:play(), but once you pause a script, it will never continue running unless there is something that is able to play it again. So, running the following script will NEVER play ever again, because the code that is supposed to unpause the script will run after the script has already been unpaused, and it runs “behind” / “after” the code that pauses it. It’s sounds a little weird, but it makes sense:

local scriptPlayer = require(script.ScriptPlayer)
local playerInstance = scriptPlayer.new()

playerInstance:pause() -- This is the last thing that the script will ever do.
task.wait(8) -- This line, and everything after it will never run.
playerInstance:play()
print("This will never run")

That is why in the unpausing example in my documentation, looks “needlessly” more “complex”, but this complexity is necessary in order for it to unpause.

So, to fix my original scenario, we can replace that code with this new code:

local scriptPlayer = require(script.Parent.ScriptPlayer)
local playerInstance = scriptPlayer.new()
function doThingy()
	-- Run Some Code that takes a long time to run
	task.wait(5)
	local toReturn = math.random(-1, 1)
	-- End of the ebove code
	return toReturn
end

-- Run Some code
task.wait(5)
-- End of the above code

local stuff = nil -- Let's just assume that the doThingy function cannot run without task.spawn()
task.defer(function()
	stuff = doThingy()
	playerInstance:play()
end)
playerInstance:pause()
print(stuff) -- This will return whatever the variable "stuff" is equal too.

This module would be extremely useful for times when you would have to do while task.wait() do end, because now, you can just pause a script until it is ready to continue running, and once it is ready to run again, we can unpause the script rather than using while task.wait() do end. Most of the time, you would use events, but there is occasionally a time when using events won’t work, which is why I created this module.

2 Likes