Best way to keep running after an Invoke()

So I created a round-based system with a voting system. But when I do an invoke with a bindable function to the voting script it will first wait until it gets what it wants in return. (the voting part is quite long). I want it to still run right after that.

The part that fires the invoke:

gamemodeVoted = voteFunction:Invoke()
			print(gamemodeVoted)
			for i = 30, 0, -1 do
				status.Value = "A new round is starting in: "..i
				wait(1)
			end

I tried using coroutine.wrap but it messes up the rest of the script. Is there a better way??? (Or maybe I didn’t put it in the right spot) Note: I want the for i loop to work with the Bindable function at the same time. (Like right after the invoke I want the loop to run too even tho the invoke is still running.) If you need more info on the script please feel to let me know!

1 Like

If this is on the server, you shouldn’t use RemoteFunctions at all, and should structure it to use RemoteEvents instead.

If it’s actually on the client, you could still use RemoteEvents. Or you could wrap it in a coroutine. I’m not sure what you mean by “but it messes up the rest of the script”.

You could also use a promise library (see the Promise.async/defer method) to make composing async tasks easier. Internally they’re just doing this though:

local conn
conn = game:GetService("RunService").Heartbeat:Connect(function()
  conn:Disconnect()
  -- call Invoke or whatever
end)

Which I’m pretty sure is now the same as task.defer, but that was added after this library was made. Either way all of these methods involve making a coroutine somehow, even if you’re not doing it explicitly :slight_smile:

both of the scripts are in a server. the map voting and the main script are separate. What I want is the voting to activate specifically right before the countdown and run the countdown too. But instead it pauses until the invoke function finishes and then moves on from there.

You could just use a bindable event right? that doesnt wait and it can communicate from server to server

Oh, you mean it’s a BindableFunction instead of a RemoteFunction.

That’s fine, it doesn’t change anything I said. You should be able to wrap it in a coroutine no problem. If you’re having trouble, you could just wrap the countdown in one and put it first.

Thats what I was using:

Read from there

yea, but he is suggesting you run it through a coroutine meaning it wouldn’t wait for the end of the function.

coroutine.wrap(function)

I just did that but messes up the whole game. Could you show me where I would put it in this script here:

https://pastebin.com/YhcfytAm

(Lines 27 to 35)

            gamemodeVoted = voteFunction:Invoke()
            print(gamemodeVoted)
            for i = 30, 0, -1 do
                status.Value = "A new round is starting in: "..i
                if i == 10 then
                    _G.roundStarting = true
                end
                wait(1)
            end

thats your code right now

what I think you can do is just change

gamemodeVoted = voteFunction:Invoke()
--To
gamemodeVoted = voteFunction:Fire() -- bindable event OR
--Connect the remote to a timer
gamemodeVoted = coroutine.wrap(function()
	return voteFunction:Invoke()
end)()
1 Like

And after that I can put the for i loop correct?

yep you can do that right after the coro

I think you’d have more luck with a BindableEvent, rather than a BindableFunction. In other words, I think @DamSam127 has your solution (so you should mark his post as such rather than mine if it does end up being the solution)

If you need the data from the event for some reason, I suppose you could spawn a new thread, in which case I’d suggest using the (kind of) new task.spawn function over coroutine.wrap.

For example:

task.spawn(function()
	gamemodeVoted = voteFunction:Invoke()
	print(gamemodeVoted)
end)
for i = 30, 0, -1 do
	status.Value = "A new round is starting in: "..i
	wait(1)
end

The code after spawn starts running when Invoke is called, after the BindableFunction's function yields or returns.

Also, as an extra bit of info for you or future readers… A key thing to note about how threads work, because it can be important to how your code works, threads actually don’t run at the same time as eachother at all in Roblox. Only one thread can be running at once, and other threads (and Roblox) can only continue running once it yields or ends.

That’s why an infinite loop like while true do will cause Roblox to freeze. The thread with the loop never ends or yields to other code, so it keeps running forever.

You could visualize it like a busy road. Cars coming onto it are yielding to the other cars until there is an opening (when yielding code can start running again). Then, some cars can exit that road to get gas (the thread is yielding), or go home because they’re done driving (the thread is finished running).

When you spawn a thread, or fire an event, you make your current thread yield, and then the new code you are spawning starts running. So, with the traffic analogy you could think about it like changing a traffic light, stopping your current code and letting your spawned code go.

3 Likes

But it doesn’t seem to return what I want when I print gamemodeVoted (it prints nil instead). Is there anyway you can fix that?

The reason is I want something in return the most voted gamemode. You get what I mean right?

Never mind I just used @Hexcede 's example and it worked. Thank you so much for your help!

You should mark @DamSam127’s reply as the solution because my example is the same as what Sam was suggesting, I just wanted to give more information.

Yes but your example solved my issue where @DamSam127 gave the solution but there was a problem where it didn’t return what I needed. It gave nil. That’s why I gave it to you. Are you sure???

Ah dude I think he deserves it ngl. He knows what hes talking about lol sorry I didnt really know how to respond I was trying to come up with a solution, but I didnt know how I solved it on my own code.

1 Like