diff --git a/godot_project/export_presets.cfg b/godot_project/export_presets.cfg index 5a3d745d9..458c985f0 100644 --- a/godot_project/export_presets.cfg +++ b/godot_project/export_presets.cfg @@ -45,8 +45,8 @@ application/product_name="" application/file_description="" application/copyright="" application/trademarks="" -application/export_angle=0 -application/export_d3d12=0 +application/export_angle=2 +application/export_d3d12=1 application/d3d12_agility_sdk_multiarch=true ssh_remote_deploy/enabled=false ssh_remote_deploy/host="user@host_ip" diff --git a/godot_project/scripts/autoload/scene_transition_manager.gd b/godot_project/scripts/autoload/scene_transition_manager.gd index ca8653ea3..780fb4f86 100644 --- a/godot_project/scripts/autoload/scene_transition_manager.gd +++ b/godot_project/scripts/autoload/scene_transition_manager.gd @@ -20,30 +20,44 @@ func _ready(): canvas_layer.add_child(fade_rect) -# Transition to a new scene with fade +# Transition to a new scene with fade (uses threaded loading to prevent main thread hangs) func transition_to_scene(scene_path: String): # Fade out var fade_tween = create_tween() fade_tween.tween_property(fade_rect, "color", Color(0, 0, 0, 1), 0.5) await fade_tween.finished - # Load new scene - if scene_path.ends_with(".tscn"): - # Direct scene change - get_tree().change_scene_to_file(scene_path) + # Start threaded scene load to prevent main thread blocking + var err = ResourceLoader.load_threaded_request(scene_path) + if err == OK: + # Wait for load to complete with timeout to prevent infinite hang + var timeout: float = 30.0 + var elapsed: float = 0.0 + while elapsed < timeout: + var status = ResourceLoader.load_threaded_get_status(scene_path) + if status == ResourceLoader.THREAD_LOAD_LOADED: + var scene_resource = ResourceLoader.load_threaded_get(scene_path) + var new_scene = scene_resource.instantiate() + var root = get_tree().root + var current_scene = get_tree().current_scene + if current_scene: + root.remove_child(current_scene) + current_scene.queue_free() + root.add_child(new_scene) + get_tree().current_scene = new_scene + break + elif status == ResourceLoader.THREAD_LOAD_FAILED or status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: + push_error("Failed to load scene: " + scene_path + ", using fallback") + get_tree().change_scene_to_file(scene_path) + break + await get_tree().create_timer(0.016).timeout + elapsed += 0.016 + if elapsed >= timeout: + push_error("Scene load timeout after 30s, using fallback: " + scene_path) + get_tree().change_scene_to_file(scene_path) else: - # Try to use instantiated PackedScene - var new_scene = load(scene_path).instantiate() - - # Get the current scene and replace it - var root = get_tree().root - var current_scene = get_tree().current_scene - - root.remove_child(current_scene) - current_scene.queue_free() - - root.add_child(new_scene) - get_tree().current_scene = new_scene + # Fallback to direct scene change if threaded request fails + get_tree().change_scene_to_file(scene_path) # Fade back in fade_tween = create_tween() diff --git a/godot_project/scripts/systems/ShiftSummaryScreen.gd b/godot_project/scripts/systems/ShiftSummaryScreen.gd index 8b3197d1c..301cffca3 100644 --- a/godot_project/scripts/systems/ShiftSummaryScreen.gd +++ b/godot_project/scripts/systems/ShiftSummaryScreen.gd @@ -953,8 +953,10 @@ func transition_within_viewport(scene_path: String): tween.tween_property(fade_rect, "color", Color(0, 0, 0, 1), 0.5) await tween.finished - # Wait for threaded load to complete + # Wait for threaded load to complete with timeout to prevent infinite hang var scene_resource = null + var load_timeout: float = 30.0 # Maximum 30 seconds to load a scene + var load_elapsed: float = 0.0 while true: var status = ResourceLoader.load_threaded_get_status(scene_path) if status == ResourceLoader.THREAD_LOAD_LOADED: @@ -964,6 +966,18 @@ func transition_within_viewport(scene_path: String): push_error("Failed to load scene: " + scene_path) fade_rect.queue_free() return + elif status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: + push_error("Invalid resource while loading scene: " + scene_path) + fade_rect.queue_free() + get_tree().change_scene_to_file(scene_path) # Fallback to direct load + return + # Timeout check to prevent infinite hang + load_elapsed += 0.016 + if load_elapsed >= load_timeout: + push_error("Scene load timeout after " + str(load_timeout) + " seconds: " + scene_path) + fade_rect.queue_free() + get_tree().change_scene_to_file(scene_path) # Fallback to direct load + return # Small delay before checking again await get_tree().create_timer(0.016).timeout diff --git a/godot_project/scripts/utils/simple_scene_loader.gd b/godot_project/scripts/utils/simple_scene_loader.gd index 63ad19a1a..2a631db33 100644 --- a/godot_project/scripts/utils/simple_scene_loader.gd +++ b/godot_project/scripts/utils/simple_scene_loader.gd @@ -29,6 +29,8 @@ func load_scene(path: String, use_sub_threads: bool = false): func _thread_load(path, use_sub_threads): var loader = ResourceLoader.load_threaded_request(path, "", use_sub_threads) if loader == OK: + var timeout_ms: int = 60000 # 60 second timeout to prevent infinite hang + var elapsed_ms: int = 0 while true: var status = ResourceLoader.load_threaded_get_status(path) match status: @@ -41,8 +43,16 @@ func _thread_load(path, use_sub_threads): ResourceLoader.THREAD_LOAD_FAILED: call_deferred("_loading_failed") break + ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: + call_deferred("_loading_failed") + break ResourceLoader.THREAD_LOAD_IN_PROGRESS: OS.delay_msec(50) # Wait before checking again + elapsed_ms += 50 + if elapsed_ms >= timeout_ms: + push_error("Scene load timeout: " + path) + call_deferred("_loading_failed") + break func _loading_done():