dialogic-godot / dialogic

💬 Create Dialogs, Visual Novels, RPGs, and manage Characters with Godot to create your Game!
https://dialogic.pro
MIT License
3.42k stars 206 forks source link

Small lag/freeze when Dialogic.start(...) is triggered #1943

Closed jdeblander closed 4 months ago

jdeblander commented 5 months ago

The problem

Describe the bug I have done some experimenting with getting the latest version of dialogic 2.0 to work in my project. I have set up a nod that is 'Actionable/Interactable' and that should trigger a bubble (the one from the default styles)

But whenever I trigger the Dialogic.start(...) in my script, I seem to have a split second freeze.

My code:

extends Area2D

class_name Actionable

@export_category("Dialogic")
@export_file var dialog_character_path: String
@export_file var dialog_timeline_path: String
@export var skip_to_label: String = ""

var dialog_character: DialogicCharacter
var dialog_timeline: DialogicTimeline

func _ready():
    dialog_character = load(dialog_character_path)
    dialog_timeline = load(dialog_timeline_path)

func action() -> void:
    var layout = Dialogic.start(dialog_timeline, skip_to_label)
    layout.register_character(dialog_character, self)

The code above is triggered when my player character is in the area and I press the 'interact' button:

extends CharacterBody2D

@onready var actionable_finder: Area2D = $Direction/ActionableFinder

        ...

func _input(event: InputEvent):

        ...

    if event.is_action_pressed("interact"):
        var actionables = actionable_finder.get_overlapping_areas()
        if actionables.size() > 0:
            actionables[0].action()

        ...

I have tried checking in the debugger, but I'm not proficient enough to figure out where the delay comes from. Maybe I'm violating a best practice here? Or I should 'load' the timeline file and or character node in a different way?

extra: The short freeze also occurs when I don't execute the .register_character(...) and it falls back to the default bubble example. I do see the freeze, cause it stops my moving player character.

To Reproduce If necessary, I could give access to a repository with the project.

Expected behavior No obvious 'hiccups' in the process of the game.

Screenshots N/A

System (please complete the following information):

Jowan-Spooner commented 5 months ago

Hey, thanks for the report, I will try to look into this and similar optimizations in the coming days/weeks.

My first assumption is that this is just due to the layout being added (a bunch of nodes added at the same time). I can't be sure though. However in your example you are actually loading the timeline and character in _ready(), so they should already be loaded just correctly.

Other info that would be useful: Does this happen again or only at the first Dialogic.start() call. As in if you have a later encounter, do you get the same hickup? Do you have the same hickup when doing the same encounter (same timeline, etc) again during the same session (without closing the game)?

jdeblander commented 5 months ago

I have created a small test project that has the exact same problem. I tried to avoid as much clutter as possible. It just contains a level and a characterBody. But it still has the same 'hiccup'. I hope this helps in debugging the issue. DialogicTest repository

Other info that would be useful: Does this happen again or only at the first Dialogic.start() call. As in if you have a later encounter, do you get the same hickup? Do you have the same hickup when doing the same encounter (same timeline, etc) again during the same session (without closing the game)?

I tried this and it looks like it only appears the first time Dialogic.start(...) is triggered for a specific timeline.

Jowan-Spooner commented 5 months ago

Thank you, this was very helpful.

I have good and bad news: Good news is, I think I found a way to fix this. This new system might require you to preload/prepare the style you will be using but it should remove most of the stutter. We could probably automate this, but that's not as high a priority. Bad new is that my implementation relies on the new style system coming in alpha 12 (which breaks compatibility for previously made styles). So you will have to wait for the next alpha.

My solution relies on preloading the layout scenes with ResourceLoader.load_threaded_request() in case you need a quick workaround try that.

jdeblander commented 5 months ago

Ok, I'll take the good news that there is a fix incoming. For the bad news. I can wait until the next alpha release. I'm going to look into your proposed solution. but I'm not sure if i have enough knowledge of Godot yet to understand it.

My first bet would be to replace the load(path) with a load_threaded_request(path) in my _ready() function. This would slow down the initial loading of the scene, but then when I start the dialog, it should be smooth. Correct?

lastly I'm going to ask you a very difficult question 😉 Do you have an estimate on when it would release?

Jowan-Spooner commented 5 months ago

Unfortunately you cannot simple replace the load() with load_threaded_request() (because that doesn't actually return the resource).

My solution is to add a prepare() method to the style resource (new in alpha 12 wip). If this method is called a bit before dialog is started (e.g. in the _ready method) with this code DialogicUtil.get_style_by_name("Textbubbles").prepare() then the lag isn't really noticeable anymore from my (be it quick) experiments.

For the release, idk. Hopefully during the next week, pretty surely before christmas though.

jdeblander commented 5 months ago

Okay, looking forward to next release. I'll then test it against my project and my test project and see if we can close this issue.

Thanks.

jdeblander commented 5 months ago

I just downloaded the latest code from the main branch and tried it in the reproduction project (without any code changes). Sadly the issue is still there. Do I need to do something else to avoid it? Or am I missing something?

CakeVR commented 5 months ago

I just downloaded the latest code from the main branch and tried it in the reproduction project (without any code changes). Sadly the issue is still there. Do I need to do something else to avoid it? Or am I missing something?

You will have to change your code, the pull request explains this: https://github.com/coppolaemilio/dialogic/pull/1945

jdeblander commented 5 months ago

Alright, new update, now with the added code from the merged fix. So in my test project, I added DialogicUtil.get_style_by_name("").prepare() And retested if there is any hiccup.

Bad news is, it is still there. On the plus side it is less severe. With a crude time measurement, it changed on my machine from 300ms to 50ms.

Could this somehow be improved further? Cause when something is moving on the screen, it is still very noticable that everything stops for a split second.

Jowan-Spooner commented 5 months ago

@jdeblander Thanks for testing again. I'm glad it got less severe for you too.

The remaining hiccup might be solveable (I sure hope it is) but I have no idea right now how. As it's only the first instanting of the layout, I would guess it could be shader-compilation. Afaik the best workaround is to instance the shader at the scene or game startup. So you could have a empty timeline and start it when your scene is loaded originally. This might remove the hiccup mid-game.

Not sure though. Let's hope we find a fix in the future.

jdeblander commented 5 months ago

I'll give that a try this week and give you an update. I hope with you that there is a way to fix the small remaining hiccup.

faunya commented 5 months ago

Any update or workaround on this? I'm encountering the same issue with the latest version as well.

Jowan-Spooner commented 4 months ago

I answered something similar yesterday on discord, maybe the answer helps:


Hi, this is somewhat expected. Godot always struggles a bit with first instancing stuff.

There is two options: First of all you can try if calling the prepare() method on the style helps at all. This could be done on game startup or when entering the scene.

E.g.

load("res://path/to/my/style.tres").prepare()

Otherwise the best solution is to start a very short nearly empty timeline on scene startup to have the stutter at a less noticeable moment.


faunya commented 4 months ago

I've tried both of those but I still have the hiccup. In my case, it seems to happen every time I call Dialogue.start() even for the same timeline.

gabrielf82 commented 4 months ago

Hi! I've been having the same issue! The "empty timeline" suggestion proposed by @Jowan-Spooner seems to work for now. During my first tests of the "empty timeline" (placed at the project _ready() call) I experienced very simbolic hiccup, but it hasn't yet affected the experience in my project.

CakeVR commented 4 months ago

Hi! I've been having the same issue! The "empty timeline" suggestion proposed by @Jowan-Spooner seems to work for now. During my first tests of the "empty timeline" (placed at the project _ready() call) I experienced very simbolic hiccup, but it hasn't yet affected the experience in my project.

This is indeed the shader compilation.

Take a look at this issue: https://github.com/godotengine/godot/issues/13954

It's a Godot design problem, the compiler is lazy-loading. Whenever a new shader (variant) is known, it will be compiled. Some people explore solutions for this behaviour in the linked issue, there is little Dialogic 2 can do, unless we bundle our own shader precompiler.

CakeVR commented 4 months ago

I will close this. I added a doc entry about this too: https://dialogic-docs.coppolaemilio.com/faq.html#i-encounter-a-small-lag-or-freeze-when-starting-the-dialogue