서버 스크립트

task

기다리고, 나중에 하고, 따로 도는 흐름을 만드는 것. `Chain2D` 아래가 아니라 전역 `task` 입니다. 어디서 기다리는지가 중요합니다 — 런타임이 직접 부른 콜백 안에서 기다리면 그 콜백이 끝날 때까지 채널 전체가 멈춥니다. 런타임은 콜백의 흐름이 끝나기를 기다리는 동안 시뮬레이션을 진행하지도, 스냅샷을 보내지도 않습니다. `task.spawn` / `task.defer` / `task.delay` 로 떼어 낸 흐름은 콜백이 끝난 뒤에도 남아 있어서, 그 안에서 기다리는 동안에는 세계가 계속 돕니다.

task.spawn

선언
task.spawn(routine: ((...any) -> ()) | thread, ...: any) -> thread
매개변수
routine((...any) -> ()) | thread새 흐름으로 돌 함수, 또는 멈춰 있는 thread — 아직 시작하지 않은 것이든 `task.wait` 에서 멈춘 것이든 받습니다. 함수도 thread 도 아니면 `task.spawn expects a function or thread` 로 거부됩니다.
...any`routine` 에 그대로 전달됩니다. 함수면 인자로, 멈춰 있던 thread 면 그 thread 를 멈춰 세운 자리의 반환값으로 들어갑니다.
반환

thread돌기 시작한 흐름. 함수를 넘겼으면 그것을 감싼 새 thread 이고, thread 를 넘겼으면 넘긴 그것이 그대로 돌아옵니다.

지금 바로 시작합니다 — 부른 자리에서 이어서 돌고, `routine` 이 처음 기다리거나 끝날 때 부른 쪽으로 돌아옵니다. 그래서 시작하자마자 난 오류는 부른 자리의 오류가 되고, 스택 트레이스가 붙어 옵니다. 이미 돌고 있거나 끝난 thread 를 넘기면 `cannot schedule a thread that is not suspended` 로 거부됩니다.

task.spawn(function(name)
    Chain2D.Maps.load(name)
end, "town")

task.defer

선언
task.defer(routine: ((...any) -> ()) | thread, ...: any) -> thread
매개변수
routine((...any) -> ()) | thread나중에 돌 함수, 또는 멈춰 있는 thread — `task.spawn` 이 받는 것과 같습니다. 함수도 thread 도 아니면 `task.defer expects a function or thread` 로 거부되고, 돌고 있거나 이미 끝난 thread 는 `cannot schedule a thread that is not suspended` 로 거부됩니다.
...any흐름이 이어질 때 `routine` 에 그대로 전달됩니다 — `task.spawn` 과 같은 방식입니다.
반환

thread줄에 선 흐름. 부른 자리에서는 아직 한 줄도 돌지 않은 채로 돌아옵니다.

줄에만 세웁니다. 지금 돌고 있는 흐름이 끝나거나 양보한 뒤에 시작합니다 — `task.spawn` 과 다른 점은 부른 자리에서 아무것도 실행되지 않는다는 것입니다. 여기서 난 오류는 부른 자리로 돌아가지 않습니다. 부른 쪽은 이미 끝났기 때문이며, 그 오류는 런타임 오류로 올라가 채널을 멈춥니다.

Chain2D.Players.playerAdded(function(player)
    task.defer(function()
        Chain2D.Network.send(player, "hello", { text = "환영합니다" })
    end)
end)

task.delay

선언
task.delay(duration: number, routine: ((...any) -> ()) | thread, ...: any) -> thread
매개변수
durationnumber기다릴 초. 0 이상 3600 이하여야 하고, 생략할 수 없습니다. 그 밖의 값은 `task duration must be between 0 and 3600 seconds` 로 거부됩니다.
routine((...any) -> ()) | thread시간이 됐을 때 부를 함수, 또는 그때 이어서 돌릴 thread. 함수도 thread 도 아니면 `task.delay expects a function or thread` 로 거부됩니다.
...any지금 붙잡아 두었다가 시간이 됐을 때 `routine` 에 그대로 전달됩니다.
반환

thread기다리는 흐름. `routine` 자체가 아니라 그것을 감싸 기다리는 흐름이며, `task.cancel` 에 넘길 것은 이 값입니다.

기다렸다가 한 번 부릅니다. 기다리는 흐름을 줄에 세우는 것이므로 부른 자리는 멈추지 않습니다. `routine` 이 thread 이면 시간이 됐을 때 그것을 이어서 돌리고, 그 안에서 난 오류를 그대로 다시 올립니다.

Chain2D.Players.playerAdded(function(player)
    task.delay(5, function(target)
        Chain2D.Network.send(target, "tip", { text = "5초가 지났습니다" })
    end, player)
end)

task.wait

선언
task.wait(duration: number?) -> number
매개변수
durationnumber?기다릴 초. 0 이상 3600 이하. 생략하면 가장 짧게 — 다음 차례가 돌아올 때까지만 기다립니다.
반환

number실제로 지난 시간(초). 요청한 값이 아니라 타이머가 잰 값입니다.

부른 흐름을 멈춥니다. 그 밖에 무엇이 함께 멈추는지는 어느 흐름에서 불렀는지에 달려 있습니다. `Chain2D.onStart`, `Chain2D.onTick`, `Players.playerAdded`, `Network.on` 처럼 런타임이 직접 부른 콜백 안에서 기다리면, 그 콜백이 끝날 때까지 채널이 멈춥니다 — 그동안 시뮬레이션은 한 걸음도 나아가지 않고 스냅샷도 나가지 않습니다. 다시 움직일 때 밀린 만큼을 몰아서 따라잡지도 않습니다: 최대 여덟 걸음(60Hz 로 약 0.13초)까지만 따라잡고 나머지는 버립니다. 그래서 세계를 계속 돌리면서 기다리려면 `task.spawn` 이나 `task.delay` 로 흐름을 하나 떼어 그 안에서 기다립니다. 범위를 벗어난 값은 `task duration must be between 0 and 3600 seconds` 로 거부됩니다. 런타임이 멈추는 중이면 기다리던 자리에서 `Runtime stopping` 오류로 끝납니다.

Chain2D.onStart(function()
    local elapsed = task.wait(1)
    print("기다린 시간: " .. tostring(elapsed))
end)

task.cancel

선언
task.cancel(thread: thread)
매개변수
threadthread`task.spawn`, `task.defer`, `task.delay` 가 돌려준 흐름. thread 가 아니면 — 아무것도 넘기지 않은 것을 포함해 — `task.cancel expects a thread` 로 거부됩니다. 뒤에 붙인 인자는 `Chain2D.onStart` 나 `Chain2D.onTick` 과 달리 세지 않고 그냥 버립니다 — 여기서 남는 인자는 전할 곳이 없기 때문입니다.

흐름을 되돌려 다시 깨어나지 않게 합니다. 기다리는 중이었다면 그 타이머도 함께 닫히므로 예약된 일은 오지 않습니다. 멈춰 있는 흐름만 취소할 수 있습니다 — 돌고 있는 흐름도, 이미 끝난 흐름도 `cannot cancel a thread that is not suspended` 로 거부됩니다. `task.spawn` 이 돌려준 흐름이 그 자리에서 끝까지 돌았다면 그것도 여기 해당합니다 — 취소할 것이 남아 있지 않습니다.

local pending = task.delay(10, function()
    Chain2D.Network.broadcast("round", { state = "start" })
end)
task.cancel(pending)