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.Core;
using CSync.Lib;
using CSync.Patches;
using CSync.Util;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
[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\nAllows serialization of a ConfigEntry with a drop in replacement.\r\n\r\nThe wiki/usage guide can be found on GitHub.\r\nhttps://github.com/Owen3H/CSync/wiki\r\n ")]
[assembly: AssemblyFileVersion("3.0.0.0")]
[assembly: AssemblyInformationalVersion("3.0.0+a03bd481a153bbd87607e6805f3162820eb4222a")]
[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("3.0.0.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", "3.0.0")]
public class Plugin : BaseUnityPlugin
{
public const string GUID = "io.github.CSync";
public const string NAME = "CSync";
public const string VERSION = "3.0.0";
private Harmony Patcher;
internal static ManualLogSource Logger { get; private set; }
internal static CSyncConfig Config { get; private set; }
private void Awake()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
Config = new CSyncConfig(((BaseUnityPlugin)this).Config);
if (!Config.ENABLE_PATCHING.Value)
{
return;
}
try
{
Patcher = new Harmony("io.github.CSync");
Patcher.PatchAll(typeof(NetworkManagerPatch));
}
catch (Exception arg)
{
Logger.LogError((object)$"Failed to apply necessary patches!!\n{arg}");
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "CSync";
public const string PLUGIN_NAME = "CSync";
public const string PLUGIN_VERSION = "3.0.0";
}
}
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, ConfigDefinition definition, V defaultVal, ConfigDescription desc = null)
{
return cfg.Bind<V>(definition, defaultVal, desc).ToSyncedEntry<V>();
}
public static SyncedEntry<V> BindSyncedEntry<V>(this ConfigFile cfg, ConfigDefinition definition, V defaultValue, string desc)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Expected O, but got Unknown
return cfg.Bind<V>(definition, defaultValue, new ConfigDescription(desc, (AcceptableValueBase)null, Array.Empty<object>())).ToSyncedEntry<V>();
}
public static SyncedEntry<V> BindSyncedEntry<V>(this ConfigFile cfg, string section, string key, V defaultValue, ConfigDescription desc = null)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
return cfg.Bind<V>(new ConfigDefinition(section, key), defaultValue, desc).ToSyncedEntry<V>();
}
public static SyncedEntry<V> BindSyncedEntry<V>(this ConfigFile cfg, string section, string key, V defaultValue, string desc)
{
//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 cfg.Bind<V>(new ConfigDefinition(section, key), defaultValue, new ConfigDescription(desc, (AcceptableValueBase)null, Array.Empty<object>())).ToSyncedEntry<V>();
}
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_0026: Unknown result type (might be due to invalid IL or missing references)
bool flag = ((FastBufferWriter)(ref stream)).Capacity > 1300;
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(guid + "_" + label, clientId, stream, (NetworkDelivery)(flag ? 4 : 2));
}
}
}
namespace CSync.Util.Types
{
[Serializable]
public class SColor
{
public float r;
public float g;
public float b;
public float a;
public static implicit operator Color(SColor col)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new Color(col.r, col.g, col.b, col.a);
}
public SColor(Color color)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
SetRGBA(color);
}
public SColor(string hex)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
Color rGBA = default(Color);
ColorUtility.TryParseHtmlString(hex, ref rGBA);
SetRGBA(rGBA);
}
public void SetRGBA(Color color)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
r = color.r;
g = color.g;
b = color.b;
a = color.a;
}
public Color AsColor()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new Color(r, g, b, a);
}
public string AsHex()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return ColorUtility.ToHtmlStringRGBA(AsColor());
}
}
[Serializable]
public class SQuaternion
{
public float x;
public float y;
public float z;
public float w;
public SQuaternion(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
base..ctor();
}
public override string ToString()
{
return $"[{x}, {y}, {z}, {w}]";
}
public static implicit operator Quaternion(SQuaternion sq)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new Quaternion(sq.x, sq.y, sq.z, sq.w);
}
public static implicit operator SQuaternion(Quaternion q)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new SQuaternion(q.x, q.y, q.z, q.w);
}
}
[Serializable]
public class SVector2
{
public float x;
public float y;
public SVector2(float _x, float _y)
{
x = _x;
y = _y;
base..ctor();
}
public override string ToString()
{
return $"[{x}, {y}]";
}
public static implicit operator SVector2(SVector3 sv2)
{
return new SVector2(sv2.x, sv2.y);
}
public static implicit operator SVector2(Vector3 v2)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return new SVector2(v2.x, v2.y);
}
}
[Serializable]
public class SVector3
{
public float x;
public float y;
public float z;
public SVector3(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
base..ctor();
}
public override string ToString()
{
return $"[{x}, {y}, {z}]";
}
public static implicit operator Vector3(SVector3 sv3)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(sv3.x, sv3.y, sv3.z);
}
public static implicit operator SVector3(Vector3 v3)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
return new SVector3(v3.x, v3.y, v3.z);
}
}
[Serializable]
public class SVector4
{
public float x;
public float y;
public float z;
public float w;
public SVector4(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
base..ctor();
}
public override string ToString()
{
return $"[{x}, {y}, {z}, {w}]";
}
public static implicit operator Vector4(SVector4 sv4)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new Vector4(sv4.x, sv4.y, sv4.z, sv4.w);
}
public static implicit operator SVector4(Vector4 v4)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new SVector4(v4.x, v4.y, v4.z, v4.w);
}
}
}
namespace CSync.Patches
{
[HarmonyPatch(typeof(NetworkConnectionManager))]
internal class NetworkManagerPatch
{
private static bool HasAuthority
{
get
{
if (!NetworkManager.Singleton.IsHost)
{
return NetworkManager.Singleton.IsServer;
}
return true;
}
}
[HarmonyPostfix]
[HarmonyPatch("InvokeOnClientConnectedCallback")]
private static void OnConnected(ulong clientId)
{
ConfigManager.SyncInstances();
if (!HasAuthority)
{
Plugin.Logger.LogDebug((object)$"Client connected with id: {clientId}");
}
}
}
}
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.RegisterMessages();
});
}
internal static void RevertSyncedInstances()
{
CollectionExtensions.Do<ISynchronizable>((IEnumerable<ISynchronizable>)Instances.Values, (Action<ISynchronizable>)delegate(ISynchronizable i)
{
i.RevertSync();
});
}
}
public interface ISynchronizable
{
void RegisterMessages();
void RequestSync();
void RevertSync();
}
[Serializable]
public class SyncedConfig<T> : SyncedInstance<T>, ISynchronizable where T : class
{
public readonly string GUID;
[NonSerialized]
public Action<ulong> SyncRequested;
[NonSerialized]
public Action SyncReceived;
internal SyncedEntry<bool> SYNC_TO_CLIENTS { get; private set; }
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);
}
private void RegisterMessage(string name, HandleNamedMessageDelegate callback)
{
SyncedInstance<T>.MessageManager.RegisterNamedMessageHandler(GUID + "_" + name, callback);
}
internal void OnSyncRequested(ulong clientId)
{
SyncRequested?.Invoke(clientId);
}
internal void OnSyncReceived()
{
SyncReceived?.Invoke();
}
protected void EnableHostSyncControl(SyncedEntry<bool> hostSyncControlOption)
{
SYNC_TO_CLIENTS = hostSyncControlOption;
hostSyncControlOption.SettingChanged += delegate
{
SYNC_TO_CLIENTS = hostSyncControlOption;
};
}
void ISynchronizable.RegisterMessages()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Expected O, but got Unknown
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Expected O, but got Unknown
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (SyncedInstance<T>.IsHost)
{
RegisterMessage("OnRequestConfigSync", new HandleNamedMessageDelegate(OnRequestSync));
return;
}
RegisterMessage("OnHostDisabledSyncing", new HandleNamedMessageDelegate(OnHostDisabledSyncing));
RegisterMessage("OnReceiveConfigSync", new HandleNamedMessageDelegate(OnReceiveSync));
RequestSync();
}
void ISynchronizable.RequestSync()
{
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_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
if (!SyncedInstance<T>.IsHost)
{
return;
}
OnSyncRequested(clientId);
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 syncing disabled! Informing other clients..");
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($"{GUID} - Error syncing config instance!\n{arg}");
}
}
internal void OnHostDisabledSyncing(ulong _, FastBufferReader reader)
{
OnSyncCompleted(success: false);
LogDebug(GUID + " - The host has disabled syncing. Invoking the SyncComplete event..");
}
}
[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
{
[NonSerialized]
public Action<bool> SyncComplete;
[NonSerialized]
public Action SyncReverted;
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; }
internal void OnSyncCompleted(bool success)
{
SyncComplete?.Invoke(success);
}
internal void OnSyncReverted()
{
SyncReverted?.Invoke();
}
public void InitInstance(T instance)
{
Default = instance;
Instance = instance;
}
public void SyncInstance(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException("data", "Null value was passed the `SyncInstance` method.\nUnless you know what you are doing, calling this method is not advised!");
}
Instance = ByteSerializer<T>.DeserializeFromBytes(data);
OnSyncCompleted(Instance != null);
}
public void RevertSync()
{
Instance = Default;
OnSyncReverted();
}
}
}
namespace CSync.Core
{
internal class CSyncConfig
{
public ConfigEntry<bool> ENABLE_PATCHING { get; } = cfg.Bind<bool>("io.github.CSync", "bEnablePatching", true, "Whether to let CSync apply necessary patches.\nIt is not recommended to disable this unless all of your mods implement their own patches for syncing.");
public ConfigEntry<bool> GAME_DETECTION { get; } = cfg.Bind<bool>("io.github.CSync", "bGameDetection", true, "Should CSync automatically apply patches specific to the game currently running?\nTurning this off will not affect the core functionality of CSync, in some cases, it may solve issues.");
public CSyncConfig(ConfigFile cfg)
{
}
}
}