@tool extends Node # Constants const TIMER_INTERVAL := 5.0 const TIMER_LOG_INTERVAL := 6 # 30秒打印一次 (6 * 5秒) const TIMER_EDITOR_LOG_INTERVAL := 120 # 编辑器中600秒打印一次 # Static config static var config: GlobalConfig: set = _set_config # Timer for tracking game time var timer := Timer.new() var _timer_tick_counter := 0 func _ready() -> void: _setup_timer() func _setup_timer() -> void: timer.wait_time = TIMER_INTERVAL timer.one_shot = false timer.timeout.connect(_on_timer_timeout) add_child(timer) timer.start() static func _set_config(val: GlobalConfig) -> void: config = val if not config or Engine.is_editor_hint(): return _apply_debug_mode() _apply_window_settings() _apply_audio_settings() _apply_locale_settings() static func _apply_debug_mode() -> void: if config.debug_mode: GlobalConfig.DEBUG = true print_rich("[color=orange]Debug mode enabled[/color]") static func _apply_window_settings() -> void: var window = Engine.get_main_loop().root.get_window() if config.window_fullscreen: window.mode = Window.MODE_EXCLUSIVE_FULLSCREEN else: window.mode = Window.MODE_WINDOWED window.always_on_top = config.window_top static func _apply_audio_settings() -> void: AudioServer.set_bus_volume_db( AudioServer.get_bus_index(GlobalConfig.BUS_MASTER), config.db_master ) AudioServer.set_bus_volume_db( AudioServer.get_bus_index(GlobalConfig.BUS_GAME_SFX), config.db_game_sfx ) AudioServer.set_bus_volume_db( AudioServer.get_bus_index(GlobalConfig.BUS_DIALOG), config.db_dialog ) prints( "config load volume_db settings (master, sfx, dialog): ", config.db_master, config.db_game_sfx, config.db_dialog ) static func _apply_locale_settings() -> void: var locale = config.get_locale() print("set language to: ", locale) TranslationServer.set_locale(locale) # -1 null; 0 zh; 1 en func update_locale(lang_id: int, caption_id: int) -> void: config.language = wrapi(lang_id, 0, GlobalConfig.LANGUAGE_OPTIONS.size()) var caption_options = GlobalConfig.CAPTION_OPTIONS_DICT.get(config.language, [""]) config.caption = wrapi(caption_id, 0, caption_options.size()) _apply_locale_settings() func get_locale_language_name() -> String: if config: return config.get_locale_language_name() return "" func get_locale_caption_name() -> String: if config: return config.get_locale_caption_name() return "" func _on_timer_timeout() -> void: var archive := ArchiveManager.archive if not archive or not config: return # Update game time archive.game_seconds += int(TIMER_INTERVAL) config.game_total_seconds += int(TIMER_INTERVAL) _timer_tick_counter += 1 # Check if should log if _should_log_game_info(): print_global_info() func _should_log_game_info() -> bool: # 30s 打印一次,无需首次打印 if _timer_tick_counter % TIMER_LOG_INTERVAL != 0: return false # editor 中 600s 打印一次 if Engine.is_editor_hint() and _timer_tick_counter % TIMER_EDITOR_LOG_INTERVAL != 0: return false return true func print_global_info() -> void: var archive := ArchiveManager.archive if not archive or not config: return var game_time_str = _format_game_time(archive.game_seconds) var tick_time_str = _format_tick_time() var round_info = _get_round_info() var scene_info = archive.current_scene prints( "[timemark]", Time.get_datetime_string_from_system(), round_info, scene_info, game_time_str + " " + tick_time_str ) static func _format_game_time(total_seconds: int) -> String: @warning_ignore("integer_division") var hours := total_seconds / 3600 @warning_ignore("integer_division") var minutes := (total_seconds % 3600) / 60 var seconds := total_seconds % 60 return "game:%d:%02d:%02d" % [hours, minutes, seconds] static func _get_round_info() -> String: # 0:未开始游戏;1:序章;2-5:一~四章;6:结尾 var chapter := EventManager.get_chapter_stage() return "r%d_c%d" % [config.game_rounds, chapter] @warning_ignore_start("integer_division") static func _format_tick_time() -> String: var ticks = Time.get_ticks_msec() var hours := ticks / 3600000 as int var minutes := (ticks % 3600000) / 60000 as int var seconds := (ticks % 60000) / 1000 as int var msec := ticks % 1000 as int return "tick:%d:%02d:%02d.%03d" % [hours, minutes, seconds, msec]