Skip to content

Commit c782633

Browse files
committed
Added a multithreading loading
I just replaced load(scene_path) with ResourceLoader.load_threaded_request(scene_path) and placed await in the code. Now, when scenes with characters are loaded, there are no freezes in the main thread. I used a complex custom scene with Spine animations and 4k atlas textures.
1 parent b56e693 commit c782633

File tree

1 file changed

+87
-34
lines changed

1 file changed

+87
-34
lines changed

addons/dialogic/Modules/Character/subsystem_portraits.gd

+87-34
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,22 @@ func load_game_state(_load_flag:=LoadFlags.FULL_LOAD) -> void:
3535
var character_info: Dictionary = portraits_info[character_path]
3636
var character: DialogicCharacter = load(character_path)
3737
var container := dialogic.PortraitContainers.load_position_container(character.get_character_name())
38-
add_character(character, container, character_info.portrait, character_info.position_id)
39-
change_character_mirror(character, character_info.get('custom_mirror', false))
40-
change_character_z_index(character, character_info.get('z_index', 0))
41-
change_character_extradata(character, character_info.get('extra_data', ""))
38+
39+
ResourceLoader.load_threaded_request(character_path)
40+
41+
var load_status = ResourceLoader.load_threaded_get_status(character_path)
42+
while load_status == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
43+
await get_tree().process_frame
44+
load_status = ResourceLoader.load_threaded_get_status(character_path)
45+
46+
if load_status == ResourceLoader.THREAD_LOAD_LOADED:
47+
character = ResourceLoader.load_threaded_get(character_path)
48+
add_character(character, container, character_info.portrait, character_info.position_id)
49+
change_character_mirror(character, character_info.get('custom_mirror', false))
50+
change_character_z_index(character, character_info.get('z_index', 0))
51+
change_character_extradata(character, character_info.get('extra_data', ""))
52+
else:
53+
push_error('[Dialogic] Failed to load character "' + str(character_path) + '".')
4254

4355
# Load Speaker Portrait
4456
var speaker: Variant = dialogic.current_state_info.get('speaker', "")
@@ -117,19 +129,29 @@ func _change_portrait(character_node: Node2D, portrait: String, fade_animation:=
117129
if (not previous_portrait == null and
118130
previous_portrait.get_meta('scene', '') == scene_path and
119131
# Also check if the scene supports changing to the given portrait.
132+
previous_portrait.has_method('_should_do_portrait_update') and
120133
previous_portrait._should_do_portrait_update(character, portrait)):
121134
portrait_node = previous_portrait
122135
info['same_scene'] = true
123136

124137
else:
125138

126139
if ResourceLoader.exists(scene_path):
127-
var packed_scene: PackedScene = load(scene_path)
140+
ResourceLoader.load_threaded_request(scene_path)
141+
142+
var load_status = ResourceLoader.load_threaded_get_status(scene_path)
143+
while load_status == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
144+
await get_tree().process_frame
145+
load_status = ResourceLoader.load_threaded_get_status(scene_path)
128146

129-
if packed_scene:
130-
portrait_node = packed_scene.instantiate()
147+
if load_status == ResourceLoader.THREAD_LOAD_LOADED:
148+
var packed_scene: PackedScene = ResourceLoader.load_threaded_get(scene_path)
149+
if packed_scene:
150+
portrait_node = packed_scene.instantiate()
151+
else:
152+
push_error('[Dialogic] Portrait node "' + str(scene_path) + '" for character [' + character.display_name + '] could not be loaded. Your portrait might not show up on the screen. Confirm the path is correct.')
131153
else:
132-
push_error('[Dialogic] Portrait node "' + str(scene_path) + '" for character [' + character.display_name + '] could not be loaded. Your portrait might not show up on the screen. Confirm the path is correct.')
154+
push_error('[Dialogic] Failed to load portrait node "' + str(scene_path) + '" for character [' + character.display_name + '].')
133155

134156
if !portrait_node:
135157
portrait_node = default_portrait_scene.instantiate()
@@ -156,7 +178,8 @@ func _change_portrait(character_node: Node2D, portrait: String, fade_animation:=
156178
if not fade_animation.is_empty() and fade_length > 0:
157179
var fade_out := _animate_node(previous_portrait, fade_animation, fade_length, 1, true)
158180
var _fade_in := _animate_node(portrait_node, fade_animation, fade_length, 1, false)
159-
fade_out.finished.connect(previous_portrait.queue_free)
181+
await fade_out.finished
182+
previous_portrait.queue_free()
160183
else:
161184
previous_portrait.queue_free()
162185

@@ -167,20 +190,27 @@ func _change_portrait(character_node: Node2D, portrait: String, fade_animation:=
167190
## Unless @force is false, this will take into consideration the character mirror,
168191
## portrait mirror and portrait position mirror settings.
169192
func _change_portrait_mirror(character_node: Node2D, mirrored := false, force := false) -> void:
170-
var latest_portrait := character_node.get_child(-1)
193+
var latest_portrait := character_node.get_child(-1)
194+
if character_node.get_child_count() > 0 else null
171195

172-
if latest_portrait.has_method('_set_mirror'):
196+
if latest_portrait and latest_portrait.has_method("_set_mirror"):
173197
var character: DialogicCharacter = character_node.get_meta('character')
174198
var current_portrait_info := character.get_portrait_info(character_node.get_meta('portrait'))
175199
latest_portrait._set_mirror(force or (mirrored != character.mirror != character_node.get_parent().mirrored != current_portrait_info.get('mirror', false)))
176200

177201

178202
func _change_portrait_extradata(character_node: Node2D, extra_data := "") -> void:
179-
var latest_portrait := character_node.get_child(-1)
203+
if not is_instance_valid(character_node):
204+
push_error("[Dialogic] Invalid character node provided.")
205+
return
180206

181-
if latest_portrait.has_method('_set_extra_data'):
182-
latest_portrait._set_extra_data(extra_data)
207+
if character_node.get_child_count() > 0:
208+
var latest_portrait := character_node.get_child(-1)
183209

210+
if latest_portrait and latest_portrait.has_method("_set_extra_data"):
211+
latest_portrait._set_extra_data(extra_data)
212+
else:
213+
push_warning("[Dialogic] No portrait found for character node: " + character_node.name)
184214

185215
func _update_character_transform(character_node:Node, time := 0.0) -> void:
186216
for child in character_node.get_children():
@@ -379,7 +409,7 @@ func join_character(character:DialogicCharacter, portrait:String, position_id:S
379409
return
380410

381411
var container := dialogic.PortraitContainers.add_container(character.get_character_name())
382-
var character_node := add_character(character, container, portrait, position_id)
412+
var character_node := await add_character(character, container, portrait, position_id)
383413
if character_node == null:
384414
return null
385415

@@ -410,9 +440,9 @@ func join_character(character:DialogicCharacter, portrait:String, position_id:S
410440
return character_node
411441

412442

413-
func add_character(character:DialogicCharacter, container: DialogicNode_PortraitContainer, portrait:String, position_id:String) -> Node:
443+
func add_character(character: DialogicCharacter, container: DialogicNode_PortraitContainer, portrait: String, position_id: String) -> Node:
414444
if is_character_joined(character):
415-
printerr('[DialogicError] Cannot add a already joined character. If this is intended call _create_character_node manually.')
445+
printerr('[DialogicError] Cannot add an already joined character. If this is intended, call _create_character_node manually.')
416446
return null
417447

418448
portrait = get_valid_portrait(character, portrait)
@@ -423,21 +453,31 @@ func add_character(character:DialogicCharacter, container: DialogicNode_Portrait
423453
if not character:
424454
printerr('[DialogicError] Cannot call add_portrait() with null character.')
425455
return null
456+
457+
ResourceLoader.load_threaded_request(character.resource_path)
458+
459+
var load_status = ResourceLoader.load_threaded_get_status(character.resource_path)
460+
while load_status == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
461+
await get_tree().process_frame
462+
load_status = ResourceLoader.load_threaded_get_status(character.resource_path)
426463

427-
var character_node := _create_character_node(character, container)
428-
429-
if character_node == null:
430-
printerr('[Dialogic] Failed to join character to position ', position_id, ". Could not find position container.")
431-
return null
432-
464+
if load_status == ResourceLoader.THREAD_LOAD_LOADED:
465+
character = ResourceLoader.load_threaded_get(character.resource_path)
466+
var character_node := _create_character_node(character, container)
433467

434-
dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_id':position_id}
468+
if character_node == null:
469+
printerr('[Dialogic] Failed to join character to position ', position_id, ". Could not find position container.")
470+
return null
435471

436-
_move_character(character_node, position_id)
437-
_change_portrait(character_node, portrait)
472+
dialogic.current_state_info['portraits'][character.resource_path] = {'portrait': portrait, 'node': character_node, 'position_id': position_id}
438473

439-
return character_node
474+
_move_character(character_node, position_id)
475+
await _change_portrait(character_node, portrait)
440476

477+
return character_node
478+
else:
479+
push_error('[Dialogic] Failed to load character "' + str(character.resource_path) + '".')
480+
return null
441481

442482
## Changes the portrait of a character. Only works with joined characters.
443483
func change_character_portrait(character: DialogicCharacter, portrait: String, fade_animation:="DEFAULT", fade_length := -1.0) -> void:
@@ -455,7 +495,7 @@ func change_character_portrait(character: DialogicCharacter, portrait: String, f
455495

456496
fade_animation = DialogicPortraitAnimationUtil.guess_animation(fade_animation, DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
457497

458-
var info := _change_portrait(dialogic.current_state_info.portraits[character.resource_path].node, portrait, fade_animation, fade_length)
498+
var info := await _change_portrait(dialogic.current_state_info.portraits[character.resource_path].node, portrait, fade_animation, fade_length)
459499
dialogic.current_state_info.portraits[character.resource_path].portrait = info.portrait
460500
_change_portrait_mirror(
461501
dialogic.current_state_info.portraits[character.resource_path].node,
@@ -629,7 +669,8 @@ func change_speaker(speaker: DialogicCharacter = null, portrait := "") -> void:
629669

630670
if leave_animation and leave_animation_length:
631671
var animate_out := _animate_node(character_node, leave_animation, leave_animation_length, 1, true)
632-
animate_out.finished.connect(character_node.queue_free)
672+
await animate_out.finished
673+
character_node.queue_free()
633674
else:
634675
character_node.get_parent().remove_child(character_node)
635676
character_node.queue_free()
@@ -640,7 +681,19 @@ func change_speaker(speaker: DialogicCharacter = null, portrait := "") -> void:
640681
continue
641682

642683
if just_joined:
643-
_create_character_node(speaker, container)
684+
ResourceLoader.load_threaded_request(speaker.resource_path)
685+
686+
var load_status = ResourceLoader.load_threaded_get_status(speaker.resource_path)
687+
while load_status == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
688+
await get_tree().process_frame
689+
load_status = ResourceLoader.load_threaded_get_status(speaker.resource_path)
690+
691+
if load_status == ResourceLoader.THREAD_LOAD_LOADED:
692+
speaker = ResourceLoader.load_threaded_get(speaker.resource_path)
693+
_create_character_node(speaker, container)
694+
else:
695+
push_error('[Dialogic] Failed to load speaker "' + str(speaker.resource_path) + '".')
696+
continue
644697

645698
elif portrait.is_empty():
646699
continue
@@ -655,10 +708,10 @@ func change_speaker(speaker: DialogicCharacter = null, portrait := "") -> void:
655708

656709
fade_animation = DialogicPortraitAnimationUtil.guess_animation(fade_animation, DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
657710

658-
if container.portrait_prefix+portrait in speaker.portraits:
659-
portrait = container.portrait_prefix+portrait
711+
if container.portrait_prefix + portrait in speaker.portraits:
712+
portrait = container.portrait_prefix + portrait
660713

661-
_change_portrait(character_node, portrait, fade_animation, fade_length)
714+
await _change_portrait(character_node, portrait, fade_animation, fade_length)
662715

663716
# if the character has no portraits _change_portrait won't actually add a child node
664717
if character_node.get_child_count() == 0:
@@ -677,7 +730,7 @@ func change_speaker(speaker: DialogicCharacter = null, portrait := "") -> void:
677730
var join_animation_length := _get_join_default_length()
678731

679732
if join_animation and join_animation_length:
680-
_animate_node(character_node, join_animation, join_animation_length)
733+
await _animate_node(character_node, join_animation, join_animation_length).finished
681734

682735
_change_portrait_mirror(character_node)
683736

0 commit comments

Comments
 (0)