/******************************************************************************/ /* Project - MudBun Publisher - Long Bunny Labs http://LongBunnyLabs.com Author - Ming-Lun "Allen" Chou http://AllenChou.net */ /******************************************************************************/ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace MudBun { public class ProjectPrefs : ScriptableObject { private static readonly string InstancePath = "Assets/MudBun/ProjectPrefs.asset"; [Serializable] public class Record { public enum TypeEnum { Bool, Int, Float, String, Set, } public string Key = ""; public TypeEnum Type = TypeEnum.Bool; public string Value = ""; public void Sort() { if (Type != TypeEnum.Set) return; var set = StringToSet(Value); set = set.OrderBy(x => x).ToArray(); Value = SetToString(set); } } [SerializeField] private List m_records = new List(); public List Records => m_records; [SerializeField] private string m_version = ""; public string Version => m_version; internal static void Init() { // poke var instance = Instance; //Debug.Log("MudBun: Project prefs version " + MudBun.Version); } private static ProjectPrefs Instance { get { var instance = AssetDatabase.LoadAssetAtPath(InstancePath); if (instance != null && instance.m_version != MudBun.Version) { #if !MUDBUN_DEV Debug.Log($"MudBun: Detected previous different version ({instance.m_version}); resettings compatibility records."); //Debug.Log($"MudBun: New project prefs created for version {MudBun.Version}."); CompatibilityManager.Reset(); #endif instance.m_version = MudBun.Version; } if (instance == null) { instance = CreateInstance(); instance.m_version = MudBun.Version; AssetDatabase.CreateAsset(instance, InstancePath); AssetDatabase.Refresh(); instance = AssetDatabase.LoadAssetAtPath(InstancePath); Assert.Unequal(instance, null); } return instance; } } private static string[] StringToSet(string value) { return value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); } private static string SetToString(string[] set) { return string.Join(";", set); } private static string AddToSetString(string setStr, string value) { var set = StringToSet(setStr); if (set.Contains(value)) return setStr; set = set.Append(value).ToArray(); return SetToString(set); } private static string RemoveFromSetString(string setStr, string value) { var set = StringToSet(setStr); set = set.Where(x => x != value).ToArray(); return SetToString(set); } public static bool GetRecord(string key, out Record record) { var list = Instance.Records.FindAll(x => x.Key.Equals(key)); if (list == null || list.Count == 0) { record = null; return false; } record = list.First(); return true; } public static void SetRecord(string key, Record record) { if (GetRecord(key, out Record existingRecord)) { if (existingRecord.Type == record.Type && existingRecord.Value.Equals(record.Value)) return; existingRecord.Type = record.Type; existingRecord.Value = record.Value; } else { record.Key = key; Instance.Records.Add(record); } EditorUtility.SetDirty(Instance); AssetDatabase.SaveAssets(); } public static bool HasKey(string key) { return Instance.Records.Any(x => x.Key.Equals(key)); } public static void DeleteKey(string key) { Instance.Records.RemoveAll(x => x.Key.Equals(key)); } public static bool GetBool(string key, bool defaultValue) { if (!GetRecord(key, out Record record)) return defaultValue; Assert.Equal(record.Type, Record.TypeEnum.Bool); if (!bool.TryParse(record.Value, out bool result)) { Debug.LogWarning($"MudBun ProjectPrefs: Cannot parse string \"{record.Value}\" into bool for project preference \"{record.Key}\"."); return defaultValue; } return result; } public static void SetBool(string key, bool value) { SetRecord(key, new Record() { Type = Record.TypeEnum.Bool, Value = value.ToString() }); } public static int GetInt(string key, int defaultValue) { if (!GetRecord(key, out Record record)) return defaultValue; Assert.Equal(record.Type, Record.TypeEnum.Int); if (!int.TryParse(record.Value, out int result)) { Debug.LogWarning($"MudBun ProjectPrefs: Cannot parse string \"{record.Value}\" into int for project preference \"{record.Key}\"."); return defaultValue; } return result; } public static void SetInt(string key, int value) { SetRecord(key, new Record() { Type = Record.TypeEnum.Int, Value = value.ToString() }); } public static float GetFloat(string key, float defaultValue) { if (!GetRecord(key, out Record record)) return defaultValue; Assert.Equal(record.Type, Record.TypeEnum.Float); if (!float.TryParse(record.Value, out float result)) { Debug.LogWarning($"MudBun ProjectPrefs: Cannot parse string \"{record.Value}\" into float for project preference \"{record.Key}\"."); return defaultValue; } return result; } public static void SetFloat(string key, float value) { SetRecord(key, new Record() { Type = Record.TypeEnum.Float, Value = value.ToString() }); } public static string GetString(string key, string defaultValue) { if (!GetRecord(key, out Record record)) return defaultValue; Assert.Equal(record.Type, Record.TypeEnum.String); return record.Value; } public static void SetString(string key, string value) { SetRecord(key, new Record() { Type = Record.TypeEnum.String, Value = value }); } public static string[] GetSet(string key, string[] defaultValue) { if (!GetRecord(key, out Record record)) return defaultValue; Assert.Equal(record.Type, Record.TypeEnum.Set); return record.Value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); } public static bool SetContains(string key, string value) { var set = GetSet(key, null); if (set == null) return false; return set.Contains(value); } public static void AddToSet(string key, string value) { if (!GetRecord(key, out Record record)) { SetRecord(key, new Record() { Type = Record.TypeEnum.Set, Value = value }); return; } Assert.Equal(record.Type, Record.TypeEnum.Set); record.Value = AddToSetString(record.Value, value); } public static void RemoveFromSet(string key, string value) { if (!GetRecord(key, out Record record)) return; Assert.Equal(record.Type, Record.TypeEnum.Set); record.Value = RemoveFromSetString(record.Value, value); } } [CustomEditor(typeof(ProjectPrefs))] public class ProjectPrefsEditor : MudEditorBase { private static readonly int TypeWidth = 80; private static readonly int SmallButtonWidth = 24; private static readonly int SortButtonWidth = 80; private static readonly float SaveDelay = 2.0f; private float m_lastDirtyTime = -1.0f; private void MarkDirty() { EditorUtility.SetDirty(serializedObject.targetObject); m_lastDirtyTime = Time.realtimeSinceStartup; } private void Save() { AssetDatabase.SaveAssets(); m_lastDirtyTime = -1.0f; } private void TrySave() { if (m_lastDirtyTime < 0.0f) return; if (Time.realtimeSinceStartup - m_lastDirtyTime < SaveDelay) return; Save(); } private void OnEnable() { EditorApplication.update += TrySave; } private void OnDisable() { EditorApplication.update -= TrySave; Save(); } public override void OnInspectorGUI() { serializedObject.Update(); var prefs = (ProjectPrefs) serializedObject.targetObject; var records = prefs.Records; if (records == null) return; Undo.RecordObject(prefs, "Modify ProjectPrefs"); EditorGUI.BeginChangeCheck(); ProjectPrefs.Record recordToMoveUp = null; ProjectPrefs.Record recordToMoveDown = null; ProjectPrefs.Record recordToDelete = null; foreach (var record in records) { EditorGUILayout.BeginHorizontal(); record.Key = EditorGUILayout.TextField(record.Key); if (GUILayout.Button("↑", GUILayout.Width(SmallButtonWidth))) recordToMoveUp = record; if (GUILayout.Button("↓", GUILayout.Width(SmallButtonWidth))) recordToMoveDown = record; if (GUILayout.Button("-", GUILayout.Width(SmallButtonWidth))) recordToDelete = record; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginHorizontal(); record.Type = (ProjectPrefs.Record.TypeEnum) Convert.ToInt32(EditorGUILayout.EnumPopup(record.Type, GUILayout.MinWidth(TypeWidth), GUILayout.MaxWidth(TypeWidth))); switch (record.Type) { case ProjectPrefs.Record.TypeEnum.Bool: bool boolValue; if (!bool.TryParse(record.Value, out boolValue)) boolValue = false; record.Value = EditorGUILayout.Toggle(boolValue).ToString(); break; case ProjectPrefs.Record.TypeEnum.Int: int intValue; if (!int.TryParse(record.Value, out intValue)) intValue = 0; record.Value = EditorGUILayout.IntField(intValue).ToString(); break; case ProjectPrefs.Record.TypeEnum.Float: float floatValue; if (!float.TryParse(record.Value, out floatValue)) floatValue = 0.0f; record.Value = EditorGUILayout.FloatField(floatValue).ToString(); break; case ProjectPrefs.Record.TypeEnum.Set: case ProjectPrefs.Record.TypeEnum.String: record.Value = EditorGUILayout.TextField(record.Value); break; } EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); } if (recordToMoveUp != null) { int i = records.FindIndex(x => x == recordToMoveUp); if (i > 0) { var recordToSwap = records[i - 1]; records[i - 1] = recordToMoveUp; records[i] = recordToSwap; } } if (recordToMoveDown != null) { int i = records.FindIndex(x => x == recordToMoveDown); if (i >= 0 && i < records.Count - 1) { var recordToSwap = records[i + 1]; records[i + 1] = recordToMoveDown; records[i] = recordToSwap; } } if (recordToDelete != null) records.Remove(recordToDelete); GUILayout.Label($"Version: {prefs.Version}"); EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Sort", GUILayout.Width(SortButtonWidth))) { records.Sort((a, b) => a.Key.CompareTo(b.Key)); records.ForEach(x => x.Sort()); } if (GUILayout.Button("+", GUILayout.Width(SmallButtonWidth))) { string newRecordKey = "NewRecord"; while (records.Any(x => x.Key.Equals(newRecordKey))) newRecordKey += "+"; records.Add(new ProjectPrefs.Record() { Key = newRecordKey }); } EditorGUILayout.EndHorizontal(); serializedObject.Update(); if (EditorGUI.EndChangeCheck()) { MarkDirty(); } } } }