513 lines
20 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using UnityEngine;
public static class SettingsManager
{
public static event Action SettingsSaved;
private static string SettingsFileName = "settings.rr";
private static string SettingsPath => Application.persistentDataPath;
public static SettingsSchemeDTO currentSchemeDTO {get; private set;}
// Обновленный метод Initialize с обработкой ошибок загрузки
public static void Initialize(SettingsScheme defaultSchemeAsset)
{
LoadSettings(defaultSchemeAsset);
}
#region Load/Save/Restore
private static void LoadSettings(SettingsScheme defaultSchemeAsset)
{
try
{
if (defaultSchemeAsset == null)
{
Debug.LogError("Default scheme asset is null!");
return;
}
// Конвертируем дефолтную схему в DTO
var defaultDTO = defaultSchemeAsset.GetDTO();
if (defaultDTO == null)
{
Debug.LogError("Failed to convert default scheme to DTO!");
return;
}
SettingsSchemeDTO loadedDTO = null;
bool loadSuccess = false;
try
{
var loadResult = FileUtil.LoadJson<SettingsSchemeDTO>(SettingsFileName, SettingsPath);
Debug.Log(loadResult.Message);
if (loadResult.OK && loadResult.Data != null)
{
loadedDTO = loadResult.Data;
loadSuccess = true;
}
}
catch (Exception ex)
{
Debug.LogError($"Error loading settings file: {ex.Message}");
}
if (!loadSuccess || loadedDTO == null)
{
currentSchemeDTO = CloneSettingsScheme(defaultDTO);
Debug.Log("Загружена схема настроек по умолчанию (файл отсутствует или поврежден)");
SaveSettings();
return;
}
string defaultHash = defaultDTO.CalculateHash();
string loadedHash = loadedDTO.CalculateHash();
if (string.Compare(defaultHash, loadedHash, StringComparison.Ordinal) == 0)
{
currentSchemeDTO = loadedDTO;
Debug.Log("Загружена схема настроек из файла");
return;
}
// Хэши не совпадают - восстанавливаем совместимые настройки
Debug.Log("Обнаружено несоответствие схем. Выполняется восстановление настроек...");
currentSchemeDTO = RestoreSettings(defaultDTO, loadedDTO);
// Проверяем, что восстановление прошло успешно
if (currentSchemeDTO == null)
{
Debug.LogError("Restore settings failed! Using default settings.");
currentSchemeDTO = CloneSettingsScheme(defaultDTO);
}
SaveSettings();
}
catch (Exception ex)
{
Debug.LogError($"Critical error in Initialize: {ex.Message}\n{ex.StackTrace}");
// Последняя попытка - создать дефолтную схему
if (defaultSchemeAsset != null)
{
currentSchemeDTO = defaultSchemeAsset.GetDTO();
SaveSettings();
}
}
}
private static SettingsSchemeDTO RestoreSettings(SettingsSchemeDTO defaultDTO, SettingsSchemeDTO loadedDTO)
{
try
{
// Проверяем входные параметры
if (defaultDTO == null)
{
Debug.LogError("defaultDTO is null! Cannot restore settings.");
return null;
}
if (loadedDTO == null)
{
Debug.LogWarning("loadedDTO is null, using default settings");
return CloneSettingsScheme(defaultDTO);
}
// Проверяем, что у defaultDTO есть группы
if (defaultDTO.groups == null || defaultDTO.groups.Count == 0)
{
Debug.LogError("defaultDTO has no groups! Cannot restore settings.");
return CloneSettingsScheme(defaultDTO);
}
var restoredDTO = new SettingsSchemeDTO();
restoredDTO.groups = new List<SettingsGroupDTO>();
// Создаем словарь для быстрого поиска групп и настроек из загруженной схемы
var loadedGroupsMap = new Dictionary<string, SettingsGroupDTO>();
if (loadedDTO.groups != null)
{
foreach (var group in loadedDTO.groups)
{
if (group != null && !string.IsNullOrEmpty(group.Name))
{
// Если группа с таким именем уже есть, пропускаем дубликат
if (!loadedGroupsMap.ContainsKey(group.Name))
{
loadedGroupsMap[group.Name] = group;
}
else
{
Debug.LogWarning($"Duplicate group name found: {group.Name}, skipping duplicate");
}
}
}
}
// Проходим по каждой группе в дефолтной схеме
foreach (var defaultGroup in defaultDTO.groups)
{
if (defaultGroup == null)
{
Debug.LogWarning("Null group found in defaultDTO, skipping");
continue;
}
try
{
var restoredGroup = new SettingsGroupDTO();
restoredGroup.Name = defaultGroup.Name;
restoredGroup.IconPath = defaultGroup.IconPath;
restoredGroup.Settings = new List<SettingDTO>();
// Создаем словарь настроек загруженной группы (если она существует)
var loadedSettingsMap = new Dictionary<string, SettingDTO>();
if (loadedGroupsMap.TryGetValue(defaultGroup.Name, out var loadedGroup) && loadedGroup != null)
{
if (loadedGroup.Settings != null)
{
foreach (var setting in loadedGroup.Settings)
{
if (setting != null && !string.IsNullOrEmpty(setting.Id))
{
try
{
string settingHash = setting.GetStringForHash();
if (!loadedSettingsMap.ContainsKey(settingHash))
{
loadedSettingsMap[settingHash] = setting;
}
}
catch (Exception ex)
{
Debug.LogError($"Error calculating hash for setting {setting.Id}: {ex.Message}");
}
}
}
}
}
// Проходим по каждой настройке в дефолтной группе
if (defaultGroup.Settings != null)
{
foreach (var defaultSetting in defaultGroup.Settings)
{
if (defaultSetting == null)
{
Debug.LogWarning("Null setting found in default group, skipping");
continue;
}
try
{
string defaultSettingHash = defaultSetting.GetStringForHash();
SettingDTO finalSetting = null;
// Пытаемся найти совместимую настройку
if (loadedSettingsMap.TryGetValue(defaultSettingHash, out var compatibleSetting))
{
// Нашли - берем значение из загруженной настройки
finalSetting = CopySettingValue(compatibleSetting, defaultSetting);
Debug.Log($"Восстановлена настройка: {defaultSetting.Id} из группы {defaultGroup.Name}");
}
else
{
// Не нашли - берем значение по умолчанию
finalSetting = CopySettingStructure(defaultSetting);
Debug.Log($"Использовано значение по умолчанию для настройки: {defaultSetting.Id} из группы {defaultGroup.Name}");
}
if (finalSetting != null)
{
restoredGroup.Settings.Add(finalSetting);
}
}
catch (Exception ex)
{
Debug.LogError($"Error restoring setting {defaultSetting.Id} from group {defaultGroup.Name}: {ex.Message}");
// Добавляем настройку по умолчанию в случае ошибки
var fallbackSetting = CopySettingStructure(defaultSetting);
if (fallbackSetting != null)
{
restoredGroup.Settings.Add(fallbackSetting);
}
}
}
}
restoredDTO.groups.Add(restoredGroup);
}
catch (Exception ex)
{
Debug.LogError($"Error restoring group {defaultGroup.Name}: {ex.Message}");
// Пытаемся добавить группу с настройками по умолчанию
try
{
var fallbackGroup = CopyGroupStructure(defaultGroup);
if (fallbackGroup != null)
{
restoredDTO.groups.Add(fallbackGroup);
}
}
catch (Exception fallbackEx)
{
Debug.LogError($"Failed to create fallback group {defaultGroup.Name}: {fallbackEx.Message}");
}
}
}
// Проверяем, что у нас есть хотя бы одна группа
if (restoredDTO.groups == null || restoredDTO.groups.Count == 0)
{
Debug.LogError("Failed to restore any groups! Using default settings.");
return CloneSettingsScheme(defaultDTO);
}
Debug.Log($"Настройки восстановлены успешно. Групп: {restoredDTO.groups.Count}");
return restoredDTO;
}
catch (Exception ex)
{
Debug.LogError($"Critical error in RestoreSettings: {ex.Message}\n{ex.StackTrace}");
// В случае критической ошибки возвращаем копию дефолтной схемы
return CloneSettingsScheme(defaultDTO);
}
}
// Вспомогательный метод для создания глубокой копии схемы
private static SettingsSchemeDTO CloneSettingsScheme(SettingsSchemeDTO source)
{
if (source == null) return null;
try
{
var clone = new SettingsSchemeDTO();
clone.groups = new List<SettingsGroupDTO>();
if (source.groups != null)
{
foreach (var group in source.groups)
{
if (group != null)
{
var groupClone = CopyGroupStructure(group);
if (groupClone != null)
{
clone.groups.Add(groupClone);
}
}
}
}
return clone;
}
catch (Exception ex)
{
Debug.LogError($"Error cloning settings scheme: {ex.Message}");
return null;
}
}
// Вспомогательный метод для копирования группы
private static SettingsGroupDTO CopyGroupStructure(SettingsGroupDTO source)
{
if (source == null) return null;
try
{
var group = new SettingsGroupDTO();
group.Name = source.Name;
group.IconPath = source.IconPath;
group.Settings = new List<SettingDTO>();
if (source.Settings != null)
{
foreach (var setting in source.Settings)
{
if (setting != null)
{
var settingClone = CopySettingStructure(setting);
if (settingClone != null)
{
group.Settings.Add(settingClone);
}
}
}
}
return group;
}
catch (Exception ex)
{
Debug.LogError($"Error copying group {source?.Name}: {ex.Message}");
return null;
}
}
private static SettingDTO CopySettingValue(SettingDTO source, SettingDTO targetTemplate)
{
var newSetting = new SettingDTO();
// Копируем структуру из шаблона
newSetting.Type = targetTemplate.Type;
newSetting.Id = targetTemplate.Id;
newSetting.Alias = targetTemplate.Alias;
newSetting.Description = targetTemplate.Description;
newSetting.IntMin = targetTemplate.IntMin;
newSetting.IntMax = targetTemplate.IntMax;
newSetting.IntStep = targetTemplate.IntStep;
newSetting.FloatMin = targetTemplate.FloatMin;
newSetting.FloatMax = targetTemplate.FloatMax;
newSetting.FloatStep = targetTemplate.FloatStep;
if (targetTemplate.AllowedValues != null)
{
newSetting.AllowedValues = new List<string>(targetTemplate.AllowedValues);
}
// Копируем значение из source
switch (targetTemplate.Type)
{
case Setting.SettingType.Bool:
newSetting.BoolValue = source.BoolValue;
break;
case Setting.SettingType.Int:
newSetting.IntValue = Mathf.Clamp(source.IntValue, targetTemplate.IntMin, targetTemplate.IntMax);
break;
case Setting.SettingType.Float:
newSetting.FloatValue = Mathf.Clamp(source.FloatValue, targetTemplate.FloatMin, targetTemplate.FloatMax);
break;
case Setting.SettingType.String:
if (targetTemplate.AllowedValues != null && targetTemplate.AllowedValues.Contains(source.StringValue))
{
newSetting.StringValue = source.StringValue;
}
else
{
newSetting.StringValue = targetTemplate.StringValue;
}
break;
case Setting.SettingType.Signal:
newSetting.SignalValue = targetTemplate.SignalValue;
break;
}
return newSetting;
}
private static SettingDTO CopySettingStructure(SettingDTO template)
{
var newSetting = new SettingDTO();
newSetting.Type = template.Type;
newSetting.Id = template.Id;
newSetting.Alias = template.Alias;
newSetting.Description = template.Description;
newSetting.IntMin = template.IntMin;
newSetting.IntMax = template.IntMax;
newSetting.IntStep = template.IntStep;
newSetting.FloatMin = template.FloatMin;
newSetting.FloatMax = template.FloatMax;
newSetting.FloatStep = template.FloatStep;
newSetting.BoolValue = template.BoolValue;
newSetting.IntValue = template.IntValue;
newSetting.FloatValue = template.FloatValue;
newSetting.StringValue = template.StringValue;
newSetting.SignalValue = template.SignalValue;
if (template.AllowedValues != null)
{
newSetting.AllowedValues = new List<string>(template.AllowedValues);
}
return newSetting;
}
public static void SaveSettings()
{
if (currentSchemeDTO != null)
{
FileUtil.SaveJson(SettingsFileName, SettingsPath, currentSchemeDTO);
SettingsSaved?.Invoke();
Debug.Log("Настройки сохранены");
}
}
#endregion
#region Get Values
public static string GetString(string id, string defaultValue = "")
{
if (!IsInitialized()) return defaultValue;
var setting = FindSetting(id);
if (setting == null || setting.Type != Setting.SettingType.String) return defaultValue;
return setting.StringValue ?? defaultValue;
}
public static int GetInt(string id, int defaultValue = 0)
{
if (!IsInitialized()) return defaultValue;
var setting = FindSetting(id);
if (setting == null || setting.Type != Setting.SettingType.Int) return defaultValue;
return setting.IntValue;
}
public static float GetFloat(string id, float defaultValue = 0f)
{
if (!IsInitialized()) return defaultValue;
var setting = FindSetting(id);
if (setting == null || setting.Type != Setting.SettingType.Float) return defaultValue;
return setting.FloatValue;
}
public static bool GetBool(string id, bool defaultValue = false)
{
if (!IsInitialized()) return defaultValue;
var setting = FindSetting(id);
if (setting == null || setting.Type != Setting.SettingType.Bool) return defaultValue;
return setting.BoolValue;
}
#endregion
#region Private Helpers
private static bool IsInitialized()
{
if (currentSchemeDTO == null)
{
Debug.LogError("SettingsManager not initialized! Call Initialize() first.");
return false;
}
return true;
}
private static SettingDTO FindSetting(string id)
{
foreach (var group in currentSchemeDTO.groups)
{
if (group?.Settings == null) continue;
foreach (var setting in group.Settings)
{
if (setting != null && setting.Id == id)
{
return setting;
}
}
}
Debug.LogWarning($"Setting not found: {id}");
return null;
}
#endregion
}