# Conflicts:
#	Fishing2.sln.DotSettings.user
#	UserSettings/EditorUserSettings.asset
This commit is contained in:
2025-05-30 20:39:20 +08:00
60 changed files with 1147 additions and 460 deletions

View File

@@ -2,12 +2,10 @@
namespace NBF
{
public abstract class BaseAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Field)]
public class InputIconAttribute : BaseAttribute
{
@@ -48,4 +46,15 @@ namespace NBF
Description = description;
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Class, AllowMultiple = true)]
public class SortAttribute : BaseAttribute
{
public int Sort;
public SortAttribute(int sort)
{
Sort = sort;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c12ca701ad9f433d9e6e7eaf04f507d0
timeCreated: 1748570535

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
namespace NBF.Setting
{
public interface IMultiOption : IOptionBase
{
List<string> GetOptionNames();
int GetIndex();
void SetIndex(int index);
string GetName();
}
public abstract class MultiOption<T> : OptionBase, IMultiOption
{
private int _index;
protected OptionTable<T> OptionTable = new OptionTable<T>();
/// <summary>
/// 默认值
/// </summary>
protected abstract T DefaultValue { get; }
protected override void OnLoad()
{
}
protected void AddOption(string name, T value)
{
OptionTable.Add(name, value);
}
public List<string> GetOptionNames() => OptionTable.GetNames();
public string GetName()
{
return OptionTable.GetName(_index);
}
public int GetIndex()
{
return _index;
}
public void SetIndex(int index)
{
_index = index;
}
protected void SelectOption(T value, int defaultIndex = 0)
{
SetIndex(TryGetIndex(value, out var index) ? index : defaultIndex);
}
protected void SelectOption(Predicate<T> predicate, int defaultIndex = 0)
{
SetIndex(TryGetIndex(predicate, out var index) ? index : defaultIndex);
}
protected bool TryGetIndex(T option, out int index)
{
return TryGetIndex(entry => entry.Equals(option), out index);
}
protected bool TryGetIndex(Predicate<T> predicate, out int index)
{
index = -1;
var entries = OptionTable.GetValues();
for (var i = 0; i < entries.Count; i++)
{
if (!predicate(entries[i])) continue;
index = i;
return true;
}
return false;
}
public T GetSelectedOption() => OptionTable.GetValue(_index);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5b25650e359243468131db1f9b951ae7
timeCreated: 1748571045

View File

@@ -0,0 +1,49 @@
namespace NBF.Setting
{
public interface IOptionBase
{
string Name { get; }
void Initialize();
void Apply();
}
public abstract class OptionBase : IOptionBase
{
protected string SaveKey => $"Setting_{Group}_{Name}";
public abstract string Name { get; }
/// <summary>
/// 所在组
/// </summary>
public abstract string Group { get; }
public void Initialize()
{
OnInitialize();
Load();
}
/// <summary>
/// 加载用户的设置
/// </summary>
public void Load()
{
OnLoad();
}
public void Apply()
{
OnApply();
}
protected abstract void OnInitialize();
protected abstract void OnApply();
protected abstract void OnReset();
protected abstract void OnLoad();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dd2d6f346b1145debf370bc3ac71bd7e
timeCreated: 1748570612

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
namespace NBF.Setting
{
public class OptionTable<T>
{
public struct OptionEntry
{
public string Name;
public T Value;
public OptionEntry(string name, T value)
{
this.Name = name;
this.Value = value;
}
}
List<OptionEntry> entries = new List<OptionEntry>();
public void Add(string name, T value)
{
entries.Add(new OptionEntry(name, value));
}
public List<string> GetNames() => entries.Select(x => x.Name).ToList();
public List<T> GetValues() => entries.Select(x => x.Value).ToList();
public T GetValue(int index) => entries[index].Value;
public string GetName(int index) => entries != null ? entries[index].Name : string.Empty;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a7241b5524db446eb4f73ae3a8d7b0ec
timeCreated: 1748571519

View File

@@ -0,0 +1,55 @@
namespace NBF.Setting
{
/// <summary>
/// 范围设置
/// </summary>
public abstract class RangeOption : OptionBase
{
private int _value;
public abstract int MinValue { get; }
public abstract int MaxValue { get; }
public int GetValue()
{
return _value;
}
public void SetValue(int value)
{
if (value > MaxValue) value = MaxValue;
else if (value < MinValue) value = MinValue;
_value = value;
}
protected override void OnLoad()
{
}
}
/// <summary>
/// 范围设置
/// </summary>
public abstract class RangeOptionFloat : OptionBase
{
private float _value;
public abstract float MinValue { get; }
public abstract float MaxValue { get; }
public float GetValue()
{
return _value;
}
public void SetValue(float value)
{
if (value > MaxValue) value = MaxValue;
else if (value < MinValue) value = MinValue;
_value = value;
}
protected override void OnLoad()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3531567c76fc48d5939644966fe22057
timeCreated: 1748572844

View File

@@ -0,0 +1,15 @@
namespace NBF.Setting
{
public abstract class ToggleOption : MultiOption<bool>
{
protected override void OnInitialize()
{
AddOption("Off", false);
AddOption("On", true);
SelectOption(DefaultValue);
}
public bool IsEnabled() => GetSelectedOption();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dbcf52430d8b483497f040fe7cbcfa62
timeCreated: 1748572278

View File

@@ -1,301 +0,0 @@
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace NBF
{
public class GameSettings : MonoService<GameSettings>
{
public enum QualityEnum
{
Low = 0,
Medium = 1,
High = 2,
Ultra = 3
}
public enum VSyncEnum
{
Off = 0,
On = 1,
}
/// <summary>
/// 抗锯齿等级
/// </summary>
public enum AntiAliasLevelEnum
{
Off = 1,
x2 = 2,
x4 = 4,
x8 = 8
}
/// <summary>
/// 贴图质量
/// </summary>
public enum TextureQualityEnum
{
FullRes = 0,
HalfRes = 1,
QuarterRes = 2,
EighthRes = 3
}
public enum AnisotropicLevelEnum
{
Off = -1,
x2 = 2,
x4 = 4,
x8 = 8,
x16 = 16
}
public enum ShadowmapResolutionEnum
{
Low = 0,
Medium = 1,
High = 2,
}
public const string SaveKey = "PlayerGameSetting";
[System.Serializable]
public class GameSettingsData
{
/// <summary>
/// 质量等级 0 1 2 3
/// </summary>
// [Title("Settings_Title_quality")] [Description("Settings_Description_quality")]
[Title("图像质量")] [Description("图像质量324234图像质量图像质量图像质量图像质量3434")]
public QualityEnum QualityLevel = QualityEnum.High;
/// <summary>
/// 显示分辨率有任意一个为0则为全屏
/// </summary>
[Title("Settings_Title_Resolution")] [Description("Settings_Description_Resolution")]
public Vector2Int Resolution = new Vector2Int(0, 0);
/// <summary>
/// 渲染比例
/// </summary>
[Title("Settings_Title_RenderScale")] [Description("Settings_Description_RenderScale")] [Range(0.1f, 2f)]
public float RenderScale = 1f;
/// <summary>
/// 窗口模式
/// </summary>
[Title("Settings_Title_WindowedMode")] [Description("Settings_Description_WindowedMode")]
public FullScreenMode WindowedMode = FullScreenMode.MaximizedWindow;
/// <summary>
/// 垂直同步个数
/// </summary>
[Title("Settings_Title_VSync")] [Description("Settings_Description_VSync")]
public VSyncEnum VSync = VSyncEnum.Off;
/// <summary>
///抗锯齿等级
/// </summary>
[Title("Settings_Title_AntiAliasLevel")] [Description("Settings_Description_AntiAliasLevel")]
public AntiAliasLevelEnum AntiAliasLevel = AntiAliasLevelEnum.Off;
/// <summary>
/// 纹理质量
/// </summary>
[Title("Settings_Title_TextureQuality")] [Description("Settings_Description_TextureQuality")]
public TextureQualityEnum TextureQuality = TextureQualityEnum.FullRes;
/// <summary>
/// 全局各向异性纹理过滤模式
/// </summary>
[Title("Settings_Title_AnisotropicMode")] [Description("Settings_Description_AnisotropicMode")]
public AnisotropicFiltering AnisotropicMode = AnisotropicFiltering.Enable;
/// <summary>
/// 全局各向异性过滤限制
/// </summary>
[Title("Settings_Description_AnisotropicLevel")] [Description("Settings_Description_AnisotropicLevel")]
public AnisotropicLevelEnum AnisotropicLevel = AnisotropicLevelEnum.x4;
/// <summary>
/// 阴影等级
/// </summary>
[Title("Settings_Description_ShadowmapResolution")]
[Description("Settings_Description_ShadowmapResolution")]
public ShadowmapResolutionEnum ShadowmapResolution = ShadowmapResolutionEnum.High;
}
/// <summary>
/// 默认配置
/// </summary>
private GameSettingsData DefaultSettingsConverted = new GameSettingsData();
/// <summary>
/// 当前正在调整的配置
/// </summary>
private GameSettingsData CurrentSettings = new GameSettingsData();
/// <summary>
/// 当前使用配置
/// </summary>
public readonly GameSettingsData UseSettings = new GameSettingsData();
protected override void OnAwake()
{
LoadSettings();
}
/// <summary>
/// 重置
/// </summary>
public void ResetSettings()
{
CurrentSettings.QualityLevel = DefaultSettingsConverted.QualityLevel;
CurrentSettings.Resolution = DefaultSettingsConverted.Resolution;
CurrentSettings.RenderScale = DefaultSettingsConverted.RenderScale;
CurrentSettings.WindowedMode = DefaultSettingsConverted.WindowedMode;
CurrentSettings.VSync = DefaultSettingsConverted.VSync;
CurrentSettings.AntiAliasLevel = DefaultSettingsConverted.AntiAliasLevel;
CurrentSettings.TextureQuality = DefaultSettingsConverted.TextureQuality;
CurrentSettings.AnisotropicMode = DefaultSettingsConverted.AnisotropicMode;
CurrentSettings.AnisotropicLevel = DefaultSettingsConverted.AnisotropicLevel;
CurrentSettings.ShadowmapResolution = DefaultSettingsConverted.ShadowmapResolution;
}
/// <summary>
/// 开始进入设置模式,将当前使用的配置缓存一份
/// </summary>
public void BeginChangeSettings()
{
UseSettings.QualityLevel = CurrentSettings.QualityLevel;
UseSettings.Resolution = CurrentSettings.Resolution;
UseSettings.RenderScale = CurrentSettings.RenderScale;
UseSettings.WindowedMode = CurrentSettings.WindowedMode;
UseSettings.VSync = CurrentSettings.VSync;
UseSettings.AntiAliasLevel = CurrentSettings.AntiAliasLevel;
UseSettings.TextureQuality = CurrentSettings.TextureQuality;
UseSettings.AnisotropicMode = CurrentSettings.AnisotropicMode;
UseSettings.AnisotropicLevel = CurrentSettings.AnisotropicLevel;
UseSettings.ShadowmapResolution = CurrentSettings.ShadowmapResolution;
}
/// <summary>
/// 保存设置
/// </summary>
public void SaveSettings()
{
CurrentSettings.QualityLevel = UseSettings.QualityLevel;
CurrentSettings.Resolution = UseSettings.Resolution;
CurrentSettings.RenderScale = UseSettings.RenderScale;
CurrentSettings.WindowedMode = UseSettings.WindowedMode;
CurrentSettings.VSync = UseSettings.VSync;
CurrentSettings.AntiAliasLevel = UseSettings.AntiAliasLevel;
CurrentSettings.TextureQuality = UseSettings.TextureQuality;
CurrentSettings.AnisotropicMode = UseSettings.AnisotropicMode;
CurrentSettings.AnisotropicLevel = UseSettings.AnisotropicLevel;
CurrentSettings.ShadowmapResolution = UseSettings.ShadowmapResolution;
var json = JsonConvert.SerializeObject(CurrentSettings);
PlayerPrefs.SetString(SaveKey, json);
}
private void LoadSettings()
{
ResetSettings();
if (PlayerPrefs.HasKey(SaveKey))
{
var json = PlayerPrefs.GetString(SaveKey, string.Empty);
if (!string.IsNullOrEmpty(json))
{
var settings = JsonConvert.DeserializeObject<GameSettingsData>(json);
if (settings != null)
{
CurrentSettings.QualityLevel = settings.QualityLevel;
CurrentSettings.Resolution = settings.Resolution;
CurrentSettings.RenderScale = settings.RenderScale;
CurrentSettings.WindowedMode = settings.WindowedMode;
CurrentSettings.VSync = settings.VSync;
CurrentSettings.AntiAliasLevel = settings.AntiAliasLevel;
CurrentSettings.TextureQuality = settings.TextureQuality;
CurrentSettings.AnisotropicMode = settings.AnisotropicMode;
CurrentSettings.AnisotropicLevel = settings.AnisotropicLevel;
CurrentSettings.ShadowmapResolution = settings.ShadowmapResolution;
}
}
}
if (CurrentSettings.Resolution.x < 1 || CurrentSettings.Resolution.y < 1)
{
CurrentSettings.WindowedMode = FullScreenMode.ExclusiveFullScreen;
CurrentSettings.Resolution = new Vector2Int(Screen.width, Screen.height);
}
ApplySettings();
}
/// <summary>
/// 应用设置
/// </summary>
private void ApplySettings()
{
// // 设置当前质量等级
QualitySettings.SetQualityLevel((int)CurrentSettings.QualityLevel);
switch (CurrentSettings.WindowedMode)
{
case FullScreenMode.ExclusiveFullScreen:
Screen.SetResolution(Screen.width, Screen.width, FullScreenMode.ExclusiveFullScreen);
break;
case FullScreenMode.FullScreenWindow:
Screen.SetResolution(CurrentSettings.Resolution.x, CurrentSettings.Resolution.y,
FullScreenMode.FullScreenWindow);
break;
case FullScreenMode.MaximizedWindow:
Screen.SetResolution(CurrentSettings.Resolution.x, CurrentSettings.Resolution.y,
FullScreenMode.MaximizedWindow);
break;
case FullScreenMode.Windowed:
Screen.SetResolution(CurrentSettings.Resolution.x, CurrentSettings.Resolution.y,
FullScreenMode.Windowed);
break;
default:
Screen.SetResolution(Screen.width, Screen.width, FullScreenMode.ExclusiveFullScreen);
break;
}
// 获取当前URP Asset
UniversalRenderPipelineAsset URPAsset =
QualitySettings.GetRenderPipelineAssetAt(QualitySettings.GetQualityLevel()) as
UniversalRenderPipelineAsset;
if (URPAsset)
{
//渲染比例
URPAsset.renderScale = CurrentSettings.RenderScale;
//抗锯齿等级
URPAsset.msaaSampleCount = (int)CurrentSettings.AntiAliasLevel;
URPAsset.supportsHDR = true;
//纹理质量
QualitySettings.globalTextureMipmapLimit = (int)CurrentSettings.TextureQuality;
QualitySettings.anisotropicFiltering = CurrentSettings.AnisotropicMode;
if (CurrentSettings.AnisotropicMode == AnisotropicFiltering.Disable ||
CurrentSettings.AnisotropicMode == AnisotropicFiltering.Enable)
{
Texture.SetGlobalAnisotropicFilteringLimits(-1, -1);
}
else if (CurrentSettings.AnisotropicMode == AnisotropicFiltering.ForceEnable)
{
Texture.SetGlobalAnisotropicFilteringLimits((int)CurrentSettings.AnisotropicLevel,
(int)CurrentSettings.AnisotropicLevel);
}
//垂直同步
QualitySettings.vSyncCount = (int)CurrentSettings.VSync;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b3f3e6458ad24086b8838b3750453007
timeCreated: 1748585143

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc7b116a771640d58d650ff79698f301
timeCreated: 1748589438

View File

@@ -0,0 +1,38 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace NBF.Setting
{
/// <summary>
/// 全局各向异性纹理过滤模式
/// </summary>
[Sort(7)]
public class AnisotropicModeSetting : MultiOption<AnisotropicFiltering>
{
public override string Name => "AnisotropicMode";
public override string Group => SettingsDef.Group.Graphic;
protected override AnisotropicFiltering DefaultValue => AnisotropicFiltering.Enable;
protected override void OnInitialize()
{
}
protected override void OnApply()
{
// 获取当前URP Asset
UniversalRenderPipelineAsset URPAsset =
QualitySettings.GetRenderPipelineAssetAt(QualitySettings.GetQualityLevel()) as
UniversalRenderPipelineAsset;
if (URPAsset)
{
//全局各向异性纹理过滤模式
QualitySettings.anisotropicFiltering = GetSelectedOption();
}
}
protected override void OnReset()
{
SelectOption(DefaultValue);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b96e677183324f5d8d01e786a828c0db
timeCreated: 1748590207

View File

@@ -0,0 +1,31 @@
using UnityEngine;
namespace NBF.Setting
{
[Sort(1)]
public class FullScreenModeSetting : MultiOption<FullScreenMode>
{
public override string Name => "FullScreenMode";
public override string Group => SettingsDef.Group.Graphic;
protected override FullScreenMode DefaultValue => FullScreenMode.ExclusiveFullScreen;
protected override void OnInitialize()
{
AddOption(nameof(FullScreenMode.ExclusiveFullScreen), FullScreenMode.ExclusiveFullScreen);
AddOption(nameof(FullScreenMode.Windowed), FullScreenMode.Windowed);
AddOption(nameof(FullScreenMode.FullScreenWindow), FullScreenMode.FullScreenWindow);
AddOption(nameof(FullScreenMode.MaximizedWindow), FullScreenMode.MaximizedWindow);
SelectOption(DefaultValue);
}
protected override void OnApply()
{
Screen.fullScreenMode = GetSelectedOption();
}
protected override void OnReset()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3a6386dea2d44f3fb004905e688b97d5
timeCreated: 1748588770

View File

@@ -0,0 +1,57 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace NBF.Setting
{
public enum AnisotropicLevelEnum
{
Off = -1,
x2 = 2,
x4 = 4,
x8 = 8,
x16 = 16
}
/// <summary>
/// 全局各向异性过滤限制
/// </summary>
[Sort(8)]
public class GlobalAnisotropicFilteringLimitsSetting : MultiOption<AnisotropicLevelEnum>
{
public override string Name => "GlobalAnisotropicFilteringLimits";
public override string Group => SettingsDef.Group.Graphic;
protected override AnisotropicLevelEnum DefaultValue => AnisotropicLevelEnum.x4;
protected override void OnInitialize()
{
}
protected override void OnApply()
{
// 获取当前URP Asset
UniversalRenderPipelineAsset URPAsset =
QualitySettings.GetRenderPipelineAssetAt(QualitySettings.GetQualityLevel()) as
UniversalRenderPipelineAsset;
if (URPAsset)
{
var current = QualitySettings.anisotropicFiltering;
var level = GetSelectedOption();
if (current == AnisotropicFiltering.Disable ||
current == AnisotropicFiltering.Enable)
{
Texture.SetGlobalAnisotropicFilteringLimits(-1, -1);
}
else if (current == AnisotropicFiltering.ForceEnable)
{
Texture.SetGlobalAnisotropicFilteringLimits((int)level, (int)level);
}
}
}
protected override void OnReset()
{
SelectOption(DefaultValue);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6937878e8f61426687c62e26252e9258
timeCreated: 1748590403

View File

@@ -0,0 +1,43 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace NBF.Setting
{
public enum MsaaSampleEnum
{
Off = 1,
x2 = 2,
x4 = 4,
x8 = 8
}
[Sort(6)]
public class MsaaSampleSetting : MultiOption<MsaaSampleEnum>
{
public override string Name => "MsaaSample";
public override string Group => SettingsDef.Group.Graphic;
protected override MsaaSampleEnum DefaultValue => MsaaSampleEnum.Off;
protected override void OnInitialize()
{
}
protected override void OnApply()
{
// 获取当前URP Asset
UniversalRenderPipelineAsset URPAsset =
QualitySettings.GetRenderPipelineAssetAt(QualitySettings.GetQualityLevel()) as
UniversalRenderPipelineAsset;
if (URPAsset)
{
//抗锯齿等级
URPAsset.msaaSampleCount = (int)GetSelectedOption();
URPAsset.supportsHDR = true;
}
}
protected override void OnReset()
{
SelectOption(DefaultValue);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ae51922900c9429cb0de97b473a3429e
timeCreated: 1748589774

View File

@@ -0,0 +1,39 @@
using UnityEngine;
namespace NBF.Setting
{
/// <summary>
/// 画质设置
/// </summary>
[Sort(3)]
public class QualityLevelSetting : MultiOption<int>
{
private int _defaultQualityLevel;
public override string Name => "QualityLevel";
public override string Group => SettingsDef.Group.Graphic;
protected override int DefaultValue => _defaultQualityLevel;
protected override void OnInitialize()
{
var names = QualitySettings.names;
for (int i = 0; i < names.Length; i++)
{
AddOption(names[i], i);
}
_defaultQualityLevel = QualitySettings.GetQualityLevel();
SetIndex(QualitySettings.GetQualityLevel());
}
protected override void OnApply()
{
QualitySettings.SetQualityLevel(GetSelectedOption());
}
protected override void OnReset()
{
SetIndex(_defaultQualityLevel);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 470180f8a41b4856bf3318bc60f2abf1
timeCreated: 1748588124

View File

@@ -0,0 +1,37 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace NBF.Setting
{
[Sort(5)]
public class RenderScaleSetting : RangeOptionFloat
{
public override string Name => "RenderScale";
public override string Group => SettingsDef.Group.Graphic;
public override float MinValue => 0.1f;
public override float MaxValue => 2f;
protected override void OnInitialize()
{
}
protected override void OnApply()
{
// 获取当前URP Asset
UniversalRenderPipelineAsset URPAsset =
QualitySettings.GetRenderPipelineAssetAt(QualitySettings.GetQualityLevel()) as
UniversalRenderPipelineAsset;
if (URPAsset)
{
//渲染比例
URPAsset.renderScale = GetValue();
}
}
protected override void OnReset()
{
SetValue(1);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e54edac5d4fe4dbda2da5bce433482dc
timeCreated: 1748589449

View File

@@ -0,0 +1,65 @@
using UnityEngine;
namespace NBF.Setting
{
/// <summary>
/// 分辨率设置
/// </summary>
[Sort(2)]
public class ResolutionSetting : MultiOption<Resolution>
{
private Resolution _defaultResolution;
public override string Name => "Resolution";
public override string Group => SettingsDef.Group.Graphic;
protected override Resolution DefaultValue => _defaultResolution;
protected override void OnInitialize()
{
_defaultResolution = Screen.currentResolution;
var supportedResolutions = Screen.resolutions;
foreach (var resolution in supportedResolutions)
{
if (resolution.width < 720 || resolution.height < 720) continue;
AddOption($"{resolution.width}x{resolution.height}", resolution);
}
SelectOption(r => AreEqual(r, Screen.currentResolution), defaultIndex: 0);
}
protected override void OnApply()
{
var resolution = GetSelectedOption();
switch (Screen.fullScreenMode)
{
case FullScreenMode.ExclusiveFullScreen:
Screen.SetResolution(Screen.width, Screen.width, FullScreenMode.ExclusiveFullScreen);
break;
case FullScreenMode.FullScreenWindow:
Screen.SetResolution(resolution.width, resolution.height, FullScreenMode.FullScreenWindow);
break;
case FullScreenMode.MaximizedWindow:
Screen.SetResolution(resolution.width, resolution.height, FullScreenMode.MaximizedWindow);
break;
case FullScreenMode.Windowed:
Screen.SetResolution(resolution.width, resolution.height, FullScreenMode.Windowed);
break;
default:
Screen.SetResolution(Screen.width, Screen.width, FullScreenMode.ExclusiveFullScreen);
break;
}
}
protected override void OnReset()
{
SelectOption(r => AreEqual(r, Screen.currentResolution), defaultIndex: 0);
}
bool AreEqual(Resolution a, Resolution b)
{
return a.width == b.width && a.height == b.height;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 08fa420645764519a7a960565464a708
timeCreated: 1748586208

View File

@@ -0,0 +1,43 @@
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace NBF.Setting
{
public enum TextureQualityEnum
{
FullRes = 0,
HalfRes = 1,
QuarterRes = 2,
EighthRes = 3
}
[Sort(9)]
public class TextureQualitySetting : MultiOption<TextureQualityEnum>
{
public override string Name => "TextureQuality";
public override string Group => SettingsDef.Group.Graphic;
protected override TextureQualityEnum DefaultValue => TextureQualityEnum.FullRes;
protected override void OnInitialize()
{
}
protected override void OnApply()
{
// 获取当前URP Asset
UniversalRenderPipelineAsset URPAsset =
QualitySettings.GetRenderPipelineAssetAt(QualitySettings.GetQualityLevel()) as
UniversalRenderPipelineAsset;
if (URPAsset)
{
//纹理质量
QualitySettings.globalTextureMipmapLimit = (int)GetSelectedOption();
}
}
protected override void OnReset()
{
SelectOption(DefaultValue);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7ca1e2468b24b6285be9176ae024864
timeCreated: 1748590058

View File

@@ -0,0 +1,28 @@
using UnityEngine;
namespace NBF.Setting
{
/// <summary>
/// 垂直同步
/// </summary>
[Sort(4)]
public class VSyncSetting : ToggleOption
{
public override string Name => "VSync";
public override string Group => SettingsDef.Group.Graphic;
protected override bool DefaultValue => false;
protected override void OnApply()
{
//垂直同步
QualitySettings.vSyncCount = GetSelectedOption() ? 1 : 0;
}
protected override void OnReset()
{
SelectOption(DefaultValue);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 00628a08aaac416796a4018119e77cc6
timeCreated: 1748585191

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3ca3dc82471a404ea2346559f1e86f12
timeCreated: 1748590614

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 03ec1dd2a17344dcb27d9f06c7dbbc34
timeCreated: 1748590602

View File

@@ -0,0 +1,38 @@
using NBC;
using UnityEngine;
namespace NBF.Setting
{
public enum SettingLanguage
{
English = 10,
French = 14,
Japanese = 22,
Korean = 23,
Russian = 30,
ChineseSimplified = 40,
ChineseTraditional = 41,
}
[Sort(100)]
public class LanguageSetting : MultiOption<SettingLanguage>
{
private SettingLanguage _defaultLanguage;
public override string Name => "Language";
public override string Group => SettingsDef.Group.SoundAndLanguage;
protected override SettingLanguage DefaultValue => _defaultLanguage;
protected override void OnInitialize()
{
_defaultLanguage = (SettingLanguage)Application.systemLanguage;
}
protected override void OnApply()
{
}
protected override void OnReset()
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6eb19d962e5644ada69dca074c6e720a
timeCreated: 1748592356

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using NBF.Setting;
namespace NBF
{
public class Settings : MonoService<Settings>
{
private readonly Dictionary<string, List<OptionBase>> _dictionary = new Dictionary<string, List<OptionBase>>();
protected override void OnAwake()
{
List<OptionBase> list = new List<OptionBase>();
var options = Reflection.GetAllNonAbstractDerivedTypes<OptionBase>();
foreach (var option in options)
{
var settingOption = Activator.CreateInstance(option);
if (settingOption is OptionBase optionSetting)
{
list.Add(optionSetting);
optionSetting.Initialize();
}
}
list.SortBySortAttribute();
AddRangeToGroup(list);
}
public void LoadAllSettings()
{
foreach (var list in _dictionary.Values)
{
foreach (var option in list)
{
option.Load();
}
}
}
#region
/// <summary>
/// 获取指定 Group 的所有 OptionBase
/// </summary>
public List<OptionBase> GetOptionsByGroup(string group)
{
if (string.IsNullOrEmpty(group))
{
throw new ArgumentException("Group name cannot be null or empty.");
}
return _dictionary.TryGetValue(group, out var options) ? options : new List<OptionBase>();
}
/// <summary>
/// 获取所有 Group 名字列表
/// </summary>
public IEnumerable<string> GetAllGroups()
{
return _dictionary.Keys;
}
/// <summary>
/// 将 OptionBase 按 Group 分类存入字典
/// </summary>
private void AddToGroup(OptionBase option)
{
if (option == null) return;
if (string.IsNullOrEmpty(option.Group)) return;
// 如果字典中没有该 Group则新建一个 List 并加入字典
if (!_dictionary.ContainsKey(option.Group))
{
_dictionary[option.Group] = new List<OptionBase>();
}
// 将 Option 添加到对应的 Group List 中
_dictionary[option.Group].Add(option);
}
/// <summary>
/// 批量添加 OptionBase 到字典
/// </summary>
private void AddRangeToGroup(IEnumerable<OptionBase> options)
{
if (options == null) return;
foreach (var option in options)
{
AddToGroup(option);
}
}
#endregion
}
}

View File

@@ -0,0 +1,13 @@
namespace NBF
{
public class SettingsDef
{
public class Group
{
public const string Graphic = "Graphic";
public const string Keyboard = "Keyboard";
public const string Controller = "Controller";
public const string SoundAndLanguage = "SoundAndLanguage";
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 071c8f83b867467e9a4af17e3d474ab0
timeCreated: 1748585459

View File

@@ -10,25 +10,15 @@ namespace NBF
public string Icon;
}
public class TabSubItemData : TabItemData
public class TabListData : TabItemData
{
}
public class TabSubItemData : TabListData
{
public List<object> Items = new List<object>();
}
public class TabListData
{
public TabItemData Tab;
}
public class TabListSettingData : TabListData
{
/// <summary>
/// 设置保存对象
/// </summary>
public object SettingsObject;
}
/// <summary>
/// 保护二级子目录的列表
/// </summary>
@@ -38,8 +28,8 @@ namespace NBF
public void AddTestData(int index)
{
Tab = new TabItemData();
Tab.Name = $"标题-{index + 1}";
Name = $"标题-{index + 1}";
string[] testIcon = { "Globe", "Granade", "Gun" };
var count1 = Random.Range(5, 10);
var count2 = Random.Range(90, 200);

View File

@@ -106,7 +106,7 @@ namespace NBF
private void InitService()
{
AddService<InputManager>();
AddService<GameSettings>();
AddService<Settings>();
}
#endregion

View File

@@ -47,7 +47,7 @@ namespace NBF
{
var tabData = tabList[i];
var tabItem = List.AddItemFromPool().asButton;
tabItem.title = Lan.Get(tabData.Tab.Name);
tabItem.title = Lan.Get(tabData.Name);
listWidth += tabItem.width;
if (i > 0)
{

View File

@@ -1,38 +0,0 @@
// 本脚本只在不存在时会生成一次。组件逻辑写在当前脚本内。已存在不会再次生成覆盖
using System.IO;
using System.Reflection;
using UnityEngine;
using FairyGUI;
using NBC;
using Unity.VisualScripting;
namespace NBF
{
public partial class SettingItem : GButton
{
public string TitleKey;
public string DescriptionKey;
private void OnInited()
{
}
public void SetData(FieldInfo field, object value)
{
var titleAttribute = field.GetAttribute<TitleAttribute>();
if (titleAttribute != null)
{
TitleKey = titleAttribute.Title;
}
var descriptionAttribute = field.GetAttribute<DescriptionAttribute>();
if (descriptionAttribute != null)
{
DescriptionKey = descriptionAttribute.Description;
}
TextName.text = Lan.Get(TitleKey);
}
}
}

View File

@@ -1,94 +0,0 @@
// 本脚本只在不存在时会生成一次。已存在不会再次生成覆盖
using System.Collections.Generic;
using UnityEngine;
using NBC;
using Unity.VisualScripting;
namespace NBF
{
public partial class SettingPanel : UIPanel
{
public override string UIPackName => "Main";
public override string UIResName => "SettingPanel";
private List<TabListSettingData> tabList = new List<TabListSettingData>();
private object _currentSettingsObject;
protected override void OnInit()
{
base.OnInit();
IsShowCursor = true;
TabListSettingData tabInput = new TabListSettingData();
tabInput.Tab = new TabItemData();
tabInput.Tab.Name = "键盘和鼠标";
tabList.Add(tabInput);
TabListSettingData tabCtrl = new TabListSettingData();
tabCtrl.Tab = new TabItemData();
tabCtrl.Tab.Name = "控制器";
tabList.Add(tabCtrl);
TabListSettingData tabVideo = new TabListSettingData();
tabVideo.Tab = new TabItemData();
tabVideo.Tab.Name = "视频";
tabVideo.SettingsObject = GameSettings.Instance.UseSettings;
tabList.Add(tabVideo);
TabListSettingData tabSound = new TabListSettingData();
tabSound.Tab = new TabItemData();
tabSound.Tab.Name = "音频和语言";
tabList.Add(tabSound);
Menu.OnTabChange += ChangeTab;
}
protected override void OnShow()
{
Menu.SetTabs(tabList);
}
private void ChangeTab(int index)
{
Log.Info($"Change tab index={index}");
var tabListData = tabList[index];
_currentSettingsObject = tabListData.SettingsObject;
ResetSettingList();
}
private void ResetSettingList()
{
List.RemoveChildrenToPool();
if (_currentSettingsObject == null) return;
var fields = _currentSettingsObject.GetType().GetFields();
foreach (var field in fields)
{
if (List.AddItemFromPool() is SettingItem item)
{
item.SetData(field, _currentSettingsObject);
}
}
}
private void Reset()
{
}
private void Save()
{
}
protected override void OnHide()
{
base.OnHide();
}
protected override void OnDestroy()
{
base.OnDestroy();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c812afefed4f43beb3ab200bf67bacf6
timeCreated: 1748569083

View File

@@ -0,0 +1,114 @@
// 本脚本只在不存在时会生成一次。组件逻辑写在当前脚本内。已存在不会再次生成覆盖
using System.IO;
using System.Reflection;
using UnityEngine;
using FairyGUI;
using NBC;
using NBF.Setting;
using Unity.VisualScripting;
namespace NBF
{
public partial class SettingItem : GButton
{
public OptionBase Option;
private void OnInited()
{
BtnPrev.onClick.Set(OnPrev);
BtnNext.onClick.Set(OnNext);
Slider.onChanged.Set(OnSliderChanged);
}
public void SetData(OptionBase option)
{
Option = option;
if (option is IMultiOption multiOption)
{
style.selectedIndex = 0;
}
else if (option is RangeOption range)
{
style.selectedIndex = 1;
Slider.min = range.MinValue;
Slider.max = range.MaxValue;
Slider.wholeNumbers = true;
}
else if (option is RangeOptionFloat rangeOptionFloat)
{
style.selectedIndex = 1;
Slider.min = rangeOptionFloat.MinValue;
Slider.max = rangeOptionFloat.MaxValue;
Slider.wholeNumbers = false;
}
TextName.text = Lan.Get(Option.Name);
SetShow();
}
private void SetShow()
{
if (Option is IMultiOption multiOption)
{
// style.selectedIndex = 0;
TextInfo.text = multiOption.GetName();
}
// else if (option is RangeOption range)
// {
//
// }
// else if (option is RangeOptionFloat rangeOptionFloat)
// {
//
// }
}
public void OnPrev()
{
if (Option is IMultiOption multiOption)
{
var index = multiOption.GetIndex();
if (index > 0)
{
index--;
}
else if (index == 0)
{
var names = multiOption.GetOptionNames();
index = names.Count - 1;
}
multiOption.SetIndex(index);
}
SetShow();
}
public void OnNext()
{
if (Option is IMultiOption multiOption)
{
var names = multiOption.GetOptionNames();
var index = multiOption.GetIndex();
if (index < names.Count - 1)
{
index++;
}
else if (index == names.Count - 1)
{
index = 0;
}
multiOption.SetIndex(index);
}
SetShow();
}
public void OnSliderChanged()
{
}
}
}

View File

@@ -0,0 +1,135 @@
// 本脚本只在不存在时会生成一次。已存在不会再次生成覆盖
using System.Collections.Generic;
using UnityEngine;
using NBC;
using Unity.VisualScripting;
namespace NBF
{
public partial class SettingPanel : UIPanel
{
public override string UIPackName => "Main";
public override string UIResName => "SettingPanel";
private List<TabListData> tabList = new List<TabListData>();
private string _currentGroup = "";
protected override void OnInit()
{
base.OnInit();
IsShowCursor = true;
var groupNames = Settings.Instance.GetAllGroups();
foreach (var group in groupNames)
{
var tab = new TabListData
{
Name = group
};
tabList.Add(tab);
}
Menu.OnTabChange += ChangeTab;
}
protected override void OnShow()
{
Settings.Instance.LoadAllSettings();
InputManager.OnUICanceled += OnUICanceled;
Menu.SetTabs(tabList);
UseBottomMenu();
}
private void ChangeTab(int index)
{
Log.Info($"Change tab index={index}");
var tabListData = tabList[index];
_currentGroup = tabListData.Name;
// _currentSettingsObject = tabListData.SettingsObject;
ResetSettingList();
}
private void ResetSettingList()
{
TextTitle.text = Lan.Get(_currentGroup);
List.RemoveChildrenToPool();
if (string.IsNullOrEmpty(_currentGroup)) return;
var options = Settings.Instance.GetOptionsByGroup(_currentGroup);
foreach (var option in options)
{
if (List.AddItemFromPool() is SettingItem item)
{
item.SetData(option);
}
}
}
private void UseBottomMenu()
{
BottomMenu.OnBack += Hide;
BottomMenu.Use();
}
private void OnUICanceled(string action)
{
if (action == InputDef.UI.SubPrev)
{
if (List.GetChildAt(List.selectedIndex) is SettingItem item)
{
item.OnPrev();
}
}
else if (action == InputDef.UI.SubNext)
{
if (List.GetChildAt(List.selectedIndex) is SettingItem item)
{
item.OnNext();
}
}
else if (action == InputDef.UI.Up)
{
SetListSelected(List.selectedIndex - 1);
}
else if (action == InputDef.UI.Down)
{
if (List.selectedIndex < 0)
{
SetListSelected(0);
}
else
{
SetListSelected(List.selectedIndex + 1);
}
}
}
private void SetListSelected(int selectedIndex)
{
if (selectedIndex >= 0 && selectedIndex < List.numItems)
{
List.selectedIndex = selectedIndex;
List.ScrollToView(List.selectedIndex);
}
}
protected override void OnHide()
{
base.OnHide();
BottomMenu.OnBack -= Hide;
BottomMenu.UnUse();
InputManager.OnUICanceled -= OnUICanceled;
}
protected override void OnDestroy()
{
base.OnDestroy();
Menu.OnTabChange -= ChangeTab;
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using NBF.Setting;
namespace NBF
{
public static class ListExtends
{
public static void SortBySortAttribute(this List<OptionBase> list)
{
if (list == null)
throw new ArgumentNullException(nameof(list));
list.Sort((a, b) =>
{
var orderA = GetSortOrder(a);
var orderB = GetSortOrder(b);
return orderA.CompareTo(orderB);
});
}
private static int GetSortOrder(OptionBase option)
{
if (option == null)
return 999;
var sortAttribute = option.GetType()
.GetCustomAttribute<SortAttribute>(inherit: false);
return sortAttribute?.Sort ?? 999;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 87135425aeb24b8ead2f411dceabb955
timeCreated: 1748591603

View File

@@ -8,7 +8,9 @@ namespace NBF
{
public static class Reflection
{
static Assembly _assembly;
private static readonly Assembly _assembly;
public static Assembly Assembly => _assembly;
static Reflection()
{
@@ -34,6 +36,5 @@ namespace NBF
return derivedTypes;
}
}
}