Decompiled source of AutoSync v1.0.0

AutoSync.dll

Decompiled 6 days ago
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AutoSync")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AutoSync")]
[assembly: AssemblyTitle("AutoSync")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 AutoSync
{
	[BepInPlugin("Harchytek.AutoSync", "AutoSync", "1.0.0")]
	public class AutoSyncPlugin : BaseUnityPlugin
	{
		private const string ModGUID = "Harchytek.AutoSync";

		private const string ModName = "AutoSync";

		private const string ModVersion = "1.0.0";

		public static ManualLogSource MLog;

		private ConfigEntry<bool> ConfigEnabled;

		private ConfigEntry<bool> ConfigAutoDisable;

		private ConfigEntry<bool> ConfigUserCustomEnabled;

		private ConfigEntry<string> ConfigSourceProfile;

		private ConfigEntry<string> ConfigFilesToSync;

		private ConfigEntry<string> ConfigExternalSources;

		private ConfigEntry<string> ConfigExternalDestinations;

		private ConfigFile UserConfigFile;

		private ConfigEntry<string> ConfigUserSourceProfile;

		private ConfigEntry<bool> ConfigUserCustomConfigSync;

		private ConfigEntry<string> ConfigUserFilesToSync;

		private ConfigEntry<string> ConfigUserExternalSources;

		private ConfigEntry<string> ConfigUserExternalDestinations;

		private void Awake()
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			MLog = ((BaseUnityPlugin)this).Logger;
			ConfigEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enabled", true, "Set to 'true' to synchronize on startup.");
			ConfigAutoDisable = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "AutoDisable", false, "If 'true', the 'Enabled' option will automatically revert to 'false' after a successful synchronization.");
			ConfigUserCustomEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "UserCustomEnabled", true, "Set to 'true' to allow synchronization of personal user files and settings from UsersCustom.cfg.");
			ConfigSourceProfile = ((BaseUnityPlugin)this).Config.Bind<string>("2. ModManager Source", "SourceProfile", "LastProfile", "Set to 'LastProfile' to use the last modified profile from the manager, or specify a precise profile name/path.");
			ConfigFilesToSync = ((BaseUnityPlugin)this).Config.Bind<string>("2. ModManager Source", "FilesToSync", "", "Files to synchronize from the mod manager profile source.\nExample value: BepInEx/config/quick_connect_servers.cfg");
			ConfigExternalSources = ((BaseUnityPlugin)this).Config.Bind<string>("3. External Source", "ExternalSources", "", "List of full paths for external files to copy, separated by commas.\nExample value: %USERPROFILE%/Downloads/HDPortalFX/HDPortalFX.dll");
			ConfigExternalDestinations = ((BaseUnityPlugin)this).Config.Bind<string>("3. External Source", "ExternalDestinations", "", "List of corresponding destination paths (in the same order), separated by commas.\nExample value: plugins/HDPortalFX.dll");
			string text = "Harchytek.AutoSync.UsersCustom.cfg";
			string text2 = Path.Combine(Paths.ConfigPath, text);
			UserConfigFile = new ConfigFile(text2, true);
			ConfigUserSourceProfile = UserConfigFile.Bind<string>("1. Source", "SourceProfile", "LastProfile", "Source profile to pull personal files from. Set to 'LastProfile' or specify a profile name/path.");
			ConfigUserCustomConfigSync = UserConfigFile.Bind<bool>("1. Source", "UserCustomConfigSync", true, "Set to 'true' to automatically synchronize this UsersCustom.cfg file itself from the source profile.");
			ConfigUserFilesToSync = UserConfigFile.Bind<string>("2. Files", "UserFilesToSync", "", "Add here your personal files to synchronize from your user source profile, separated by commas.\nExample value: BepInEx/config/BepInEx.cfg");
			ConfigUserExternalSources = UserConfigFile.Bind<string>("3. External Source", "ExternalSources", "", "List of full paths for external personal files to copy, separated by commas.\nExample value: %USERPROFILE%/Downloads/MyMod.dll");
			ConfigUserExternalDestinations = UserConfigFile.Bind<string>("3. External Source", "ExternalDestinations", "", "List of corresponding destination paths for external personal files (in the same order), separated by commas.\nExample value: plugins/MyMod.dll");
			if (!ConfigEnabled.Value)
			{
				MLog.LogInfo((object)"Disabled in configuration.");
				return;
			}
			MLog.LogWarning((object)"Synchronization started...");
			try
			{
				bool flag = ExecuteDualSync(text);
				if (flag && ConfigAutoDisable.Value)
				{
					ConfigEnabled.Value = false;
					((BaseUnityPlugin)this).Config.Save();
					MLog.LogWarning((object)"Synchronization completed successfully. 'Enabled' set to false.");
				}
				else if (!flag && ConfigAutoDisable.Value)
				{
					MLog.LogWarning((object)"Synchronization completed with errors. 'Enabled' remains active to retry.");
				}
				else
				{
					MLog.LogWarning((object)"Synchronization completed.");
				}
			}
			catch (Exception ex)
			{
				MLog.LogError((object)("Critical error: " + ex.Message));
			}
		}

		private bool ExecuteDualSync(string userConfigFileName)
		{
			bool flag = true;
			string bepInExRootPath = Paths.BepInExRootPath;
			string text = Directory.GetParent(bepInExRootPath)?.FullName;
			string profilesDir = Directory.GetParent(text)?.FullName;
			string[] array = (from f in ConfigFilesToSync.Value.Split(',')
				select f.Trim() into f
				where !string.IsNullOrEmpty(f)
				select f.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar)).Distinct().ToArray();
			if (array.Length != 0)
			{
				flag &= SyncProfileFiles(array, ConfigSourceProfile.Value.Trim(), profilesDir, text, bepInExRootPath, "Modpack", isOptional: false);
			}
			if (ConfigUserCustomEnabled.Value)
			{
				string sourceSetting = ConfigUserSourceProfile.Value.Trim();
				if (ConfigUserCustomConfigSync.Value)
				{
					string text2 = Path.Combine("BepInEx", "config", userConfigFileName);
					SyncProfileFiles(new string[1] { text2 }, sourceSetting, profilesDir, text, bepInExRootPath, "User", isOptional: true);
					UserConfigFile.Reload();
				}
				string[] array2 = (from f in ConfigUserFilesToSync.Value.Split(',')
					select f.Trim() into f
					where !string.IsNullOrEmpty(f)
					select f.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar)).Distinct().ToArray();
				if (array2.Length != 0)
				{
					flag &= SyncProfileFiles(array2, sourceSetting, profilesDir, text, bepInExRootPath, "User", isOptional: false);
				}
				string text3 = ConfigUserExternalSources.Value.Trim();
				string text4 = ConfigUserExternalDestinations.Value.Trim();
				if (!string.IsNullOrEmpty(text3) && !string.IsNullOrEmpty(text4))
				{
					flag &= SyncExternalFiles(text3, text4, bepInExRootPath);
				}
			}
			string text5 = ConfigExternalSources.Value.Trim();
			string text6 = ConfigExternalDestinations.Value.Trim();
			if (!string.IsNullOrEmpty(text5) && !string.IsNullOrEmpty(text6))
			{
				flag &= SyncExternalFiles(text5, text6, bepInExRootPath);
			}
			return flag;
		}

		private bool SyncExternalFiles(string sourcesSetting, string destinationsSetting, string currentBepInEx)
		{
			bool result = true;
			string[] array = (from s in sourcesSetting.Split(',')
				select s.Trim() into s
				where !string.IsNullOrEmpty(s)
				select s).ToArray();
			string[] array2 = (from d in destinationsSetting.Split(',')
				select d.Trim() into d
				where !string.IsNullOrEmpty(d)
				select d).ToArray();
			int num = Math.Min(array.Length, array2.Length);
			if (num > 0)
			{
				MLog.LogWarning((object)$"Processing {num} external file(s)...");
				for (int num2 = 0; num2 < num; num2++)
				{
					string text = Environment.ExpandEnvironmentVariables(array[num2]);
					string text2 = (Path.IsPathRooted(text) ? text : Path.GetFullPath(text));
					string text3 = array2[num2];
					string text4 = text3.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
					if (text4.StartsWith("BepInEx" + Path.DirectorySeparatorChar))
					{
						text4 = text4.Substring(8);
					}
					string text5 = Path.Combine(currentBepInEx, text4);
					if (File.Exists(text2))
					{
						if (File.Exists(text5) && text5.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
						{
							MLog.LogWarning((object)("External .dll already present, skipped: " + Path.GetFileName(text5)));
							continue;
						}
						try
						{
							Directory.CreateDirectory(Path.GetDirectoryName(text5));
							File.Copy(text2, text5, overwrite: true);
							MLog.LogWarning((object)("External copy successful: " + Path.GetFileName(text5) + " -> External Source"));
						}
						catch (Exception ex)
						{
							MLog.LogError((object)("External copy error (" + Path.GetFileName(text5) + "): " + ex.Message));
							result = false;
						}
					}
					else
					{
						MLog.LogWarning((object)("External file not found (skipped): " + Path.GetFileName(text2)));
					}
				}
			}
			return result;
		}

		private bool SyncProfileFiles(string[] files, string sourceSetting, string profilesDir, string currentProfileRoot, string currentBepInEx, string prefixLabel, bool isOptional)
		{
			DirectoryInfo directoryInfo = null;
			if (string.Equals(sourceSetting, "LastProfile", StringComparison.OrdinalIgnoreCase))
			{
				if (!string.IsNullOrEmpty(profilesDir) && Directory.Exists(profilesDir))
				{
					directoryInfo = (from d in new DirectoryInfo(profilesDir).GetDirectories()
						where !d.FullName.Equals(currentProfileRoot, StringComparison.OrdinalIgnoreCase) && Directory.Exists(Path.Combine(d.FullName, "BepInEx"))
						orderby d.LastWriteTime descending
						select d).FirstOrDefault();
				}
			}
			else if (Path.IsPathRooted(sourceSetting))
			{
				if (Directory.Exists(sourceSetting))
				{
					directoryInfo = new DirectoryInfo(sourceSetting);
				}
			}
			else
			{
				string path = Path.Combine(profilesDir, sourceSetting);
				if (Directory.Exists(path))
				{
					directoryInfo = new DirectoryInfo(path);
				}
			}
			if (directoryInfo == null)
			{
				if (string.Equals(sourceSetting, "LastProfile", StringComparison.OrdinalIgnoreCase))
				{
					MLog.LogWarning((object)"No other mod manager profile detected (first launch).");
					return true;
				}
				string fileName = Path.GetFileName(sourceSetting.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
				MLog.LogError((object)("Profile not found: '" + fileName + "'."));
				return false;
			}
			bool result = true;
			foreach (string text in files)
			{
				string text2 = Path.Combine(directoryInfo.FullName, text);
				string path2 = (text.StartsWith("BepInEx") ? text.Substring(8) : text);
				string text3 = Path.Combine(currentBepInEx, path2);
				if (File.Exists(text2))
				{
					if (File.Exists(text3) && text3.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
					{
						MLog.LogWarning((object)(prefixLabel + ": .dll already present, skipped " + Path.GetFileName(text3)));
						continue;
					}
					try
					{
						Directory.CreateDirectory(Path.GetDirectoryName(text3));
						File.Copy(text2, text3, overwrite: true);
						string fileName2 = Path.GetFileName(text3);
						MLog.LogWarning((object)(prefixLabel + " copy successful: " + fileName2 + " -> " + directoryInfo.Name));
					}
					catch (Exception ex)
					{
						MLog.LogError((object)("Error copying " + Path.GetFileName(text3) + ": " + ex.Message));
						result = false;
					}
				}
				else if (isOptional)
				{
					MLog.LogWarning((object)(prefixLabel + ": Optional config not found in source (skipped)"));
				}
				else
				{
					MLog.LogError((object)("Profile file not found: " + Path.GetFileName(text2)));
					result = false;
				}
			}
			return result;
		}
	}
}