class_name PRDConfigManager extends RefCounted ## Менеджер конфигурации для системы контроля ПРД. ## Загружает и управляет настройками из JSON-конфигурации. #region CONSTANTS const CONFIG_PATH = 'user://config/setting-prd-control.json' const DEFAULT_CONFIG_PATH = 'res://config/setting-prd-control.json' const CONFIG_VERSION = '1.0.0' # Версия конфигурации - увеличивать при изменениях #endregion #region PRIVATE_VARIABLES var _config_data: Dictionary ## Все данные конфигурации var _device_constants: Dictionary ## Константы устройств var _base_configs: Dictionary ## Базовые конфигурации var _device_configs: Dictionary ## Конфигурации устройств var _data_indices: Dictionary ## Индексы данных var _fs_keys: Dictionary ## Ключи ФС (функциональных систем) var _temperature_constants: Dictionary ## Константы температуры var _ems_input_bits_config: Dictionary ## Конфигурация битов ввода ЭМС var _fs_rules: Array ## Правила ФС var _is_loaded: bool = false ## Флаг успешной загрузки var _current_version: String ## Текущая версия загруженной конфигурации #endregion #region INITIALIZATION func _init() -> void: '''Инициализация менеджера конфигурации''' _load_configuration() #endregion #region PUBLIC_API ## Проверяет, успешно ли загружена конфигурация func is_loaded() -> bool: return _is_loaded ## Возвращает текущую версию загруженной конфигурации func get_config_version() -> String: return _current_version ## Проверяет, актуальна ли конфигурация func is_config_up_to_date() -> bool: return _current_version == CONFIG_VERSION ## Возвращает все данные конфигурации func get_config_data() -> Dictionary: return _config_data.duplicate(true) ## Возвращает константы устройств func get_device_constants() -> Dictionary: return _device_constants.duplicate(true) ## Возвращает базовые конфигурации func get_base_configs() -> Dictionary: return _base_configs.duplicate(true) ## Возвращает конфигурации устройств func get_device_configs() -> Dictionary: return _device_configs.duplicate(true) ## Возвращает индексы данных func get_data_indices() -> Dictionary: return _data_indices.duplicate(true) ## Возвращает ключи ФС func get_fs_keys() -> Dictionary: return _fs_keys.duplicate(true) ## Возвращает константы температуры func get_temperature_constants() -> Dictionary: return _temperature_constants.duplicate(true) ## Возвращает конфигурацию битов ввода ЭМС func get_ems_input_bits_config() -> Dictionary: return _ems_input_bits_config.duplicate(true) ## Возвращает правила ФС func get_fs_rules() -> Array: return _fs_rules.duplicate(true) ## Возвращает индекс данных по ключу func get_data_index(key: String) -> int: return _data_indices.get(key, -1) #endregion #region PRIVATE_METHODS ## Загружает конфигурацию из JSON файла func _load_configuration() -> void: if not _ensure_config_exists(): _is_loaded = false return var config_file = FileAccess.open(CONFIG_PATH, FileAccess.READ) if config_file: var json_text = config_file.get_as_text() config_file.close() var json = JSON.new() var parse_result = json.parse(json_text) if parse_result == OK: _config_data = json.data _current_version = _config_data.get('config_version', '0.0.0') _parse_config_data() _is_loaded = true else: push_error('Ошибка разбора JSON конфигурации: ' + json.get_error_message()) _is_loaded = false else: push_error('Ошибка загрузки файла конфигурации: ' + CONFIG_PATH) _is_loaded = false ## Парсит данные конфигурации по секциям func _parse_config_data() -> void: _device_constants = _convert_numbers(_config_data.get('device_constants', {})) _base_configs = _convert_numbers(_config_data.get('base_configs', {})) _device_configs = _convert_numbers(_config_data.get('device_configs', {})) _data_indices = _convert_numbers(_config_data.get('data_indices', {})) _fs_keys = _convert_numbers(_config_data.get('fs_keys', {})) _temperature_constants = _convert_numbers(_config_data.get('temperature_constants', {})) _ems_input_bits_config = _convert_numbers(_config_data.get('ems_input_bits_config', {})) _fs_rules = _convert_numbers(_config_data.get('fs_rules', [])) ## Конвертирует числовые значения в правильные типы (float -> int если возможно) static func _convert_numbers(value): if value is float: # Конвертируем float в int если нет дробной части if value == int(value): return int(value) return value elif value is Dictionary: var result = {} for key in value: result[key] = _convert_numbers(value[key]) return result elif value is Array: var result = [] for item in value: result.append(_convert_numbers(item)) return result else: return value ## Обеспечивает существование файла конфигурации ## Создает папку и копирует дефолтный файл если нужно func _ensure_config_exists() -> bool: # Создаем папку конфигурации если не существует DirAccess.make_dir_recursive_absolute('user://config') # Проверяем, нужно ли обновить конфигурацию if _should_update_config(): return _update_config() # Если файл уже существует - все ок if FileAccess.file_exists(CONFIG_PATH): return true # Если дефолтного файла нет - ошибка if not FileAccess.file_exists(DEFAULT_CONFIG_PATH): return false # Копируем дефолтный конфиг в user директорию return _copy_default_config() ## Проверяет, нужно ли обновить конфигурацию func _should_update_config() -> bool: # Если файла конфигурации нет - нужно создать if not FileAccess.file_exists(CONFIG_PATH): return true # Проверяем версию существующей конфигурации var config_file = FileAccess.open(CONFIG_PATH, FileAccess.READ) if config_file: var json_text = config_file.get_as_text() config_file.close() var json = JSON.new() if json.parse(json_text) == OK: var existing_version = json.data.get('config_version', '0.0.0') # Сравниваем версии return _compare_versions(existing_version, CONFIG_VERSION) < 0 else: # Если ошибка парсинга - нужно обновить return true return false ## Сравнивает две версии (semantic versioning) ## Возвращает -1 если version1 < version2, 0 если равны, 1 если version1 > version2 static func _compare_versions(version1: String, version2: String) -> int: var v1_parts = version1.split('.') var v2_parts = version2.split('.') for i in range(max(v1_parts.size(), v2_parts.size())): var v1_part = int(v1_parts[i]) if i < v1_parts.size() else 0 var v2_part = int(v2_parts[i]) if i < v2_parts.size() else 0 if v1_part < v2_part: return -1 elif v1_part > v2_part: return 1 return 0 ## Обновляет конфигурацию до актуальной версии func _update_config() -> bool: # Создаем резервную копию старой конфигурации if FileAccess.file_exists(CONFIG_PATH): var backup_path = CONFIG_PATH + '.backup_v' + _current_version DirAccess.copy_absolute(CONFIG_PATH, backup_path) # Копируем актуальную конфигурацию return _copy_default_config() ## Копирует дефолтную конфигурацию в user директорию func _copy_default_config() -> bool: if not FileAccess.file_exists(DEFAULT_CONFIG_PATH): push_error('Файл конфигурации не найден: ' + DEFAULT_CONFIG_PATH) return false var src := FileAccess.open(DEFAULT_CONFIG_PATH, FileAccess.READ) var dst := FileAccess.open(CONFIG_PATH, FileAccess.WRITE) if src == null or dst == null: push_error('Ошибка копирования конфигурации') return false dst.store_string(src.get_as_text()) src.close() dst.close() return true #endregion