The SettingsProvider are not bound to an *.asset file. They are flexible enough that you can provide your own data model. That said, if you want to save data outside of the project Assets/ folder itself you can do your own asset serialization. Here’s an example that uses JSON file to save data:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using UnityEngine;
using Random = System.Random;
namespace UnityEditor
{
[Serializable]
public class SettingsPropertyData
{
public string name;
public string label;
public string type;
public string value;
public float min;
public float max;
}
[Serializable]
public class SettingsData
{
public string name;
public string label;
public string scope;
public SettingsPropertyData[] settings;
}
public class GenericSettingsProvider : SettingsProvider
{
private string m_LocalFilePath;
private SettingsPropertyData[] m_Properties;
public GenericSettingsProvider(string path, string label, string scope, SettingsPropertyData[] properties, string jsonFilePath = null)
: base(path)
{
this.label = label;
if (scope == null)
scopes = SettingsScopes.Any;
else if (scope.ToLower() == "project")
scopes = SettingsScopes.Project;
else if (scope.ToLower() == "user")
scopes = SettingsScopes.User;
m_Properties = properties;
m_LocalFilePath = jsonFilePath;
}
public override void OnGUI(string searchContext)
{
using (new SettingsWindow.GUIScope())
{
foreach (var property in m_Properties)
{
if (searchContext.Length > 0 && !SearchUtils.MatchSearchGroups(searchContext, property.label))
continue;
using (new EditorGUILayout.HorizontalScope())
DrawPropertyControl(property);
}
GUILayout.Space(10.0f);
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (GUILayout.Button("Show in Project"))
{
var asset = AssetDatabase.LoadMainAssetAtPath(m_LocalFilePath);
if (asset)
EditorGUIUtility.PingObject(asset);
}
}
}
}
public override bool HasSearchInterest(string searchContext)
{
if (SettingsTestsUtils.HasSearchInterest(m_Properties, searchContext))
{
return true;
}
return base.HasSearchInterest(searchContext);
}
private string GetPropertyKey(SettingsPropertyData property)
{
return SettingsTestsUtils.GetPropertyKey(settingsPath, property);
}
private void DrawPropertyControl(SettingsPropertyData property)
{
switch (property.type.ToLower())
{
case "string": DrawStringPropertyControl(property); break;
case "number": DrawNumberPropertyControl(property); break;
case "bool": DrawBooleanPropertyControl(property); break;
case "color": DrawColorPropertyControl(property); break;
default: throw new NotSupportedException("Property type " + property.type + " not supported");
}
}
private void DrawColorPropertyControl(SettingsPropertyData property)
{
EditorGUI.BeginChangeCheck();
var key = GetPropertyKey(property);
var colorComponents = SettingsTestsUtils.GetFloats(property);
Color colorValue = new Color();
if (colorComponents != null && colorComponents.Length == 4)
colorValue = new Color(colorComponents[0], colorComponents[1], colorComponents[2], colorComponents[3]);
if (IsUserSettings())
{
colorValue.r = EditorPrefs.GetFloat(key + ".r", colorValue.r);
colorValue.g = EditorPrefs.GetFloat(key + ".g", colorValue.g);
colorValue.b = EditorPrefs.GetFloat(key + ".b", colorValue.b);
colorValue.a = EditorPrefs.GetFloat(key + ".a", colorValue.a);
}
Color newColor = EditorGUILayout.ColorField(property.label, colorValue);
if (EditorGUI.EndChangeCheck())
{
property.value = Json.Serialize(new[] {newColor.r, newColor.g, newColor.b, newColor.a});
if (IsUserSettings())
{
EditorPrefs.SetFloat(key + ".r", newColor.r);
EditorPrefs.SetFloat(key + ".g", newColor.g);
EditorPrefs.SetFloat(key + ".b", newColor.b);
EditorPrefs.SetFloat(key + ".a", newColor.a);
}
else
PersistSettings();
}
}
private void DrawBooleanPropertyControl(SettingsPropertyData property)
{
EditorGUI.BeginChangeCheck();
var key = GetPropertyKey(property);
bool boolValue;
if (property.value == null || !Boolean.TryParse(property.value, out boolValue))
boolValue = false;
var newValue = EditorGUILayout.Toggle(property.label, IsUserSettings() ? EditorPrefs.GetBool(key, boolValue) : boolValue);
if (EditorGUI.EndChangeCheck())
{
property.value = Convert.ToString(newValue, CultureInfo.InvariantCulture);
if (IsUserSettings())
EditorPrefs.SetBool(key, newValue);
else
PersistSettings();
}
}
private void DrawNumberPropertyControl(SettingsPropertyData property)
{
EditorGUI.BeginChangeCheck();
var key = GetPropertyKey(property);
var defaultValue = property.value != null ? Convert.ToSingle(property.value) : 0;
var floatValue = IsUserSettings() ? EditorPrefs.GetFloat(key, defaultValue) : defaultValue;
float newValue = floatValue;
if (property.min < property.max)
newValue = EditorGUILayout.Slider(property.label, floatValue, property.min, property.max);
else
newValue = EditorGUILayout.FloatField(property.label, IsUserSettings() ? EditorPrefs.GetFloat(key, floatValue) : floatValue);
if (EditorGUI.EndChangeCheck())
{
property.value = Convert.ToString(newValue, CultureInfo.InvariantCulture);
if (IsUserSettings())
EditorPrefs.SetFloat(key, newValue);
else
PersistSettings();
}
}
private void DrawStringPropertyControl(SettingsPropertyData property)
{
EditorGUI.BeginChangeCheck();
var uniquePropertyKey = GetPropertyKey(property);
var newValue = EditorGUILayout.TextField(property.label, IsUserSettings() ? EditorPrefs.GetString(uniquePropertyKey, property.value) : property.value);
if (EditorGUI.EndChangeCheck())
{
property.value = newValue;
if (IsUserSettings())
EditorPrefs.SetString(uniquePropertyKey, newValue);
else
PersistSettings();
}
}
private void PersistSettings()
{
if (String.IsNullOrEmpty(m_LocalFilePath))
throw new FileNotFoundException("Project settings data cannot be saved.");
var dataAsJson = File.ReadAllText(m_LocalFilePath);
var data = JsonUtility.FromJson<SettingsData>(dataAsJson);
data.settings = m_Properties;
File.WriteAllText(m_LocalFilePath, JsonUtility.ToJson(data, true));
}
public static GenericSettingsProvider LoadFromFile(string path)
{
var dataAsJson = File.ReadAllText(path);
var data = JsonUtility.FromJson<SettingsData>(dataAsJson);
return new GenericSettingsProvider(data.name, data.label, data.scope, data.settings, path);
}
private bool IsUserSettings()
{
return (scopes & SettingsScopes.User) != 0;
}
[SettingsProviderGroup]
internal static SettingsProvider[] FetchGenericSettingsProviderList()
{
var genericSettingsFilePaths = AssetDatabase.GetAllAssetPaths().Where(path => path.EndsWith(".settings")).ToArray();
var genericSettingsProviders = new List<SettingsProvider>(genericSettingsFilePaths.Length);
foreach (var genericSettingsFilePath in genericSettingsFilePaths)
{
if (!File.Exists(genericSettingsFilePath))
continue;
try
{
genericSettingsProviders.Add(LoadFromFile(genericSettingsFilePath));
}
catch
{
Debug.LogError("Failed to parse settings file " + genericSettingsFilePath);
}
}
return genericSettingsProviders.ToArray();
}
}
}