rakugoteam / Rakugo-Dialogue-System

Inspired by Ren'Py, Rakugo is a project aiming to provide a way to make narrative-based games on Godot easily. Simplify your project, if it is a visual novel, point and click, RPG, interactive text game or many other styles and blends of styles.
https://rakugoteam.github.io
MIT License
222 stars 7 forks source link

Houston, we have a big problem ! #21

Closed theludovyc closed 2 years ago

theludovyc commented 2 years ago

For now project use thread

Dialogue.gd

func _ready():
    if has_method(default_starting_event):
        Rakugo.set_current_dialogue(self)
        thread = Thread.new()
        step_semaphore = Semaphore.new()
        thread.start(self, default_starting_event) <= create new thread

default_starting_event is a function name, like this one

func hello_world():
    say(null, "Hello, World !")

    step()

    say(null, "What is your name ?")

    player_name = ask("Paul")

We can see step()

func step():
    if thread and thread.is_active():
        Rakugo.step()

        step_semaphore.wait()

If we refer to doc https://docs.godotengine.org/en/stable/tutorials/performance/threads/using_multiple_threads.html#semaphores , step_semaphore.wait() need to be used in thread. I don't know if it executed in thread but "it's work".

In Godot we can't kill a thread. So to quit properly, all thread need to be finished.

We can see _exit_tree()

func _exit_tree():
    if thread:
        step_semaphore.post()

        thread.wait_to_finish()

But thread need to be finished, so hello_world() must be executed in whole. So we run game, step() it's called, we want to quit, _exit_tree() is called, step_semaphore is released and go on. say(), ask(). And there we have a problem.

We can see ask()

func ask(default_answer:String):
    if thread and thread.is_alive():
        Rakugo.ask(default_answer)

        ask_yield()

        step_semaphore.wait() <= there

        return ask_return

    return null

In ask(), step_semaphore.wait() is executed. After we want to close. And in _exit_tree() we waiting with thread.wait_to_finish(). So it's never ended...

Law is "In Godot we can't kill a thread. So to quit properly, all thread need to be finished". So we can think first, add a flag in all function say(), ask(), notify(), menu(), etc... to check if a thread want to ended and do nothing. But we can add what we want in hello_world() because it's gdscript, save, pop things, make beautiful effect, etc... And them be executed !

theludovyc commented 2 years ago

Another problem is save/load system. How can I start a thread on hello_world() where I want ?

Jeremi360 commented 2 years ago

@theludovyc About threads in Rakugo they are only in it for 3 reasons:

  1. have dialog func with no need to write yield()
  2. to have rollback
  3. to start them from any point.

But how this works is black magic to me, as they were programmed, by this other guy.

Law is "In Godot we can't kill a thread. So to quit properly, all thread need to be finished". So we can think first, add a flag in all function say(), ask(), notify(), menu(), etc... to check if a thread want to ended and do nothing. But we can add what we want in hello_world() because it's gdscript, save, pop things, make beautiful effect, etc... And them be executed !

I'm not sure what you mean by this, but if this is a good solution then go with it, I trust you.

Another problem is save/load system. How can I start a thread on hello_world() where I want ?

I remember that this was working the only place I can point you to are scripts: Store.gd and StoreStack.gd in addons/Rakugo/lib dir.

theludovyc commented 2 years ago

So, we do this https://github.com/rakugoteam/RakuScript