755 lines
31 KiB
C#
755 lines
31 KiB
C#
using System.Collections;
|
|
using System.Linq;
|
|
using Core.SettingsSystem;
|
|
using Michsky.UI.Reach;
|
|
using UnityEngine;
|
|
using UI.PanelStack;
|
|
using Core.InputLock;
|
|
|
|
namespace UI.Settings
|
|
{
|
|
public class SettingsController : MonoBehaviour
|
|
{
|
|
private struct ResolutionOption
|
|
{
|
|
public int width;
|
|
public int height;
|
|
public int refreshRate;
|
|
}
|
|
|
|
[SerializeField] private bool debugLogs = true;
|
|
[Header("Root")]
|
|
[SerializeField] private GameObject rootObject;
|
|
[SerializeField] private PanelManager panelManager;
|
|
|
|
[Header("Hotkeys")]
|
|
[SerializeField] private HotkeyEvent escapeHotkey;
|
|
|
|
[Header("Buttons (Optional)")]
|
|
[SerializeField] private ButtonManager backButton;
|
|
[SerializeField] private ButtonManager applyButton;
|
|
[SerializeField] private ButtonManager resetButton;
|
|
|
|
[Header("Graphics - Dropdowns")]
|
|
[SerializeField] private Dropdown resolutionDropdown;
|
|
[SerializeField] private Dropdown displayModeDropdown;
|
|
[SerializeField] private Dropdown qualityDropdown;
|
|
[SerializeField] private Dropdown vSyncDropdown;
|
|
[SerializeField] private Dropdown msaaDropdown;
|
|
[SerializeField] private Dropdown textureQualityDropdown;
|
|
|
|
[Header("Graphics - Sliders")]
|
|
[SerializeField] private SliderManager targetFpsSlider;
|
|
[SerializeField] private SliderManager renderScaleSlider;
|
|
[SerializeField] private SliderManager shadowDistanceSlider;
|
|
|
|
[Header("Audio - Sliders")]
|
|
[SerializeField] private SliderManager masterVolumeSlider;
|
|
[SerializeField] private SliderManager musicVolumeSlider;
|
|
[SerializeField] private SliderManager sfxVolumeSlider;
|
|
|
|
[Header("Gameplay - Sliders")]
|
|
[SerializeField] private SliderManager mouseSensitivitySlider;
|
|
|
|
[Header("Gameplay - Dropdowns")]
|
|
[SerializeField] private Dropdown llmProviderDropdown;
|
|
|
|
[Header("Auto Initialize")]
|
|
[SerializeField] private bool initResolutionDropdown = true;
|
|
[SerializeField] private bool initQualityDropdown = true;
|
|
[SerializeField] private bool delayRefreshOneFrameOnEnable = true;
|
|
[SerializeField] private bool startHidden = true;
|
|
|
|
[Header("Dropdown Item Source")]
|
|
[SerializeField] private bool rebuildResolutionItems = true;
|
|
[SerializeField] private bool rebuildDisplayModeItems = true;
|
|
[SerializeField] private bool rebuildQualityItems = true;
|
|
[SerializeField] private bool rebuildVSyncItems = true;
|
|
[SerializeField] private bool rebuildMsaaItems = true;
|
|
[SerializeField] private bool rebuildTextureQualityItems = true;
|
|
[SerializeField] private bool rebuildLlmProviderItems = true;
|
|
|
|
[Header("Ranges")]
|
|
[SerializeField] private Vector2Int targetFpsRange = new Vector2Int(1, 240);
|
|
[SerializeField] private Vector2 renderScalePercentRange = new Vector2(0.1f, 200f);
|
|
[SerializeField] private Vector2 shadowDistanceRange = new Vector2(0f, 150f);
|
|
[SerializeField] private Vector2 sensitivityRange = new Vector2(0.1f, 10f);
|
|
|
|
private SettingsData applied;
|
|
private SettingsData working;
|
|
private bool isDirty;
|
|
private bool isWired;
|
|
private bool isPopulating;
|
|
private bool isClosing;
|
|
private ResolutionOption[] resolutionOptions = System.Array.Empty<ResolutionOption>();
|
|
|
|
private float RenderScalePercentMin => Mathf.Max(renderScalePercentRange.x, 10f);
|
|
private float RenderScalePercentMax => Mathf.Max(RenderScalePercentMin, renderScalePercentRange.y);
|
|
|
|
private void Awake()
|
|
{
|
|
WireOnce();
|
|
if (startHidden)
|
|
{
|
|
ShowRoot(false);
|
|
}
|
|
if (debugLogs) Debug.Log($"[SettingsController] Awake. startHidden={startHidden} rootActive={(rootObject!=null?rootObject.activeSelf:gameObject.activeSelf)}");
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
WireOnce();
|
|
ShowRoot(true);
|
|
if (delayRefreshOneFrameOnEnable) { StartCoroutine(RefreshNextFrame()); }
|
|
else { RefreshFromApplied(); }
|
|
}
|
|
|
|
private IEnumerator RefreshNextFrame()
|
|
{
|
|
yield return null;
|
|
RefreshFromApplied();
|
|
}
|
|
|
|
public void Show()
|
|
{
|
|
RefreshFromApplied();
|
|
ShowRoot(true);
|
|
if (panelManager != null) { panelManager.ShowCurrentPanel(); }
|
|
}
|
|
|
|
public void SetResolutionIndex(int index) { OnResolutionChanged(index); }
|
|
public void SetDisplayModeIndex(int index) { OnDisplayModeChanged(index); }
|
|
public void SetQualityIndex(int index) { OnQualityChanged(index); }
|
|
public void SetVSyncIndex(int index) { OnVSyncChanged(index); }
|
|
public void SetMsaaIndex(int index) { OnMsaaChanged(index); }
|
|
public void SetTextureQualityIndex(int index) { OnTextureQualityChanged(index); }
|
|
public void SetTargetFps(float value) { OnTargetFpsChanged(value); }
|
|
public void SetRenderScalePercent(float value) { OnRenderScalePercentChanged(value); }
|
|
public void SetShadowDistance(float value) { OnShadowDistanceChanged(value); }
|
|
public void SetMasterVolume(float value) { OnMasterChanged(value); }
|
|
public void SetMusicVolume(float value) { OnMusicChanged(value); }
|
|
public void SetSfxVolume(float value) { OnSfxChanged(value); }
|
|
public void SetMouseSensitivity(float value) { OnSensitivityChanged(value); }
|
|
public void SetLLMProviderIndex(int index) { OnLLMProviderChanged(index); }
|
|
|
|
public void CloseOrBack()
|
|
{
|
|
if (isClosing) { return; }
|
|
isClosing = true;
|
|
if (debugLogs) Debug.Log($"[SettingsController] CloseOrBack called. panelManagerActive={(panelManager!=null && panelManager.gameObject.activeInHierarchy)}");
|
|
|
|
if (isDirty)
|
|
{
|
|
working = Clone(applied);
|
|
PopulateUI(working);
|
|
isDirty = false;
|
|
}
|
|
|
|
if (UIPanelStack.Instance != null)
|
|
{
|
|
UIPanelStack.Instance.Remove(rootObject != null ? rootObject : gameObject);
|
|
}
|
|
|
|
if (PlayerControlLockService.Instance != null)
|
|
{
|
|
PlayerControlLockService.Instance.Unlock(this);
|
|
}
|
|
|
|
float delay = 0f;
|
|
if (panelManager != null && panelManager.isActiveAndEnabled && panelManager.gameObject.activeInHierarchy)
|
|
{
|
|
panelManager.HideCurrentPanel();
|
|
delay = panelManager.cachedStateLength * panelManager.animationSpeed;
|
|
}
|
|
|
|
if (rootObject != null) { StartCoroutine(HideAfter(delay)); }
|
|
else { StartCoroutine(HideAfter(delay)); }
|
|
}
|
|
|
|
public void OpenAtIndex(int index)
|
|
{
|
|
isClosing = false;
|
|
if (debugLogs) Debug.Log($"[SettingsController] OpenAtIndex({index}) called. panelManager={(panelManager!=null)}");
|
|
ShowRoot(true);
|
|
if (panelManager != null && !panelManager.gameObject.activeInHierarchy)
|
|
{
|
|
panelManager.gameObject.SetActive(true);
|
|
}
|
|
if (panelManager != null) { panelManager.OpenPanelByIndex(index); }
|
|
if (delayRefreshOneFrameOnEnable) { StartCoroutine(RefreshNextFrame()); }
|
|
else { RefreshFromApplied(); }
|
|
if (UIPanelStack.Instance != null) { UIPanelStack.Instance.Push(UIPanelKind.Settings, rootObject != null ? rootObject : gameObject, CloseOrBack); }
|
|
|
|
if (PlayerControlLockService.Instance != null)
|
|
{
|
|
PlayerControlLockService.Instance.Lock(this);
|
|
}
|
|
}
|
|
|
|
public void Apply()
|
|
{
|
|
SettingsService service = SettingsService.Instance;
|
|
if (service == null) { return; }
|
|
if (debugLogs) Debug.Log($"[SettingsController] Apply clicked. gameplay.mouseSensitivity={working?.gameplay?.mouseSensitivity}");
|
|
service.ApplyAndSave(Clone(working));
|
|
applied = Clone(service.Current);
|
|
isDirty = false;
|
|
}
|
|
|
|
public void ResetToDefaults()
|
|
{
|
|
working = SettingsData.Default();
|
|
PopulateUI(working);
|
|
isDirty = true;
|
|
}
|
|
|
|
private IEnumerator HideAfter(float seconds)
|
|
{
|
|
if (seconds > 0f) { yield return new WaitForSecondsRealtime(seconds); }
|
|
ShowRoot(false);
|
|
isClosing = false;
|
|
}
|
|
|
|
private void ShowRoot(bool show)
|
|
{
|
|
if (rootObject != null) { rootObject.SetActive(show); }
|
|
else { gameObject.SetActive(show); }
|
|
if (debugLogs) Debug.Log($"[SettingsController] ShowRoot({show}).");
|
|
}
|
|
|
|
private void RefreshFromApplied()
|
|
{
|
|
SettingsService service = SettingsService.Instance;
|
|
applied = service != null ? Clone(service.Current) : SettingsData.Default();
|
|
working = Clone(applied);
|
|
EnsureDropdownItems();
|
|
ApplyRanges();
|
|
PopulateUI(working);
|
|
isDirty = false;
|
|
}
|
|
|
|
private void WireOnce()
|
|
{
|
|
if (isWired) { return; }
|
|
|
|
if (escapeHotkey != null) { escapeHotkey.onHotkeyPress.AddListener(CloseOrBack); }
|
|
if (backButton != null) { backButton.onClick.AddListener(CloseOrBack); }
|
|
if (applyButton != null) { applyButton.onClick.AddListener(Apply); }
|
|
if (resetButton != null) { resetButton.onClick.AddListener(ResetToDefaults); }
|
|
|
|
if (resolutionDropdown != null) { resolutionDropdown.onValueChanged.AddListener(OnResolutionChanged); }
|
|
if (displayModeDropdown != null) { displayModeDropdown.onValueChanged.AddListener(OnDisplayModeChanged); }
|
|
if (qualityDropdown != null) { qualityDropdown.onValueChanged.AddListener(OnQualityChanged); }
|
|
if (vSyncDropdown != null) { vSyncDropdown.onValueChanged.AddListener(OnVSyncChanged); }
|
|
if (msaaDropdown != null) { msaaDropdown.onValueChanged.AddListener(OnMsaaChanged); }
|
|
if (textureQualityDropdown != null) { textureQualityDropdown.onValueChanged.AddListener(OnTextureQualityChanged); }
|
|
|
|
if (targetFpsSlider != null) { targetFpsSlider.onValueChanged.AddListener(OnTargetFpsChanged); }
|
|
if (renderScaleSlider != null) { renderScaleSlider.onValueChanged.AddListener(OnRenderScalePercentChanged); }
|
|
if (shadowDistanceSlider != null) { shadowDistanceSlider.onValueChanged.AddListener(OnShadowDistanceChanged); }
|
|
|
|
if (masterVolumeSlider != null) { masterVolumeSlider.onValueChanged.AddListener(OnMasterChanged); }
|
|
if (musicVolumeSlider != null) { musicVolumeSlider.onValueChanged.AddListener(OnMusicChanged); }
|
|
if (sfxVolumeSlider != null) { sfxVolumeSlider.onValueChanged.AddListener(OnSfxChanged); }
|
|
|
|
if (mouseSensitivitySlider != null) { mouseSensitivitySlider.onValueChanged.AddListener(OnSensitivityChanged); }
|
|
if (llmProviderDropdown != null) { llmProviderDropdown.onValueChanged.AddListener(OnLLMProviderChanged); }
|
|
|
|
isWired = true;
|
|
}
|
|
|
|
private void EnsureDropdownItems()
|
|
{
|
|
if (initResolutionDropdown && resolutionDropdown != null && (rebuildResolutionItems || resolutionDropdown.items == null || resolutionDropdown.items.Count == 0))
|
|
{
|
|
resolutionDropdown.items.Clear();
|
|
var resolutions = Screen.resolutions;
|
|
int currentWidth = Screen.width;
|
|
int currentHeight = Screen.height;
|
|
#if UNITY_2022_2_OR_NEWER
|
|
int currentRefresh = Mathf.RoundToInt((float)Screen.currentResolution.refreshRateRatio.value);
|
|
#else
|
|
int currentRefresh = Screen.currentResolution.refreshRate;
|
|
#endif
|
|
var grouped = resolutions
|
|
.GroupBy(r => new Vector2Int(r.width, r.height))
|
|
.Select(g =>
|
|
{
|
|
var list = g.ToArray();
|
|
int bestIndex = 0;
|
|
int bestRefresh = -1;
|
|
for (int i = 0; i < list.Length; i++)
|
|
{
|
|
#if UNITY_2022_2_OR_NEWER
|
|
int rr = Mathf.RoundToInt((float)list[i].refreshRateRatio.value);
|
|
#else
|
|
int rr = list[i].refreshRate;
|
|
#endif
|
|
bool prefer = rr == currentRefresh;
|
|
if (prefer)
|
|
{
|
|
bestIndex = i;
|
|
bestRefresh = rr;
|
|
break;
|
|
}
|
|
if (rr > bestRefresh)
|
|
{
|
|
bestIndex = i;
|
|
bestRefresh = rr;
|
|
}
|
|
}
|
|
var chosen = list[bestIndex];
|
|
return new ResolutionOption
|
|
{
|
|
width = chosen.width,
|
|
height = chosen.height,
|
|
refreshRate = Mathf.Max(0, bestRefresh)
|
|
};
|
|
})
|
|
.OrderBy(o => o.width)
|
|
.ThenBy(o => o.height)
|
|
.ToArray();
|
|
|
|
resolutionOptions = grouped;
|
|
int currentIndex = 0;
|
|
for (int i = 0; i < resolutionOptions.Length; i++)
|
|
{
|
|
var opt = resolutionOptions[i];
|
|
string label = opt.refreshRate > 0 ? $"{opt.width}x{opt.height} @ {opt.refreshRate}Hz" : $"{opt.width}x{opt.height}";
|
|
resolutionDropdown.CreateNewItem(label, false);
|
|
if (opt.width == currentWidth && opt.height == currentHeight) { currentIndex = i; }
|
|
}
|
|
resolutionDropdown.selectedItemIndex = Mathf.Clamp(currentIndex, 0, Mathf.Max(0, resolutionDropdown.items.Count - 1));
|
|
resolutionDropdown.Initialize();
|
|
}
|
|
else if (resolutionDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(resolutionDropdown);
|
|
}
|
|
|
|
if (displayModeDropdown != null && (rebuildDisplayModeItems || displayModeDropdown.items == null || displayModeDropdown.items.Count == 0))
|
|
{
|
|
displayModeDropdown.items.Clear();
|
|
displayModeDropdown.CreateNewItem("Fullscreen", false);
|
|
displayModeDropdown.CreateNewItem("Borderless", false);
|
|
displayModeDropdown.CreateNewItem("Windowed", false);
|
|
displayModeDropdown.Initialize();
|
|
}
|
|
else if (displayModeDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(displayModeDropdown);
|
|
}
|
|
|
|
if (initQualityDropdown && qualityDropdown != null && (rebuildQualityItems || qualityDropdown.items == null || qualityDropdown.items.Count == 0))
|
|
{
|
|
qualityDropdown.items.Clear();
|
|
foreach (string q in QualitySettings.names) { qualityDropdown.CreateNewItem(q, false); }
|
|
qualityDropdown.Initialize();
|
|
}
|
|
else if (qualityDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(qualityDropdown);
|
|
}
|
|
|
|
if (vSyncDropdown != null && (rebuildVSyncItems || vSyncDropdown.items == null || vSyncDropdown.items.Count == 0))
|
|
{
|
|
vSyncDropdown.items.Clear();
|
|
vSyncDropdown.CreateNewItem("Off", false);
|
|
vSyncDropdown.CreateNewItem("On", false);
|
|
vSyncDropdown.Initialize();
|
|
}
|
|
else if (vSyncDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(vSyncDropdown);
|
|
}
|
|
|
|
if (msaaDropdown != null && (rebuildMsaaItems || msaaDropdown.items == null || msaaDropdown.items.Count == 0))
|
|
{
|
|
msaaDropdown.items.Clear();
|
|
msaaDropdown.CreateNewItem("Off", false);
|
|
msaaDropdown.CreateNewItem("2x", false);
|
|
msaaDropdown.CreateNewItem("4x", false);
|
|
msaaDropdown.CreateNewItem("8x", false);
|
|
msaaDropdown.Initialize();
|
|
}
|
|
else if (msaaDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(msaaDropdown);
|
|
}
|
|
|
|
if (textureQualityDropdown != null && (rebuildTextureQualityItems || textureQualityDropdown.items == null || textureQualityDropdown.items.Count == 0))
|
|
{
|
|
textureQualityDropdown.items.Clear();
|
|
textureQualityDropdown.CreateNewItem("Full", false);
|
|
textureQualityDropdown.CreateNewItem("Half", false);
|
|
textureQualityDropdown.CreateNewItem("Quarter", false);
|
|
textureQualityDropdown.CreateNewItem("Eighth", false);
|
|
textureQualityDropdown.Initialize();
|
|
}
|
|
else if (textureQualityDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(textureQualityDropdown);
|
|
}
|
|
|
|
if (llmProviderDropdown != null && (rebuildLlmProviderItems || llmProviderDropdown.items == null || llmProviderDropdown.items.Count == 0))
|
|
{
|
|
llmProviderDropdown.items.Clear();
|
|
llmProviderDropdown.CreateNewItem("DeepSeek", false);
|
|
llmProviderDropdown.CreateNewItem("Doubao", false);
|
|
llmProviderDropdown.Initialize();
|
|
}
|
|
else if (llmProviderDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(llmProviderDropdown);
|
|
}
|
|
}
|
|
|
|
private void EnsureDropdownInitialized(Dropdown dropdown)
|
|
{
|
|
if (dropdown.items == null || dropdown.items.Count == 0) { return; }
|
|
for (int i = 0; i < dropdown.items.Count; i++)
|
|
{
|
|
if (dropdown.items[i].itemButton == null)
|
|
{
|
|
dropdown.Initialize();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ApplyRanges()
|
|
{
|
|
if (targetFpsSlider != null && targetFpsSlider.mainSlider != null)
|
|
{
|
|
targetFpsSlider.mainSlider.minValue = targetFpsRange.x;
|
|
targetFpsSlider.mainSlider.maxValue = targetFpsRange.y;
|
|
targetFpsSlider.useRoundValue = true;
|
|
}
|
|
|
|
if (renderScaleSlider != null && renderScaleSlider.mainSlider != null)
|
|
{
|
|
renderScaleSlider.mainSlider.minValue = RenderScalePercentMin;
|
|
renderScaleSlider.mainSlider.maxValue = RenderScalePercentMax;
|
|
renderScaleSlider.usePercent = true;
|
|
renderScaleSlider.useRoundValue = true;
|
|
}
|
|
|
|
if (shadowDistanceSlider != null && shadowDistanceSlider.mainSlider != null)
|
|
{
|
|
shadowDistanceSlider.mainSlider.minValue = shadowDistanceRange.x;
|
|
shadowDistanceSlider.mainSlider.maxValue = shadowDistanceRange.y;
|
|
shadowDistanceSlider.useRoundValue = false;
|
|
}
|
|
|
|
if (masterVolumeSlider != null && masterVolumeSlider.mainSlider != null)
|
|
{
|
|
masterVolumeSlider.mainSlider.minValue = 0f;
|
|
masterVolumeSlider.mainSlider.maxValue = 1f;
|
|
masterVolumeSlider.usePercent = true;
|
|
}
|
|
|
|
if (musicVolumeSlider != null && musicVolumeSlider.mainSlider != null)
|
|
{
|
|
musicVolumeSlider.mainSlider.minValue = 0f;
|
|
musicVolumeSlider.mainSlider.maxValue = 1f;
|
|
musicVolumeSlider.usePercent = true;
|
|
}
|
|
|
|
if (sfxVolumeSlider != null && sfxVolumeSlider.mainSlider != null)
|
|
{
|
|
sfxVolumeSlider.mainSlider.minValue = 0f;
|
|
sfxVolumeSlider.mainSlider.maxValue = 1f;
|
|
sfxVolumeSlider.usePercent = true;
|
|
}
|
|
|
|
if (mouseSensitivitySlider != null && mouseSensitivitySlider.mainSlider != null)
|
|
{
|
|
mouseSensitivitySlider.mainSlider.minValue = sensitivityRange.x;
|
|
mouseSensitivitySlider.mainSlider.maxValue = sensitivityRange.y;
|
|
mouseSensitivitySlider.useRoundValue = false;
|
|
}
|
|
}
|
|
|
|
private void PopulateUI(SettingsData data)
|
|
{
|
|
if (data == null) { return; }
|
|
isPopulating = true;
|
|
|
|
if (resolutionDropdown != null)
|
|
{
|
|
int idx = -1;
|
|
if (data.graphics.resolutionWidth > 0 && data.graphics.resolutionHeight > 0 && resolutionOptions.Length > 0)
|
|
{
|
|
int best = -1;
|
|
int bestRefreshDiff = int.MaxValue;
|
|
for (int i = 0; i < resolutionOptions.Length; i++)
|
|
{
|
|
var opt = resolutionOptions[i];
|
|
if (opt.width != data.graphics.resolutionWidth || opt.height != data.graphics.resolutionHeight) { continue; }
|
|
if (data.graphics.resolutionRefreshRate > 0 && opt.refreshRate > 0)
|
|
{
|
|
int diff = Mathf.Abs(opt.refreshRate - data.graphics.resolutionRefreshRate);
|
|
if (diff < bestRefreshDiff) { bestRefreshDiff = diff; best = i; }
|
|
}
|
|
else
|
|
{
|
|
best = i;
|
|
break;
|
|
}
|
|
}
|
|
idx = best;
|
|
}
|
|
else if (data.graphics.resolutionIndex >= 0)
|
|
{
|
|
var resolutions = Screen.resolutions;
|
|
if (data.graphics.resolutionIndex >= 0 && data.graphics.resolutionIndex < resolutions.Length && resolutionOptions.Length > 0)
|
|
{
|
|
var r = resolutions[data.graphics.resolutionIndex];
|
|
for (int i = 0; i < resolutionOptions.Length; i++)
|
|
{
|
|
if (resolutionOptions[i].width == r.width && resolutionOptions[i].height == r.height) { idx = i; break; }
|
|
}
|
|
}
|
|
}
|
|
|
|
if (idx < 0) { idx = resolutionDropdown.selectedItemIndex; }
|
|
idx = Mathf.Clamp(idx, 0, Mathf.Max(0, resolutionDropdown.items.Count - 1));
|
|
EnsureDropdownInitialized(resolutionDropdown);
|
|
if (resolutionDropdown.items != null && resolutionDropdown.items.Count > 0) { resolutionDropdown.SetDropdownIndex(idx); }
|
|
}
|
|
|
|
if (displayModeDropdown != null)
|
|
{
|
|
int modeIndex = FullscreenModeToIndex(data.graphics.fullscreenMode);
|
|
EnsureDropdownInitialized(displayModeDropdown);
|
|
if (displayModeDropdown.items != null && displayModeDropdown.items.Count > 0) { displayModeDropdown.SetDropdownIndex(modeIndex); }
|
|
}
|
|
|
|
if (qualityDropdown != null)
|
|
{
|
|
int q = data.graphics.qualityLevel;
|
|
if (q < 0) { q = QualitySettings.GetQualityLevel(); }
|
|
q = Mathf.Clamp(q, 0, Mathf.Max(0, qualityDropdown.items.Count - 1));
|
|
EnsureDropdownInitialized(qualityDropdown);
|
|
if (qualityDropdown.items != null && qualityDropdown.items.Count > 0) { qualityDropdown.SetDropdownIndex(q); }
|
|
}
|
|
|
|
if (vSyncDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(vSyncDropdown);
|
|
if (vSyncDropdown.items != null && vSyncDropdown.items.Count > 0) { vSyncDropdown.SetDropdownIndex(data.graphics.vSync ? 1 : 0); }
|
|
}
|
|
|
|
if (msaaDropdown != null)
|
|
{
|
|
EnsureDropdownInitialized(msaaDropdown);
|
|
if (msaaDropdown.items != null && msaaDropdown.items.Count > 0) { msaaDropdown.SetDropdownIndex(MsaaToIndex(data.graphics.msaaSampleCount)); }
|
|
}
|
|
|
|
if (textureQualityDropdown != null)
|
|
{
|
|
int t = Mathf.Clamp(data.graphics.textureMipmapLimit, 0, 3);
|
|
EnsureDropdownInitialized(textureQualityDropdown);
|
|
if (textureQualityDropdown.items != null && textureQualityDropdown.items.Count > 0) { textureQualityDropdown.SetDropdownIndex(t); }
|
|
}
|
|
|
|
if (targetFpsSlider != null && targetFpsSlider.mainSlider != null)
|
|
{
|
|
float v = data.graphics.targetFps <= 0 ? 60 : data.graphics.targetFps;
|
|
targetFpsSlider.mainSlider.value = v;
|
|
}
|
|
|
|
if (renderScaleSlider != null && renderScaleSlider.mainSlider != null)
|
|
{
|
|
float percent = Mathf.Clamp(data.graphics.renderScale * 100f, RenderScalePercentMin, RenderScalePercentMax);
|
|
renderScaleSlider.mainSlider.value = percent;
|
|
}
|
|
|
|
if (shadowDistanceSlider != null && shadowDistanceSlider.mainSlider != null)
|
|
{
|
|
shadowDistanceSlider.mainSlider.value = Mathf.Clamp(data.graphics.shadowDistance, shadowDistanceRange.x, shadowDistanceRange.y);
|
|
}
|
|
|
|
if (masterVolumeSlider != null && masterVolumeSlider.mainSlider != null)
|
|
{
|
|
masterVolumeSlider.mainSlider.value = Mathf.Clamp01(data.audio.master);
|
|
}
|
|
|
|
if (musicVolumeSlider != null && musicVolumeSlider.mainSlider != null)
|
|
{
|
|
musicVolumeSlider.mainSlider.value = Mathf.Clamp01(data.audio.music);
|
|
}
|
|
|
|
if (sfxVolumeSlider != null && sfxVolumeSlider.mainSlider != null)
|
|
{
|
|
sfxVolumeSlider.mainSlider.value = Mathf.Clamp01(data.audio.sfx);
|
|
}
|
|
|
|
if (mouseSensitivitySlider != null && mouseSensitivitySlider.mainSlider != null)
|
|
{
|
|
mouseSensitivitySlider.mainSlider.value = Mathf.Clamp(data.gameplay.mouseSensitivity, sensitivityRange.x, sensitivityRange.y);
|
|
}
|
|
|
|
if (llmProviderDropdown != null)
|
|
{
|
|
int p = Mathf.Clamp(data.gameplay.llmProvider, 0, 1);
|
|
EnsureDropdownInitialized(llmProviderDropdown);
|
|
if (llmProviderDropdown.items != null && llmProviderDropdown.items.Count > 0) { llmProviderDropdown.SetDropdownIndex(p); }
|
|
}
|
|
|
|
isPopulating = false;
|
|
}
|
|
|
|
private int FullscreenModeToIndex(int fullscreenMode)
|
|
{
|
|
if (fullscreenMode == (int)FullScreenMode.ExclusiveFullScreen) { return 0; }
|
|
if (fullscreenMode == (int)FullScreenMode.FullScreenWindow) { return 1; }
|
|
return 2;
|
|
}
|
|
|
|
private int IndexToFullscreenMode(int index)
|
|
{
|
|
if (index == 0) { return (int)FullScreenMode.ExclusiveFullScreen; }
|
|
if (index == 1) { return (int)FullScreenMode.FullScreenWindow; }
|
|
return (int)FullScreenMode.Windowed;
|
|
}
|
|
|
|
private int MsaaToIndex(int msaa)
|
|
{
|
|
if (msaa >= 8) { return 3; }
|
|
if (msaa >= 4) { return 2; }
|
|
if (msaa >= 2) { return 1; }
|
|
return 0;
|
|
}
|
|
|
|
private int IndexToMsaa(int index)
|
|
{
|
|
if (index == 3) { return 8; }
|
|
if (index == 2) { return 4; }
|
|
if (index == 1) { return 2; }
|
|
return 1;
|
|
}
|
|
|
|
private void MarkDirty()
|
|
{
|
|
if (isPopulating) { return; }
|
|
isDirty = true;
|
|
}
|
|
|
|
private void OnResolutionChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.resolutionIndex = -1;
|
|
if (resolutionOptions != null && index >= 0 && index < resolutionOptions.Length)
|
|
{
|
|
var opt = resolutionOptions[index];
|
|
working.graphics.resolutionWidth = opt.width;
|
|
working.graphics.resolutionHeight = opt.height;
|
|
working.graphics.resolutionRefreshRate = opt.refreshRate;
|
|
}
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnDisplayModeChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.fullscreenMode = IndexToFullscreenMode(index);
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnQualityChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.qualityLevel = index;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnVSyncChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.vSync = index == 1;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnMsaaChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.msaaSampleCount = IndexToMsaa(index);
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnLLMProviderChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.gameplay.llmProvider = Mathf.Clamp(index, 0, 1);
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnTextureQualityChanged(int index)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.textureMipmapLimit = Mathf.Clamp(index, 0, 3);
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnTargetFpsChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
int fps = Mathf.RoundToInt(value);
|
|
working.graphics.targetFps = fps;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnRenderScalePercentChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.renderScale = Mathf.Clamp(value, RenderScalePercentMin, RenderScalePercentMax) / 100f;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnShadowDistanceChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
working.graphics.shadowDistance = value;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnMasterChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
working.audio.master = value;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnMusicChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
working.audio.music = value;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnSfxChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
working.audio.sfx = value;
|
|
MarkDirty();
|
|
}
|
|
|
|
private void OnSensitivityChanged(float value)
|
|
{
|
|
if (working == null) { return; }
|
|
working.gameplay.mouseSensitivity = value;
|
|
if (debugLogs) Debug.Log($"[SettingsController] Sensitivity changed -> {value}");
|
|
MarkDirty();
|
|
}
|
|
|
|
private SettingsData Clone(SettingsData data)
|
|
{
|
|
if (data == null) { return SettingsData.Default(); }
|
|
string json = JsonUtility.ToJson(data);
|
|
SettingsData copy = JsonUtility.FromJson<SettingsData>(json);
|
|
return copy ?? SettingsData.Default();
|
|
}
|
|
}
|
|
}
|