How to cancel a yield?

Hello, I am using the MoveTo function on the humanoid and I do not want to connect the MoveToFinished event, instead I want to yield it until it fires. I was wondering if how should I make a timeout or a way to cancel the yield if it has been yielding over 2 seconds for situations that the humanoid maybe walking towards a wall?

humanoid.MoveToFinished:Wait();

I’ve tried using:

local moveToFinished = false; local moveToTimeout = tick();
spawn(function() humanoid.MoveToFinished:Wait(); moveToFinished = true; end);
repeat until moveToFinished or (tick()-moveToTimeout > 1) or not wait(1/60);

But I find this code rather inefficient, I don’t really want a loop running on the script.

Thanks in advance,
MXKhronos

2 Likes

I’ve found out that, MoveToFinished fires after 8 seconds and returns false for reached. Is there a way to shorten this yield timeout?

There really isn’t any other way. What you have there is good enough.

This post may be of interest to you. You can probably customize it to fit your needs (ie, have it return true if it finishes successfully or false if it doesn’t or if it times out).

1 Like

Thanks, but I went with this method.

local bind = Instance.new("BindableEvent");
repeat
    -- ~~
    spawn(function() delay(3,function() bind:Fire(); end) humanoid.MoveToFinished:Wait(); bind:Fire(); end);
    bind.Event:Wait();
    -- ~~
until self.IsDead or not wait();

Further improvements would be gladly appreciated. :slight_smile:

There’s two ways to you can solve this.

Your current way works in the following way

-- Happens before the event
local bindable = Instance.new("BindableEvent")
local waiting = true
delay(timeout, function ()
  if waiting then bindable:Fire() end
end)
local connection = event:Connect(function ()
  if waiting then bindable:Fire() end
end)
bindable.Event:Wait()
bindable:Destroy()
connection:Disconnect()
-- Happens after the event

Consider using a pool of bindables to make this more efficient. This would be a lot cleaner if threads weren’t automatically scheduled when yielded and thus we could use the yield method of the coroutine library.

Personally, I would implement it as follows.

-- Happens before the event

local function afterTheEvent()
  -- Happens after the event
end

local connection

delay(timeout, function ()
  if connection.IsConnected then
    connection:Disconnect()
    afterTheEvent()
  end
end)

connection = event:Connect(function ()
  connection:Disconnect()
  afterTheEvent()
end)

If you’re already using an event, you can simply just hook up to the event as well, instead of making a new BindableEvent.
See the samples below.

local continue = false
local con = humanoid.MoveToFinished:Connect(function()
  continue = true
end)
delay(3, function() continue = true end)
repeat wait() until continue
local continue = false
local start = tick()
local con = humanoid.MoveToFinished:Connect(function()
  continue = true
end)
repeat wait() until continue or (tick()-start >= 3)

@woot3 Oh interesting, Thanks.

@Ravenshield That works, but sorry, I don’t want to connect the MoveToFinished for some reasons…

This employees busy waiting, something I’d generally avoid getting into the habit of.

2 Likes

Don’t you get the same situation when using Event:Wait() though? The thread yields for the same amount of time.
Is Event:Wait() less taxing than a loop waiting for the variable because it happens on a lower level, then?

Not sure if this is what you’re looking for but this stops the player after 1 second of movement and ends the yield.

game.Players.LocalPlayer.Character.Humanoid:MoveTo(Vector3.new(100,0,0))
delay(1,function()
game.Players.LocalPlayer.Character.Humanoid:MoveTo(game.Players.LocalPlayer.Character.HumanoidRootPart.Position)
end)
game.Players.LocalPlayer.Character.Humanoid.MoveToFinished:wait()
print(“Finished”)

You’ll actually find that yours should yield for a slightly longer duration. With your implementation, the threads yield until the scheduler resumes them, while mine are resumed by the events themselves. The following example demonstrates this subtle delay:

local t
local continue = false
local con = humanoid.MoveToFinished:Connect(function()
  continue = true
  t = tick()
end)
delay(3, function()
  continue = true
  t = tick()
end)
repeat wait() until continue
print(tick() - t)

Lower-level may not be the correct term, but essentially my implementation is less-taxing since it does not poll a variable (continue) as it will be resumed automatically when the event occurs (or the timeout).

2 Likes

I did not know this. Good feedback!