Decompiled source of ZioConfigFile v1.0.2

ZioConfigFile.dll

Decompiled 3 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Zio;
using Zio.FileSystems;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ZioConfigFile")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+989b526372e295d2a3d8d6eff4aa3222af20bb5c")]
[assembly: AssemblyProduct("ZioConfigFile")]
[assembly: AssemblyTitle("ZioConfigFile")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ZioConfigFile
{
	public class ZioConfigEntry<T> : ZioConfigEntryBase
	{
		private T _typedValue;

		public T Value
		{
			get
			{
				return _typedValue;
			}
			set
			{
				value = ClampValue(value);
				if (!value.Equals(_typedValue))
				{
					T typedValue = _typedValue;
					_typedValue = value;
					OnSettingChanged(this, typedValue);
				}
			}
		}

		public override object BoxedValue
		{
			get
			{
				return Value;
			}
			set
			{
				Value = (T)value;
			}
		}

		public ZioConfigEntry(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription)
			: base(configDefinition, typeof(T), defaultValue, configDescription)
		{
		}

		public static implicit operator ConfigEntry<T>(ZioConfigEntry<T> zioEntry)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			if (zioEntry.configEntryFallback != null)
			{
				return (ConfigEntry<T>)(object)zioEntry.configEntryFallback;
			}
			if (ZioConfigEntryBase.fallbackConfigFile == null)
			{
				ZioConfigEntryBase.fallbackConfigFile = new ConfigFile("", false)
				{
					SaveOnConfigSet = false
				};
			}
			ConfigEntry<T> fallback = new ConfigEntry<T>(ZioConfigEntryBase.fallbackConfigFile, zioEntry.Definition, (T)zioEntry.DefaultValue, zioEntry.Description);
			fallback.SettingChanged += delegate
			{
				if (!zioEntry.duckChanged)
				{
					zioEntry.duckFallbackChanged = true;
					zioEntry.Value = fallback.Value;
					zioEntry.duckFallbackChanged = false;
				}
			};
			zioEntry.SettingChanged += delegate
			{
				if (!zioEntry.duckFallbackChanged)
				{
					zioEntry.duckChanged = true;
					fallback.Value = zioEntry.Value;
					zioEntry.duckChanged = false;
				}
			};
			zioEntry.configEntryFallback = (ConfigEntryBase)(object)fallback;
			return (ConfigEntry<T>)(object)zioEntry.configEntryFallback;
		}
	}
	public abstract class ZioConfigEntryBase
	{
		public bool DontSaveOnChange;

		protected ConfigEntryBase configEntryFallback;

		protected bool duckChanged;

		protected bool duckFallbackChanged;

		protected static ConfigFile fallbackConfigFile;

		public ConfigDefinition Definition { get; }

		public ConfigDescription Description { get; }

		public Type SettingType { get; }

		public object DefaultValue { get; }

		public abstract object BoxedValue { get; set; }

		public event Action<ZioConfigEntryBase, object, bool> SettingChanged;

		protected ZioConfigEntryBase(ConfigDefinition configDefinition, Type settingType, object defaultValue, ConfigDescription configDescription)
		{
			Definition = configDefinition ?? throw new ArgumentNullException("configDefinition");
			SettingType = settingType ?? throw new ArgumentNullException("settingType");
			Description = configDescription ?? ConfigDescription.Empty;
			if (Description.AcceptableValues != null && !SettingType.IsAssignableFrom(Description.AcceptableValues.ValueType))
			{
				throw new AggregateException("configDescription.AcceptableValues is for a different type than the type of this setting");
			}
			DefaultValue = defaultValue;
			BoxedValue = defaultValue;
		}

		public string GetSerializedValue()
		{
			return TomlTypeConverter.ConvertToString(BoxedValue, SettingType);
		}

		public void SetSerializedValue(string value)
		{
			try
			{
				BoxedValue = TomlTypeConverter.ConvertToValue(value, SettingType);
			}
			catch (Exception ex)
			{
				ZioConfigFile.Logger.LogWarning((object)$"Config value of setting \"{Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
			}
		}

		public T ClampValue<T>(T value)
		{
			return (Description.AcceptableValues != null) ? ((T)Description.AcceptableValues.Clamp((object)value)) : value;
		}

		public void OnSettingChanged(ZioConfigEntryBase config, object oldValue)
		{
			this.SettingChanged?.Invoke(config, oldValue, DontSaveOnChange);
		}

		public void WriteDescription(StreamWriter writer)
		{
			if (!string.IsNullOrEmpty(Description.Description))
			{
				writer.WriteLine("## " + Description.Description.Replace("\n", "\n## "));
			}
			writer.WriteLine("# Setting type: " + SettingType.Name);
			writer.WriteLine("# Default value: " + TomlTypeConverter.ConvertToString(DefaultValue, SettingType));
			if (Description.AcceptableValues != null)
			{
				writer.WriteLine(Description.AcceptableValues.ToDescriptionString());
			}
			else if (SettingType.IsEnum)
			{
				writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(SettingType)));
				if (SettingType.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any())
				{
					writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)");
				}
			}
		}
	}
	public class ZioConfigFile : IDictionary<ConfigDefinition, ZioConfigEntryBase>, ICollection<KeyValuePair<ConfigDefinition, ZioConfigEntryBase>>, IEnumerable<KeyValuePair<ConfigDefinition, ZioConfigEntryBase>>, IEnumerable
	{
		protected object _ioLock = new object();

		private static readonly FileSystem InternalFileSystem = (FileSystem)new PhysicalFileSystem();

		private readonly Stopwatch saveStopwatch = new Stopwatch();

		private bool _waitingForSaves;

		public int waitDuration = 1000;

		public BepInPlugin OwnerMetadata { get; }

		public FileSystem FileSystem { get; }

		public UPath FilePath { get; }

		public Dictionary<ConfigDefinition, ZioConfigEntryBase> Entries { get; } = new Dictionary<ConfigDefinition, ZioConfigEntryBase>();


		protected Dictionary<ConfigDefinition, string> OrphanedEntries { get; } = new Dictionary<ConfigDefinition, string>();


		public static ManualLogSource Logger { get; } = new ManualLogSource("ZioConfigFile");


		public static FileSystem BepinConfigFileSystem { get; } = (FileSystem)new SubFileSystem((IFileSystem)(object)InternalFileSystem, InternalFileSystem.ConvertPathFromInternal(Paths.ConfigPath), true);


		public bool SaveOnConfigSet { get; set; } = true;


		public int Count
		{
			get
			{
				lock (_ioLock)
				{
					return Entries.Count;
				}
			}
		}

		public bool IsReadOnly => false;

		ZioConfigEntryBase IDictionary<ConfigDefinition, ZioConfigEntryBase>.this[ConfigDefinition key]
		{
			get
			{
				lock (_ioLock)
				{
					return Entries[key];
				}
			}
			set
			{
				throw new InvalidOperationException("Directly setting a config entry is not supported");
			}
		}

		public ZioConfigEntryBase this[ConfigDefinition key]
		{
			get
			{
				lock (_ioLock)
				{
					return Entries[key];
				}
			}
		}

		public ZioConfigEntryBase this[string section, string key] => this[new ConfigDefinition(section, key)];

		public ICollection<ConfigDefinition> Keys
		{
			get
			{
				lock (_ioLock)
				{
					return Entries.Keys;
				}
			}
		}

		ICollection<ZioConfigEntryBase> IDictionary<ConfigDefinition, ZioConfigEntryBase>.Values
		{
			get
			{
				lock (_ioLock)
				{
					return Entries.Values;
				}
			}
		}

		public event Action ConfigReloaded;

		public event Action<ZioConfigEntryBase, object> SettingChanged;

		public ZioConfigFile(BepInPlugin plugin, bool saveOnInit = true)
			: this(BepinConfigFileSystem, UPath.op_Implicit(plugin.Name), saveOnInit, plugin)
		{
		}//IL_000c: Unknown result type (might be due to invalid IL or missing references)


		public ZioConfigFile(FileSystem fileSystem, UPath path, bool saveOnInit, BaseUnityPlugin unityPlugin)
			: this(fileSystem, path, saveOnInit, unityPlugin.Info.Metadata)
		{
		}//IL_0002: Unknown result type (might be due to invalid IL or missing references)


		public ZioConfigFile(FileSystem fileSystem, UPath path, bool saveOnInit, BepInPlugin bepInPlugin = null)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			OwnerMetadata = bepInPlugin;
			FileSystem = fileSystem;
			FilePath = path;
			if (fileSystem.FileExists(path))
			{
				Reload();
			}
			else if (saveOnInit)
			{
				Save();
			}
		}

		public void Reload()
		{
			InternalReload();
		}

		protected virtual void InternalReload()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			lock (_ioLock)
			{
				if (!FileSystem.FileExists(FilePath))
				{
					return;
				}
				OrphanedEntries.Clear();
				using Stream stream = FileSystem.OpenFile(FilePath, FileMode.Open, FileAccess.Read, FileShare.None);
				using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
				if (!streamReader.EndOfStream)
				{
					string text = "";
					string text2 = streamReader.ReadLine();
					do
					{
						string text3 = text2.Trim();
						if (text3.StartsWith("#"))
						{
							continue;
						}
						if (text3.StartsWith("[") && text3.EndsWith("]"))
						{
							text = text3.Substring(1, text3.Length - 2);
							continue;
						}
						string[] array = text3.Split('=');
						if (array.Length == 2)
						{
							ConfigDefinition key = new ConfigDefinition(text, array[0].Trim());
							if (Entries.TryGetValue(key, out var value))
							{
								value.SetSerializedValue(array[1].Trim());
							}
							else
							{
								OrphanedEntries[key] = array[1].Trim();
							}
						}
					}
					while ((text2 = streamReader.ReadLine()) != null);
				}
			}
			OnConfigReloaded();
		}

		public void OnConfigReloaded()
		{
			Delegate[] array = this.ConfigReloaded?.GetInvocationList();
			if (array == null)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					(@delegate as Action)?.Invoke();
				}
				catch (Exception ex)
				{
					Logger.LogError((object)ex);
				}
			}
		}

		public void OnSettingChanged(ZioConfigEntryBase changedSetting, object valueBefore, bool ignoreSave)
		{
			if (!ignoreSave && SaveOnConfigSet)
			{
				Save();
			}
			Delegate[] array = this.SettingChanged?.GetInvocationList();
			if (array == null)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					(@delegate as Action<ZioConfigEntryBase, object>)?.Invoke(changedSetting, valueBefore);
				}
				catch (Exception ex)
				{
					Logger.LogError((object)ex);
				}
			}
		}

		protected virtual void SaveThread()
		{
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			while (saveStopwatch.ElapsedMilliseconds < waitDuration)
			{
				Task.Delay(Mathf.FloorToInt((float)waitDuration * 0.1f));
			}
			using MemoryStream memoryStream = new MemoryStream();
			using StreamWriter streamWriter = new StreamWriter(memoryStream, Encoding.UTF8);
			if (OwnerMetadata != null)
			{
				streamWriter.WriteLine($"## Settings file was created by plugin {OwnerMetadata.Name} v{OwnerMetadata.Version}");
				streamWriter.WriteLine("## Plugin GUID: " + OwnerMetadata.GUID);
				streamWriter.WriteLine();
			}
			lock (_ioLock)
			{
				foreach (IGrouping<string, (ConfigDefinition, ZioConfigEntryBase, string)> item in from x in Entries.Select((KeyValuePair<ConfigDefinition, ZioConfigEntryBase> x) => (x.Key, x.Value, x.Value.GetSerializedValue())).Concat(((IEnumerable<KeyValuePair<ConfigDefinition, string>>)OrphanedEntries).Select((Func<KeyValuePair<ConfigDefinition, string>, (ConfigDefinition, ZioConfigEntryBase, string)>)((KeyValuePair<ConfigDefinition, string> x) => (x.Key, null, x.Value))))
					group x by x.Key.Section into x
					orderby x.Key
					select x)
				{
					streamWriter.WriteLine("[" + item.Key + "]");
					foreach (var item2 in item)
					{
						streamWriter.WriteLine();
						item2.Item2?.WriteDescription(streamWriter);
						streamWriter.WriteLine(item2.Item1.Key + " = " + item2.Item3);
					}
					streamWriter.WriteLine();
				}
				streamWriter.Flush();
			}
			try
			{
				UPath filePath = FilePath;
				if (((UPath)(ref filePath)).IsNull)
				{
					goto IL_0278;
				}
				filePath = FilePath;
				if (((UPath)(ref filePath)).IsEmpty || FilePath == UPath.op_Implicit("/"))
				{
					goto IL_0278;
				}
				FileSystem.CreateDirectory(UPathExtensions.GetDirectory(FilePath));
				goto end_IL_0237;
				IL_0278:
				Logger.LogWarning((object)"Tried to create a ZioConfigFile with a null, empty or root path, escaping.");
				return;
				end_IL_0237:;
			}
			catch (UnauthorizedAccessException ex)
			{
				Debug.LogError((object)ex);
			}
			using Stream stream = FileSystem.OpenFile(FilePath, FileMode.Create, FileAccess.Write, FileShare.None);
			stream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
			stream.Close();
			_waitingForSaves = false;
		}

		public void Save()
		{
			saveStopwatch.Restart();
			if (!_waitingForSaves)
			{
				new Thread(SaveThread).Start();
			}
			_waitingForSaves = true;
		}

		public bool TryGetEntry<T>(string section, string key, out ZioConfigEntry<T> entry)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			return TryGetEntry(new ConfigDefinition(section, key), out entry);
		}

		public bool TryGetEntry<T>(ConfigDefinition configDefinition, out ZioConfigEntry<T> entry)
		{
			lock (_ioLock)
			{
				if (Entries.TryGetValue(configDefinition, out var value))
				{
					entry = (ZioConfigEntry<T>)value;
					return true;
				}
				entry = null;
				return false;
			}
		}

		public virtual ZioConfigEntry<T> Bind<T>(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription = null)
		{
			if (!TomlTypeConverter.CanConvert(typeof(T)))
			{
				throw new ArgumentException(string.Format("Type {0} is not supported by the config system. Supported types: {1}", typeof(T), string.Join(", ", (from x in TomlTypeConverter.GetSupportedTypes()
					select x.Name).ToArray())));
			}
			lock (_ioLock)
			{
				if (Entries.TryGetValue(configDefinition, out var value))
				{
					return (ZioConfigEntry<T>)value;
				}
				ZioConfigEntry<T> zioConfigEntry = new ZioConfigEntry<T>(configDefinition, defaultValue, configDescription);
				Entries[configDefinition] = zioConfigEntry;
				zioConfigEntry.SettingChanged += OnSettingChanged;
				if (OrphanedEntries.TryGetValue(configDefinition, out var value2))
				{
					zioConfigEntry.SetSerializedValue(value2);
					OrphanedEntries.Remove(configDefinition);
				}
				if (SaveOnConfigSet)
				{
					Save();
				}
				return zioConfigEntry;
			}
		}

		public ZioConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_001b: Expected O, but got Unknown
			return Bind(new ConfigDefinition(section, key), defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		public ZioConfigEntry<T> Bind<T>(string section, string key, T defaultValue, ConfigDescription configDescription = null)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			return Bind(new ConfigDefinition(section, key), defaultValue, configDescription);
		}

		public IEnumerator<KeyValuePair<ConfigDefinition, ZioConfigEntryBase>> GetEnumerator()
		{
			return Entries.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		void ICollection<KeyValuePair<ConfigDefinition, ZioConfigEntryBase>>.Add(KeyValuePair<ConfigDefinition, ZioConfigEntryBase> item)
		{
			lock (_ioLock)
			{
				Entries.Add(item.Key, item.Value);
			}
		}

		public bool Contains(KeyValuePair<ConfigDefinition, ZioConfigEntryBase> item)
		{
			return Entries.Contains(item);
		}

		public void CopyTo(KeyValuePair<ConfigDefinition, ZioConfigEntryBase>[] array, int arrayIndex)
		{
			lock (_ioLock)
			{
				((ICollection<KeyValuePair<ConfigDefinition, ZioConfigEntryBase>>)Entries).CopyTo(array, arrayIndex);
			}
		}

		public bool Remove(KeyValuePair<ConfigDefinition, ZioConfigEntryBase> item)
		{
			lock (_ioLock)
			{
				return Entries.Remove(item.Key);
			}
		}

		public bool ContainsKey(ConfigDefinition key)
		{
			lock (_ioLock)
			{
				return Entries.ContainsKey(key);
			}
		}

		public void Add(ConfigDefinition key, ZioConfigEntryBase value)
		{
			throw new InvalidOperationException("Directly adding a config entry is not supported");
		}

		public bool Remove(ConfigDefinition key)
		{
			lock (_ioLock)
			{
				return Entries.Remove(key);
			}
		}

		public void Clear()
		{
			lock (_ioLock)
			{
				Entries.Clear();
			}
		}

		public bool TryGetValue(ConfigDefinition key, out ZioConfigEntryBase value)
		{
			lock (_ioLock)
			{
				return Entries.TryGetValue(key, out value);
			}
		}
	}
	[BepInPlugin("bubbet.zioconfigfile", "Zio Config File", "1.0.1")]
	public class ZioConfigFilePlugin : BaseUnityPlugin
	{
	}
}