using System; using UnityEngine; namespace ET.PackageManager.Editor { /// 用于本地小数据量记录的playerPre的包装,用于方便把单个设置项直接当做变量使用 /// 使用这个,可以避免读取时每次都调用PlayerPrefs /// 另外集成了以groupKey(比如userid)来分组数据 public struct Prefs { private T m_value; private string m_key; private string m_valueKey; private RwFlag m_rwFlag; private int m_groupKeyVer; private IGroupKey m_groupKey; private IPrefsAccessor m_accessor; private T m_defValue; public Prefs(string key, IGroupKey groupKey, T defValue, IPrefsAccessor accessor) { m_defValue = defValue; m_value = defValue; m_groupKey = groupKey; m_accessor = accessor; m_groupKeyVer = int.MinValue; m_rwFlag = RwFlag.None; m_valueKey = key; m_key = key; UpdateKey(); } private void UpdateKey(bool notWrite = false) { if (m_groupKey == null) { return; } var curVer = m_groupKey.Version; if (curVer != m_groupKeyVer) { m_groupKeyVer = curVer; var oldKey = m_key; m_key = StrUtil.Concat(m_groupKey.Key, "|", m_valueKey); if (m_rwFlag.Has(RwFlag.Write)) { if (oldKey != m_key) { //如果之前已经有写入,则需要删除旧的,写入新的 PlayerPrefs.DeleteKey(oldKey); if (!notWrite) { m_accessor.Set(m_key, m_value); } } } //清除读取标记 m_rwFlag.UnmarkSelf(RwFlag.Read); } } public T Value { get { UpdateKey(); //如果即没有读过,也没有写过 if (!m_rwFlag.Overlaps(RwFlag.Full)) { if (m_accessor.HasKey(m_key)) { m_value = m_accessor.Get(m_key); } else if (m_groupKey != null && m_accessor.HasKey(m_valueKey)) { //第一次时,如果定向的值拿不到,就去尝试拿全局的值 m_value = m_accessor.Get(m_valueKey); } else { m_value = m_defValue; } m_rwFlag.MarkSelf(RwFlag.Read); } return m_value; } set { UpdateKey(); if (m_rwFlag.Overlaps(RwFlag.Full) && value.Equals(m_value)) { return; } m_value = value; m_rwFlag |= RwFlag.Write; m_accessor.Set(m_key, value); } } public void Delete() { UpdateKey(true); m_groupKeyVer = int.MinValue; m_value = default; m_rwFlag.MarkSelf(RwFlag.Write); PlayerPrefs.DeleteKey(m_key); } public interface IPrefsAccessor { bool HasKey(string key); T Get(string key); void Set(string key, T value); } } public struct IntPrefs { private Prefs m_value; public int Value { get => m_value.Value; set => m_value.Value = value; } public IntPrefs(string key, IGroupKey groupKey = null, int defValue = 0) { m_value = new Prefs(key, groupKey, defValue, IntAccessor.Inst); } public void Delete() { m_value.Delete(); } public static implicit operator int(IntPrefs value) { return value.Value; } } public struct FloatPrefs { private Prefs m_value; public float Value { get => m_value.Value; set => m_value.Value = value; } public FloatPrefs(string key, IGroupKey groupKey = null, float defValue = 0f) { m_value = new Prefs(key, groupKey, defValue, FloatAccessor.Inst); } public void Delete() { m_value.Delete(); } public static implicit operator float(FloatPrefs value) { return value.Value; } } public struct StringPrefs { private Prefs m_value; public string Value { get => m_value.Value; set => m_value.Value = value; } public StringPrefs(string key, IGroupKey groupKey = null, string defValue = null) { m_value = new Prefs(key, groupKey, defValue, StrAccessor.Inst); } public void Delete() { m_value.Delete(); } public static implicit operator string(StringPrefs value) { return value.Value; } } public struct BoolPrefs { private Prefs m_value; public bool Value { get => m_value.Value == 1; set => m_value.Value = value ? 1 : 0; } public BoolPrefs(string key, IGroupKey groupKey = null, bool defValue = false) { m_value = new Prefs(key, groupKey, defValue ? 1 : 0, IntAccessor.Inst); } public void Delete() { m_value.Delete(); } public static implicit operator bool(BoolPrefs value) { return value.Value; } } public struct ArrPrefs where T : IComparable { private Prefs m_value; public ArrPrefs(string key, IGroupKey groupKey = null) { m_value = new Prefs(key, groupKey, "", StrAccessor.Inst); } public T[] Get() { string value = m_value.Value; if (string.IsNullOrEmpty(value)) { return Array.Empty(); } return StrConv.ToArr(value, StrConv.ArrSplitLv1); } public void Set(T[] value) { if (value == null || value.Length < 1) { m_value.Delete(); return; } var sb = SbPool.Get(); sb.Append(value[0].ToString()); for (int i = 1; i < value.Length; i++) { sb.Append(StrConv.ChrArrSplitLv1).Append(value[i].ToString()); } m_value.Value = SbPool.PutAndToStr(sb); } public void Delete() { m_value.Delete(); } } public struct EnumPrefs where T : Enum { private Prefs m_value; public T Value { get => (T)Enum.ToObject(typeof(T), m_value.Value); set => m_value.Value = Convert.ToInt32(value); } public EnumPrefs(string key, IGroupKey groupKey = null, T defValue = default) { m_value = new Prefs(key, groupKey, Convert.ToInt32(defValue), IntAccessor.Inst); } public void Delete() { m_value.Delete(); } public static implicit operator T(EnumPrefs value) { return value.Value; } } public class IntAccessor : Prefs.IPrefsAccessor { public static readonly IntAccessor Inst = new IntAccessor(); public bool HasKey(string key) { return PlayerPrefs.HasKey(key); } public int Get(string key) { return PlayerPrefs.GetInt(key); } public void Set(string key, int value) { PlayerPrefs.SetInt(key, value); } } public class FloatAccessor : Prefs.IPrefsAccessor { public static readonly FloatAccessor Inst = new FloatAccessor(); public bool HasKey(string key) { return PlayerPrefs.HasKey(key); } public float Get(string key) { return PlayerPrefs.GetFloat(key); } public void Set(string key, float value) { PlayerPrefs.SetFloat(key, value); } } public class StrAccessor : Prefs.IPrefsAccessor { public static readonly StrAccessor Inst = new StrAccessor(); public bool HasKey(string key) { return PlayerPrefs.HasKey(key); } public string Get(string key) { return PlayerPrefs.GetString(key); } public void Set(string key, string value) { PlayerPrefs.SetString(key, value); } } /// /// 分组KEY /// public interface IGroupKey { int Version { get; } string Key { get; } } [Flags] public enum RwFlag { None = 0, Write = 1, Read = 1 << 1, Full = Write | Read } public static class RwFlagExt { public static RwFlag Mark(this RwFlag owner, RwFlag flags) { return owner | flags; } public static RwFlag Unmark(this RwFlag owner, RwFlag flags) { return owner & (~flags); } public static void MarkSelf(this ref RwFlag owner, RwFlag flags) { owner |= flags; } public static void UnmarkSelf(this ref RwFlag owner, RwFlag flags) { owner &= (~flags); } public static bool Has(this RwFlag owner, RwFlag flags) { return (owner & flags) == flags; } public static bool Overlaps(this RwFlag owner, RwFlag flags) { return (owner & flags) != 0; } } }