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();
}
}
}