Decompiled source of CSync v2.2.4

BepInEx/plugins/CSync/CSync.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CSync.Lib;
using CSync.Util;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;

[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("Owen3H")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Configuration file syncing library for BepInEx.\r\n    Allows serialization of a ConfigEntry with a drop in replacement.\r\n      \r\n    The wiki/usage guide can be found on GitHub.\r\n    https://github.com/Owen3H/CSync/wiki\r\n    ")]
[assembly: AssemblyFileVersion("2.2.4.0")]
[assembly: AssemblyInformationalVersion("2.2.4+1fbc1b3bc4c5674d2ca3be9d672c43666910f444")]
[assembly: AssemblyProduct("CSync")]
[assembly: AssemblyTitle("CSync")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Owen3H/CSync.git")]
[assembly: NeutralResourcesLanguage("en-GB")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.2.4.0")]
[module: UnverifiableCode]
[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 CSync
{
	[BepInPlugin("io.github.CSync", "CSync", "2.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		private const string GUID = "io.github.CSync";

		private const string NAME = "CSync";

		private const string VERSION = "2.2.4";

		private Harmony Patcher;

		internal static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			try
			{
				Patcher = new Harmony("io.github.CSync");
				Patcher.PatchAll();
				Logger.LogInfo((object)"CSync successfully applied patches.");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)ex);
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "CSync";

		public const string PLUGIN_NAME = "CSync";

		public const string PLUGIN_VERSION = "2.2.4";
	}
}
namespace CSync.Util
{
	[Serializable]
	public class ByteSerializer<T>
	{
		[NonSerialized]
		private static readonly DataContractSerializer Serializer = new DataContractSerializer(typeof(T));

		public static int IntSize => 4;

		public static byte[] SerializeToBytes(T val)
		{
			using MemoryStream memoryStream = new MemoryStream();
			Serializer.WriteObject(memoryStream, val);
			return memoryStream.ToArray();
		}

		public static T DeserializeFromBytes(byte[] data)
		{
			using MemoryStream stream = new MemoryStream(data);
			try
			{
				return (T)Serializer.ReadObject(stream);
			}
			catch (Exception)
			{
				return default(T);
			}
		}
	}
	public static class Extensions
	{
		public static SyncedEntry<V> BindSyncedEntry<V>(this ConfigFile cfg, string section, string key, V defaultVal, string desc)
		{
			return cfg.Bind<V>(section, key, defaultVal, desc).ToSyncedEntry<V>();
		}

		public static SyncedEntry<V> BindSyncedEntry<V>(this ConfigFile cfg, string section, string key, V defaultVal, ConfigDescription desc)
		{
			return cfg.BindSyncedEntry(section, key, defaultVal, desc.Description);
		}

		public static SyncedEntry<T> BindSyncedEntry<T>(this ConfigFile cfg, ConfigDefinition definition, T defaultValue, ConfigDescription desc = null)
		{
			return cfg.BindSyncedEntry(definition.Section, definition.Key, defaultValue, desc.Description);
		}

		public static SyncedEntry<T> BindSyncedEntry<T>(this ConfigFile cfg, ConfigDefinition definition, T defaultValue, string desc)
		{
			return cfg.BindSyncedEntry(definition.Section, definition.Key, defaultValue, desc);
		}

		public static SyncedEntry<V> ToSyncedEntry<V>(this ConfigEntry<V> entry)
		{
			return new SyncedEntry<V>(entry);
		}

		public static T GetObject<T>(this SerializationInfo info, string key)
		{
			return (T)info.GetValue(key, typeof(T));
		}

		internal static ConfigEntry<V> Reconstruct<V>(this ConfigFile cfg, SerializationInfo info)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition(info.GetString("Section"), info.GetString("Key"));
			ConfigDescription val2 = new ConfigDescription(info.GetString("Description"), (AcceptableValueBase)null, Array.Empty<object>());
			return cfg.Bind<V>(val, info.GetObject<V>("DefaultValue"), val2);
		}

		internal static void SendMessage(this FastBufferWriter stream, string guid, string label, ulong clientId = 0uL)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			bool num = ((FastBufferWriter)(ref stream)).Capacity > 1300;
			NetworkDelivery val = (NetworkDelivery)(num ? 4 : 2);
			if (num)
			{
				Plugin.Logger.LogDebug((object)($"{guid} - Size of stream ({((FastBufferWriter)(ref stream)).Capacity}) was past the max buffer size.\n" + "Config instance will be sent in fragments to avoid overflowing the buffer."));
			}
			NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(guid + "_" + label, clientId, stream, val);
		}
	}
}
namespace CSync.Patches
{
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class JoinPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("ConnectClientToPlayerObject")]
		private static void SyncOnJoin()
		{
			ConfigManager.SyncInstances();
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal class LeavePatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("StartDisconnect")]
		private static void RevertOnDisconnect()
		{
			ConfigManager.RevertSyncedInstances();
		}
	}
}
namespace CSync.Lib
{
	public class ConfigManager
	{
		internal static Dictionary<string, ConfigFile> FileCache = new Dictionary<string, ConfigFile>();

		internal static Dictionary<string, ISynchronizable> Instances = new Dictionary<string, ISynchronizable>();

		internal static ConfigFile GetConfigFile(string fileName)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			if (!FileCache.TryGetValue(fileName, out var value))
			{
				value = new ConfigFile(Path.Combine(Paths.ConfigPath, fileName), false);
				FileCache.Add(fileName, value);
			}
			return value;
		}

		public static void Register<T>(T config) where T : SyncedConfig<T>, ISynchronizable
		{
			string gUID = config.GUID;
			if (config == null)
			{
				Plugin.Logger.LogError((object)("An error occurred registering config: " + gUID + "\nConfig instance cannot be null!"));
			}
			if (Instances.ContainsKey(gUID))
			{
				Plugin.Logger.LogWarning((object)("Attempted to register config `" + gUID + "` after it has already been registered!"));
				return;
			}
			config.InitInstance(config);
			Instances.Add(gUID, config);
		}

		internal static void SyncInstances()
		{
			CollectionExtensions.Do<ISynchronizable>((IEnumerable<ISynchronizable>)Instances.Values, (Action<ISynchronizable>)delegate(ISynchronizable i)
			{
				i.SetupSync();
			});
		}

		internal static void RevertSyncedInstances()
		{
			CollectionExtensions.Do<ISynchronizable>((IEnumerable<ISynchronizable>)Instances.Values, (Action<ISynchronizable>)delegate(ISynchronizable i)
			{
				i.RevertSync();
			});
		}
	}
	public interface ISynchronizable
	{
		void SetupSync();

		void RevertSync();
	}
	[Serializable]
	public class SyncedConfig<T> : SyncedInstance<T>, ISynchronizable where T : class
	{
		public readonly string GUID;

		internal SyncedEntry<bool> SYNC_TO_CLIENTS { get; private set; }

		public event EventHandler SyncRequested;

		public event EventHandler SyncReceived;

		public SyncedConfig(string guid)
		{
			GUID = guid;
			base..ctor();
		}

		private static void LogErr(string str)
		{
			Plugin.Logger.LogError((object)str);
		}

		private static void LogDebug(string str)
		{
			Plugin.Logger.LogDebug((object)str);
		}

		internal void OnSyncRequested()
		{
			this.SyncRequested?.Invoke(this, EventArgs.Empty);
		}

		internal void OnSyncReceived()
		{
			this.SyncReceived?.Invoke(this, EventArgs.Empty);
		}

		protected void EnableHostSyncControl(SyncedEntry<bool> hostSyncControlOption)
		{
			SYNC_TO_CLIENTS = hostSyncControlOption;
			hostSyncControlOption.SettingChanged += delegate
			{
				SYNC_TO_CLIENTS = hostSyncControlOption;
			};
		}

		void ISynchronizable.SetupSync()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (SyncedInstance<T>.IsHost)
			{
				SyncedInstance<T>.MessageManager.RegisterNamedMessageHandler(GUID + "_OnRequestConfigSync", new HandleNamedMessageDelegate(OnRequestSync));
				return;
			}
			SyncedInstance<T>.MessageManager.RegisterNamedMessageHandler(GUID + "_OnHostDisabledSyncing", new HandleNamedMessageDelegate(OnHostDisabledSyncing));
			SyncedInstance<T>.MessageManager.RegisterNamedMessageHandler(GUID + "_OnReceiveConfigSync", new HandleNamedMessageDelegate(OnReceiveSync));
			RequestSync();
		}

		private void RequestSync()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!SyncedInstance<T>.IsClient)
			{
				return;
			}
			FastBufferWriter stream = default(FastBufferWriter);
			((FastBufferWriter)(ref stream))..ctor(ByteSerializer<T>.IntSize, (Allocator)2, -1);
			try
			{
				stream.SendMessage(GUID, "OnRequestConfigSync", 0uL);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref stream)).Dispose();
			}
		}

		internal void OnRequestSync(ulong clientId, FastBufferReader _)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (!SyncedInstance<T>.IsHost)
			{
				return;
			}
			OnSyncRequested();
			if (SYNC_TO_CLIENTS != null && !SYNC_TO_CLIENTS)
			{
				FastBufferWriter stream = default(FastBufferWriter);
				((FastBufferWriter)(ref stream))..ctor(ByteSerializer<T>.IntSize, (Allocator)2, -1);
				try
				{
					stream.SendMessage(GUID, "OnHostDisabledSyncing", clientId);
					LogDebug(GUID + " - The host (you) has disabled syncing, sending clients a message!");
					return;
				}
				finally
				{
					((IDisposable)(FastBufferWriter)(ref stream)).Dispose();
				}
			}
			LogDebug($"{GUID} - Config sync request received from client: {clientId}");
			byte[] array = ByteSerializer<T>.SerializeToBytes(SyncedInstance<T>.Instance);
			int num = array.Length;
			FastBufferWriter stream2 = default(FastBufferWriter);
			((FastBufferWriter)(ref stream2))..ctor(num + ByteSerializer<T>.IntSize, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref stream2)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref stream2)).WriteBytesSafe(array, -1, 0);
				stream2.SendMessage(GUID, "OnReceiveConfigSync", clientId);
			}
			catch (Exception arg)
			{
				LogErr($"{GUID} - Error occurred syncing config with client: {clientId}\n{arg}");
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref stream2)).Dispose();
			}
		}

		internal void OnReceiveSync(ulong _, FastBufferReader reader)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			OnSyncReceived();
			if (!((FastBufferReader)(ref reader)).TryBeginRead(ByteSerializer<T>.IntSize))
			{
				LogErr(GUID + " - Config sync error: Could not begin reading buffer.");
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
			{
				LogErr(GUID + " - Config sync error: Host could not sync.");
				return;
			}
			byte[] data = new byte[num];
			((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
			try
			{
				SyncInstance(data);
			}
			catch (Exception arg)
			{
				LogErr($"Error syncing config instance!\n{arg}");
			}
		}

		internal void OnHostDisabledSyncing(ulong _, FastBufferReader reader)
		{
			OnSyncCompleted();
			LogDebug(GUID + " - Host disabled syncing. The SyncComplete event will still be invoked.");
		}
	}
	[Serializable]
	public class SyncedEntry<V> : ISerializable
	{
		[NonSerialized]
		public readonly ConfigEntry<V> Entry;

		private string ConfigFileName => Path.GetFileName(((ConfigEntryBase)Entry).ConfigFile.ConfigFilePath);

		public string Key => ((ConfigEntryBase)Entry).Definition.Key;

		public string Section => ((ConfigEntryBase)Entry).Definition.Section;

		public string Description => ((ConfigEntryBase)Entry).Description.Description;

		public object DefaultValue => ((ConfigEntryBase)Entry).DefaultValue;

		public V Value
		{
			get
			{
				return Entry.Value;
			}
			set
			{
				Entry.Value = value;
			}
		}

		public event EventHandler SettingChanged
		{
			add
			{
				Entry.SettingChanged += value;
			}
			remove
			{
				Entry.SettingChanged -= value;
			}
		}

		public static implicit operator V(SyncedEntry<V> e)
		{
			return e.Value;
		}

		public SyncedEntry(ConfigEntry<V> cfgEntry)
		{
			Entry = cfgEntry;
		}

		private SyncedEntry(SerializationInfo info, StreamingContext ctx)
		{
			ConfigFile configFile = ConfigManager.GetConfigFile(info.GetString("ConfigFileName"));
			Entry = configFile.Reconstruct<V>(info);
			Value = info.GetObject<V>("CurrentValue");
		}

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("ConfigFileName", ConfigFileName);
			info.AddValue("Key", Key);
			info.AddValue("Section", Section);
			info.AddValue("Description", Description);
			info.AddValue("DefaultValue", DefaultValue);
			info.AddValue("CurrentValue", Value);
		}

		public override string ToString()
		{
			return $"Key: {Key}\nDefault Value: {DefaultValue}\nCurrent Value: {Value}";
		}
	}
	[Serializable]
	public class SyncedInstance<T> : ByteSerializer<T> where T : class
	{
		public static bool Synced;

		public static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;

		public static bool IsClient => NetworkManager.Singleton.IsClient;

		public static bool IsHost => NetworkManager.Singleton.IsHost;

		public static T Default { get; private set; }

		public static T Instance { get; private set; }

		public event EventHandler SyncComplete;

		public event EventHandler SyncReverted;

		internal void OnSyncCompleted()
		{
			this.SyncComplete?.Invoke(this, EventArgs.Empty);
		}

		internal void OnSyncReverted()
		{
			this.SyncReverted?.Invoke(this, EventArgs.Empty);
		}

		public void InitInstance(T instance)
		{
			Default = instance;
			Instance = instance;
		}

		public void SyncInstance(byte[] data)
		{
			Instance = ByteSerializer<T>.DeserializeFromBytes(data);
			Synced = Instance != null;
			OnSyncCompleted();
		}

		public void RevertSync()
		{
			Instance = Default;
			Synced = false;
			OnSyncReverted();
		}
	}
}