using System; using System.Globalization; using UnityEngine; namespace DanroJump.Settings { /// /// Тип значения сервисной настройки. /// public enum ServiceSettingValueType { Bool, Int, Float, String, Button, Option } /// /// Универсальное значение сервисной настройки с явным типом. /// [Serializable] public struct ServiceSettingValue : IEquatable { /// /// Активный тип значения. /// public ServiceSettingValueType type; /// /// Значение для bool-настроек. /// public bool boolValue; /// /// Значение для int и option-настроек. /// public int intValue; /// /// Значение для float-настроек. /// public float floatValue; /// /// Значение для string-настроек. /// public string stringValue; /// /// Создает bool-значение. /// public static ServiceSettingValue Bool(bool value) { return new ServiceSettingValue { type = ServiceSettingValueType.Bool, boolValue = value }; } /// /// Создает int-значение. /// public static ServiceSettingValue Int(int value) { return new ServiceSettingValue { type = ServiceSettingValueType.Int, intValue = value }; } /// /// Создает float-значение. /// public static ServiceSettingValue Float(float value) { return new ServiceSettingValue { type = ServiceSettingValueType.Float, floatValue = value }; } /// /// Создает string-значение. /// public static ServiceSettingValue String(string value) { return new ServiceSettingValue { type = ServiceSettingValueType.String, stringValue = value ?? string.Empty }; } /// /// Создает marker-значение для кнопки действия. /// public static ServiceSettingValue Button() { return new ServiceSettingValue { type = ServiceSettingValueType.Button }; } /// /// Создает option-значение по индексу варианта. /// public static ServiceSettingValue Option(int optionIndex) { return new ServiceSettingValue { type = ServiceSettingValueType.Option, intValue = optionIndex }; } /// /// Упаковывает значение в компактный строковый формат для JSON. /// public ServiceSettingValueCompact ToCompact() { return new ServiceSettingValueCompact { type = (int)type, value = type switch { ServiceSettingValueType.Bool => boolValue ? "1" : "0", ServiceSettingValueType.Int => intValue.ToString(CultureInfo.InvariantCulture), ServiceSettingValueType.Float => floatValue.ToString("R", CultureInfo.InvariantCulture), ServiceSettingValueType.String => stringValue ?? string.Empty, ServiceSettingValueType.Button => string.Empty, ServiceSettingValueType.Option => intValue.ToString(CultureInfo.InvariantCulture), _ => string.Empty } }; } /// /// Восстанавливает typed-значение из компактного JSON-представления. /// public static ServiceSettingValue FromCompact(ServiceSettingValueCompact compact) { var valueType = Enum.IsDefined(typeof(ServiceSettingValueType), compact.type) ? (ServiceSettingValueType)compact.type : ServiceSettingValueType.String; return valueType switch { ServiceSettingValueType.Bool => Bool(compact.value == "1" || bool.TryParse(compact.value, out var boolValue) && boolValue), ServiceSettingValueType.Int => Int(ParseInt(compact.value)), ServiceSettingValueType.Float => Float(ParseFloat(compact.value)), ServiceSettingValueType.String => String(compact.value), ServiceSettingValueType.Button => Button(), ServiceSettingValueType.Option => Option(ParseInt(compact.value)), _ => String(compact.value) }; } /// /// Сравнивает значения настроек с учетом типа и приблизительного float-сравнения. /// public bool Equals(ServiceSettingValue other) { return type == other.type && boolValue == other.boolValue && intValue == other.intValue && Mathf.Approximately(floatValue, other.floatValue) && stringValue == other.stringValue; } /// /// Сравнивает значение с boxed-объектом. /// public override bool Equals(object obj) { return obj is ServiceSettingValue other && Equals(other); } /// /// Возвращает hash code для использования значения в словарях и наборах. /// public override int GetHashCode() { return HashCode.Combine(type, boolValue, intValue, floatValue, stringValue); } /// /// Возвращает строковое представление активного typed-значения. /// public override string ToString() { return type switch { ServiceSettingValueType.Bool => boolValue.ToString(), ServiceSettingValueType.Int => intValue.ToString(CultureInfo.InvariantCulture), ServiceSettingValueType.Float => floatValue.ToString(CultureInfo.InvariantCulture), ServiceSettingValueType.String => stringValue ?? string.Empty, ServiceSettingValueType.Button => string.Empty, ServiceSettingValueType.Option => intValue.ToString(CultureInfo.InvariantCulture), _ => string.Empty }; } /// /// Безопасно читает int из invariant-строки. /// private static int ParseInt(string value) { return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) ? result : 0; } /// /// Безопасно читает float из invariant-строки. /// private static float ParseFloat(string value) { return float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) ? result : 0f; } } /// /// Компактное сериализуемое представление значения настройки. /// [Serializable] public struct ServiceSettingValueCompact { /// /// Числовой код типа значения. /// public int type; /// /// Значение, упакованное в строку для JSON. /// public string value; } }