geekrelief / gdnim

godot-nim based bootstrapping framework supporting hot reloading

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Get async working on signals

geekrelief opened this issue · comments

We want to be able to yield on a signal the way gdscript does it. I have some starter code that implements this so far:

import godot
import godotapi / [timer, scene_tree]
import hot
import asyncdispatch

gdobj TimerComp of Timer:

  method enter_tree() =
    discard register(timer_comp)

  proc reload():seq[byte] {.gdExport.} =
    self.queue_free()

  method ready() =
    self.one_shot = true
    registerFrameCallback(
      proc() =
        if hasPendingOperations():
          poll(0)
    )
    asyncCheck self.fireTimer()

#[
  proc fire_timer() {.async.} =
    for c in "STARWARS: A LONG TIME AGO IN A GALAXY FAR, FAR AWAY":
      self.one_shot = true
      self.start(0.15)
      onSignal(self, "timeout")
      print c
]#

  proc fire_timer() {.async.} =
    await on_signal(self.get_tree().createTimer(1), "timeout")
    print "timeout sceneTree"
    self.start(1)
    await on_signal(self, "timeout")
    print "timeout 1"

But I need to handle various expressions and statements where on_signal could be inside of like a for loop, if / else statements, etc. Also I need to implement support for returning values from the signal.

I decided to have the user use the await keyword to wait on the Future from on_signal to allow for composability. I want to be able to use or, and, all, etc from the asyncfutures module.

I'm still undecided on whether to auto generate the registerFrameCallback call somehow or just have a function for it. You need a call to poll for each dll that has Futures. But if you include multiple modules into a dll, you probably only need one Node to poll.

Got this working now:

 proc fireTimer() {.async.} =
    # nnkStmtList
    # nnkCommand
    await on_signal(self.get_tree().createTimer(1), "timeout")
    print "timeout sceneTree"

    # nnkForStmt
    for c in "A LONG TIME AGO IN A GALAXY FAR, FAR AWAY":
      self.timer.start(0.05)
      await onSignal(self.timer, "timeout")
      print c

    when hostOS == "windows": #nnkWhenStmt
      var fast = false
      if fast: #nnkIfStmt
        self.timer.start(0.15)
        await on_signal(self.timer, "timeout")
        print "fast timeout"
      else: #nnkElseStmt
        self.timer.start(1.15)
        await on_signal(self.timer, "timeout")
        print "slow timeout"

    #nnkInfix
    print "waiting for timeout 4 OR click"
    var f1 = on_signal(self.get_tree().createTimer(4), "timeout")
    var f2 = on_signal(self, "simple_click")
    await f1 or f2
    if f1.finished:
      print "timeout or simple click: timeout"
    if f2.finished:
      print "timeout or simple click: click"

    print "waiting for timeout 2 seconds AND click"
    await on_signal(self.get_tree().createTimer(2), "timeout") and on_signal(self, "simple_click")
    print "timeout scene tree timer and simple click"


    #nnkCaseStmt
    var c = 'b'
    case c:
      of 'a':
        print "case a, waiting for timeout"
        await on_signal(self.get_tree().createTimer(4), "timeout")
        print "tree timer timeout"
      else:
        print "case b, waiting for click"
        await on_signal(self, "simple_click")
        print "simple click"

Next up, retrieving parameters from the signal.

got parameters working

    var val = await on_signal(self, "bclick", int)
    print &"bclick {val = }"
    self.rotate45()

    var vals = await on_signal(self, "bsclick", tuple[button_idx:int, shape_idx:int])
    print &"bsclick {vals.button_idx = } {vals.shape_idx = }"
    self.rotate45()