Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- доработан flow призовой витрины и связанного UI: добавлены `PrizeStandButtonView` и `RulesPrizeListPage`, обновлены `PrizeStandController`, `PrizeStandPrize`, `PrizeStandModal`, `PrizeStandSettingsModal`, `LevelPrizeSettingsModal`, `QRCodeSettingsModal`, `BalanceDisplay`, `ButtonTextFocusColor` и связанные prefab'ы, чтобы улучшить настройку, навигацию, отображение кнопок и prize flow - расширена система настроек и сохранения значений: `OptionPicker` получил отдельный формат `ValueSelector`, обновлены `SettingsDatabase`, `SettingEntryDrawer`, `SettingUIItem`, `SettingsUIGenerator`, `ValueSelectorRow` и `MainSettingsDatabase.asset`, а сохранение option picker-значений, включая `gameplay.gameDifficulty`, исправлено и синхронизировано с остальными настройками - добавлены универсальные спавнеры сущностей: реализованы `EntitySpawner` и `EntitySpawnerManager` с поддержкой весов префабов, точек спавна, заполнения по проценту, ограничений на количество и автоспавна при инициализации - доработана логика игрового спавна и сложности: процент инициализационного спавна может зависеть от настройки `gameplay.gameDifficulty` с градациями 25/50/75/100, в одном цикле массового спавна повторно не используется та же точка, а gizmo спавнера теперь показывает только сами точки без линий - упрощена работа в редакторе Unity и добавлены editor-инструменты: в `GameManager` лицензия пропускается при запуске в `UNITY_EDITOR`, а `HierarchySelectionCounter`, `HierarchySelectionCountOverlay` и `HierarchyBulkRenamerWindow` добавляют подсчет выделения, realtime overlay в `SceneView` и массовое переименование объектов по правилам нумерации из Unity Project Settings - синхронизированы сцены, ресурсы и UI-ассеты под новый flow: обновлены `MainMenu`, `Level UI`, уровни `1-1` и `1-2`, строки настроек, кнопки, TMP/font assets, изображения UI, `prizes.json` и recovery-данные после правок интерфейса и логики - очищены и переразложены часть внешних и служебных ресурсов: удалён пакет `Lava_Flowing_Shader`, переименованы/заменены отдельные UI-prefab'ы и добавлены сопутствующие проектные артефакты, которые сейчас используются обновлённой конфигурацией проекта
252 lines
9.8 KiB
C#
252 lines
9.8 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace RR.Common.Settings
|
||
{
|
||
public enum SettingValueType
|
||
{
|
||
Bool,
|
||
Int,
|
||
Float,
|
||
String,
|
||
Button, // Кнопка - не хранит значение, только вызывает действие
|
||
OptionPicker // Выбор из списка опций (enum-like)
|
||
}
|
||
|
||
public enum ApplyTarget
|
||
{
|
||
None,
|
||
Audio // Применить к звуку через AudioManager (музыка или эффекты)
|
||
}
|
||
|
||
public enum AudioTargetType
|
||
{
|
||
Music, // Музыка
|
||
Sfx // Звуковые эффекты
|
||
}
|
||
|
||
public enum IntDisplayFormat
|
||
{
|
||
Slider, // Обычный слайдер
|
||
ValueSelector // Выбор значения (со стрелками или дропдауном)
|
||
}
|
||
|
||
public enum FloatDisplayFormat
|
||
{
|
||
Slider, // Обычный слайдер
|
||
ValueSelector // Выбор значения (со стрелками)
|
||
}
|
||
|
||
public enum OptionPickerDisplayFormat
|
||
{
|
||
Default, // Текущее поведение: dropdown или отдельный option picker prefab
|
||
ValueSelector // Выбор значения через тот же prefab, что и для Int/Float
|
||
}
|
||
|
||
[Serializable]
|
||
public struct SettingValue
|
||
{
|
||
public SettingValueType type;
|
||
public bool b;
|
||
public int i;
|
||
public float f;
|
||
public string s;
|
||
|
||
public static SettingValue Bool(bool v) => new() { type = SettingValueType.Bool, b = v };
|
||
public static SettingValue Int(int v) => new() { type = SettingValueType.Int, i = v };
|
||
public static SettingValue Float(float v) => new() { type = SettingValueType.Float, f = v };
|
||
public static SettingValue String(string v) => new() { type = SettingValueType.String, s = v };
|
||
public static SettingValue OptionPicker(int v) => new() { type = SettingValueType.OptionPicker, i = v };
|
||
|
||
/// <summary>
|
||
/// Создает компактную версию для сериализации (только нужные поля)
|
||
/// </summary>
|
||
public SettingValueCompact ToCompact()
|
||
{
|
||
return new SettingValueCompact
|
||
{
|
||
type = (int)type,
|
||
value = type switch
|
||
{
|
||
SettingValueType.Bool => b ? "1" : "0",
|
||
SettingValueType.Int => i.ToString(),
|
||
SettingValueType.OptionPicker => i.ToString(),
|
||
SettingValueType.Float => f.ToString("F6"),
|
||
SettingValueType.String => s ?? "",
|
||
_ => ""
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает SettingValue из компактной версии
|
||
/// </summary>
|
||
public static SettingValue FromCompact(SettingValueCompact compact)
|
||
{
|
||
var type = (SettingValueType)compact.type;
|
||
return type switch
|
||
{
|
||
SettingValueType.Bool => Bool(compact.value == "1"),
|
||
SettingValueType.Int => Int(int.TryParse(compact.value, out int i) ? i : 0),
|
||
SettingValueType.OptionPicker => OptionPicker(int.TryParse(compact.value, out int optionIndex) ? optionIndex : 0),
|
||
SettingValueType.Float => Float(float.TryParse(compact.value, out float f) ? f : 0f),
|
||
SettingValueType.String => String(compact.value ?? ""),
|
||
_ => default
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Компактная версия SettingValue для сериализации (экономит место в JSON)
|
||
/// </summary>
|
||
[Serializable]
|
||
public struct SettingValueCompact
|
||
{
|
||
public int type;
|
||
public string value;
|
||
}
|
||
|
||
[Serializable]
|
||
public class SettingEntry
|
||
{
|
||
public string key;
|
||
public string displayName;
|
||
[TextArea] public string description;
|
||
public string group = "General";
|
||
|
||
[Tooltip("Показывать ли настройку в UI меню настроек")]
|
||
public bool shownInSettings = true;
|
||
|
||
[Tooltip("Доступна ли настройка для изменения извне (через API/файл)")]
|
||
public bool exposed = false;
|
||
|
||
public SettingValueType valueType;
|
||
|
||
// Defaults
|
||
public bool defaultBool = true;
|
||
public int defaultInt = 0;
|
||
public float defaultFloat = 1f;
|
||
public string defaultString = "";
|
||
|
||
// Ranges (used for Int/Float)
|
||
public int minInt = 0;
|
||
public int maxInt = 10;
|
||
|
||
[Tooltip("Формат отображения для Int (слайдер или выбор значения)")]
|
||
public IntDisplayFormat intDisplayFormat = IntDisplayFormat.Slider;
|
||
|
||
[Tooltip("Шаг для выбора значения Int (используется только для ValueSelector)")]
|
||
public int intStep = 1;
|
||
|
||
public float minFloat = 0f;
|
||
public float maxFloat = 1f;
|
||
|
||
[Tooltip("Отображать float значение как проценты (0-100%)")]
|
||
public bool displayAsPercentage = false;
|
||
|
||
[Tooltip("Формат отображения для Float (слайдер или выбор значения)")]
|
||
public FloatDisplayFormat floatDisplayFormat = FloatDisplayFormat.Slider;
|
||
|
||
[Tooltip("Шаг для выбора значения Float (используется только для ValueSelector)")]
|
||
public float floatStep = 0.1f;
|
||
|
||
public ApplyTarget applyTarget = ApplyTarget.None;
|
||
|
||
// Audio params (используется только для ApplyTarget.Audio)
|
||
[Tooltip("Тип звука: музыка или звуковые эффекты")]
|
||
public AudioTargetType audioTargetType = AudioTargetType.Music;
|
||
|
||
// Button params (для типа Button)
|
||
[Tooltip("Текст на кнопке (если не задан displayName)")]
|
||
public string buttonText;
|
||
|
||
[Tooltip("Дополнительные данные для кнопки (URL, имя сцены и т.д.)")]
|
||
public string buttonData;
|
||
|
||
[Tooltip("Цвет кнопки")]
|
||
public Color buttonColor = Color.white;
|
||
|
||
[Tooltip("Текстура/спрайт кнопки")]
|
||
public Sprite buttonSprite;
|
||
|
||
// OptionPicker params (для типа OptionPicker)
|
||
[Tooltip("Список вариантов выбора")]
|
||
public List<string> options;
|
||
|
||
[Tooltip("Индекс варианта по умолчанию")]
|
||
public int defaultOptionIndex;
|
||
|
||
[Tooltip("Формат отображения для Option Picker")]
|
||
public OptionPickerDisplayFormat optionPickerDisplayFormat = OptionPickerDisplayFormat.Default;
|
||
|
||
public SettingValue DefaultValue => valueType switch
|
||
{
|
||
SettingValueType.Bool => SettingValue.Bool(defaultBool),
|
||
SettingValueType.Int => SettingValue.Int(defaultInt),
|
||
SettingValueType.Float => SettingValue.Float(defaultFloat),
|
||
SettingValueType.String => SettingValue.String(defaultString ?? ""),
|
||
SettingValueType.Button => default, // Кнопки не хранят значение
|
||
SettingValueType.OptionPicker => SettingValue.OptionPicker(options != null && options.Count > 0
|
||
? Mathf.Clamp(defaultOptionIndex, 0, options.Count - 1)
|
||
: 0),
|
||
_ => default
|
||
};
|
||
|
||
public SettingValue Sanitize(SettingValue v)
|
||
{
|
||
if (valueType == SettingValueType.OptionPicker)
|
||
{
|
||
if (v.type != SettingValueType.OptionPicker && v.type != SettingValueType.Int)
|
||
return DefaultValue;
|
||
}
|
||
else if (v.type != valueType)
|
||
{
|
||
return DefaultValue;
|
||
}
|
||
|
||
// защита от кривых min/max
|
||
int iMin = Mathf.Min(minInt, maxInt);
|
||
int iMax = Mathf.Max(minInt, maxInt);
|
||
float fMin = Mathf.Min(minFloat, maxFloat);
|
||
float fMax = Mathf.Max(minFloat, maxFloat);
|
||
|
||
return valueType switch
|
||
{
|
||
SettingValueType.Bool => SettingValue.Bool(v.b),
|
||
SettingValueType.Int => SettingValue.Int(Mathf.Clamp(v.i, iMin, iMax)),
|
||
SettingValueType.Float => SettingValue.Float(Mathf.Clamp(v.f, fMin, fMax)),
|
||
SettingValueType.String => SettingValue.String(v.s ?? ""),
|
||
SettingValueType.Button => default,
|
||
SettingValueType.OptionPicker => SettingValue.OptionPicker(options != null && options.Count > 0
|
||
? Mathf.Clamp(v.i, 0, options.Count - 1)
|
||
: 0),
|
||
_ => DefaultValue
|
||
};
|
||
}
|
||
}
|
||
|
||
[CreateAssetMenu(menuName = "Settings/Database")]
|
||
public class SettingsDatabase : ScriptableObject
|
||
{
|
||
public List<SettingEntry> entries = new();
|
||
|
||
public SettingEntry Find(string key)
|
||
=> entries.Find(e => string.Equals(e.key, key, StringComparison.Ordinal));
|
||
|
||
private void OnValidate()
|
||
{
|
||
var set = new HashSet<string>();
|
||
foreach (var e in entries)
|
||
{
|
||
if (e == null) continue;
|
||
|
||
if (string.IsNullOrWhiteSpace(e.key))
|
||
Debug.LogWarning($"[SettingsDatabase] Empty key in {name}", this);
|
||
else if (!set.Add(e.key))
|
||
Debug.LogWarning($"[SettingsDatabase] Duplicate key '{e.key}' in {name}", this);
|
||
}
|
||
}
|
||
}
|
||
}
|