Decompiled source of ConditionalConfigSync v1.0.10

ConditionalConfigSync.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Conditional Config Sync")]
[assembly: AssemblyDescription("Shared config synchronization and server policy library for Valheim mods.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("shudnal")]
[assembly: AssemblyProduct("Conditional Config Sync")]
[assembly: AssemblyCopyright("Copyright © shudnal 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("566458c7-717b-4583-af37-a69e4cd02966")]
[assembly: AssemblyFileVersion("1.0.10")]
[assembly: AssemblyInformationalVersion("1.0.10")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/shudnal/ConditionalConfigSync")]
[assembly: AssemblyMetadata("License", "Unlicense")]
[assembly: InternalsVisibleTo("ConditionalConfigSync.Plugin")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ConditionalConfigSync
{
	[Description("Registers and synchronizes config entries and runtime values for one mod.")]
	public class ConditionalConfigSync
	{
		internal static class ConfigEntryOnSettingChangedPatch
		{
			internal static bool Prefix(ConfigEntryBase __instance)
			{
				OwnConfigEntryBase configData = GetConfigData(__instance);
				if (configData != null)
				{
					ConditionalConfigSync owningConfigSync = GetOwningConfigSync(configData);
					if (owningConfigSync != null && !owningConfigSync.configsBeingApplied.Contains(__instance) && !IsWritableConfig(configData))
					{
						owningConfigSync.RestoreRejectedConfigChange(__instance, configData, owningConfigSync.GetWriteRejectionReason(configData));
						return false;
					}
				}
				return true;
			}
		}

		internal static class ConfigEntryGetSerializedValuePatch
		{
			internal static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase configData = GetConfigData(__instance);
				if (configData == null || (IsWritableConfig(configData) && (!configData.HasLocalBaseValue || !ShouldStoreLocalConfigValue(configData))))
				{
					return true;
				}
				object obj = (configData.HasLocalBaseValue ? configData.LocalBaseValue : (configData.HasLastAcceptedValue ? configData.LastAcceptedValue : __instance.BoxedValue));
				__result = TomlTypeConverter.ConvertToString(obj, __instance.SettingType);
				return false;
			}
		}

		internal static class ConfigEntrySetSerializedValuePatch
		{
			internal static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase configData = GetConfigData(__instance);
				if (configData == null)
				{
					return true;
				}
				if (!ShouldStoreLocalConfigValue(configData) && IsWritableConfig(configData))
				{
					return true;
				}
				try
				{
					configData.StoreLocalBaseValue(TomlTypeConverter.ConvertToValue(value, __instance.SettingType));
				}
				catch (Exception ex)
				{
					LogSource.LogWarning((object)$"[ConfigFile] Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}");
				}
				return false;
			}
		}

		[Description("Diagnostic logging verbosity for ConditionalConfigSync.")]
		public enum ConditionalConfigSyncDebugLevel
		{
			Basic = 1,
			Verbose,
			Trace
		}

		private readonly struct ReceivedConfigState
		{
			public readonly bool ServerControlled;

			public readonly bool Hidden;

			public ReceivedConfigState(bool serverControlled, bool hidden)
			{
				ServerControlled = serverControlled;
				Hidden = hidden;
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();

			public readonly Dictionary<OwnConfigEntryBase, ReceivedConfigState> configStates = new Dictionary<OwnConfigEntryBase, ReceivedConfigState>();

			public readonly Dictionary<OwnConfigEntryBase, ReceivedConfigState> clientConfigStateClaims = new Dictionary<OwnConfigEntryBase, ReceivedConfigState>();

			public readonly List<PolicyStateChangedEventArgs> policyTransitions = new List<PolicyStateChangedEventArgs>();

			public int? capabilities;

			public string? rejectionReason;

			public int entryCount;

			public void Reject(string reason)
			{
				if (rejectionReason == null)
				{
					rejectionReason = reason;
				}
			}
		}

		private enum PackageEntryKind : byte
		{
			Config = 1,
			CustomValue,
			ServerVersion,
			LockExempt,
			ConfigState
		}

		private class PackageEntry
		{
			public PackageEntryKind kind;

			public string? section;

			public string? key;

			public Type? type;

			public object? value;

			public bool serverControlled;

			public bool hidden;

			public int? capabilities;

			public static PackageEntry ServerVersion(string version)
			{
				return new PackageEntry
				{
					kind = PackageEntryKind.ServerVersion,
					value = version
				};
			}

			public static PackageEntry LockExempt(bool value, int? capabilities = null)
			{
				return new PackageEntry
				{
					kind = PackageEntryKind.LockExempt,
					value = value,
					capabilities = capabilities
				};
			}

			public static PackageEntry ConfigState(ConfigEntryBase config, bool serverControlled, bool hidden)
			{
				return new PackageEntry
				{
					kind = PackageEntryKind.ConfigState,
					section = config.Definition.Section,
					key = config.Definition.Key,
					serverControlled = serverControlled,
					hidden = hidden
				};
			}

			public static PackageEntry CustomValue(CustomSyncedValueBase customValue, object? value)
			{
				return new PackageEntry
				{
					kind = PackageEntryKind.CustomValue,
					key = customValue.Identifier,
					type = customValue.Type,
					value = value
				};
			}
		}

		private class InvalidDeserializationTypeException : Exception
		{
			public string expected = null;

			public string received = null;

			public string field = "";
		}

		private enum ConfigPolicyOverride
		{
			Default,
			ForceServerControlled,
			ForceClientControlled
		}

		private enum ModRequirementPolicyOverride
		{
			Default,
			ForceRequired,
			ForceOptional
		}

		private sealed class SyncPolicyRecord
		{
			internal readonly string DisplayText;

			internal readonly string? Key;

			internal readonly ConfigPolicyOverride PolicyOverride;

			internal readonly string? Error;

			internal SyncPolicyRecord(string displayText, string? key, ConfigPolicyOverride policyOverride, string? error)
			{
				DisplayText = displayText;
				Key = key;
				PolicyOverride = policyOverride;
				Error = error;
			}
		}

		private sealed class ModRequirementPolicyRecord
		{
			internal readonly string DisplayText;

			internal readonly string? Key;

			internal readonly ModRequirementPolicyOverride PolicyOverride;

			internal readonly string? Error;

			internal ModRequirementPolicyRecord(string displayText, string? key, ModRequirementPolicyOverride policyOverride, string? error)
			{
				DisplayText = displayText;
				Key = key;
				PolicyOverride = policyOverride;
				Error = error;
			}
		}

		private sealed class HiddenPolicyRecord
		{
			internal readonly string DisplayText;

			internal readonly string? Key;

			internal readonly string? Error;

			internal HiddenPolicyRecord(string displayText, string? key, string? error)
			{
				DisplayText = displayText;
				Key = key;
				Error = error;
			}
		}

		private enum PolicyTargetFailure
		{
			None,
			Mod,
			Section,
			Config
		}

		private sealed class PolicyTargetResolution
		{
			internal ConditionalConfigSync? ConfigSync;

			internal readonly List<OwnConfigEntryBase> Configs = new List<OwnConfigEntryBase>();

			internal PolicyTargetFailure Failure;
		}

		internal static class TerminalInitPatch
		{
			internal static void Postfix()
			{
				RegisterDebugConsoleCommands();
			}
		}

		private sealed class SendSlot
		{
			internal readonly long Generation;

			internal readonly ZNet Session;

			internal readonly bool Sequenced;

			internal LinkedListNode<SendSlot>? Node;

			internal bool Waiting = true;

			internal bool Released;

			internal SendSlot(long generation, ZNet session, bool sequenced)
			{
				Generation = generation;
				Session = session;
				Sequenced = sequenced;
			}
		}

		internal readonly struct FullSyncSnapshotKey : IEquatable<FullSyncSnapshotKey>
		{
			internal readonly long Revision;

			internal readonly bool Admin;

			internal readonly string? ServerVersion;

			internal readonly int ConfigCount;

			internal readonly int CustomValueCount;

			internal readonly bool HasLockingConfig;

			internal readonly string? LockingConfigSection;

			internal readonly string? LockingConfigKey;

			internal readonly ConfigSyncMode LockingConfigSyncMode;

			internal readonly bool LockingConfigSynchronized;

			internal readonly bool LockingConfigServerControlled;

			internal readonly bool LockingConfigHidden;

			internal FullSyncSnapshotKey(long revision, bool admin, string? serverVersion, int configCount, int customValueCount, OwnConfigEntryBase? lockingConfig)
			{
				Revision = revision;
				Admin = admin;
				ServerVersion = serverVersion;
				ConfigCount = configCount;
				CustomValueCount = customValueCount;
				HasLockingConfig = lockingConfig != null;
				LockingConfigSection = ((lockingConfig != null) ? lockingConfig.BaseConfig.Definition.Section : null);
				LockingConfigKey = ((lockingConfig != null) ? lockingConfig.BaseConfig.Definition.Key : null);
				LockingConfigSyncMode = lockingConfig?.SyncMode ?? ConfigSyncMode.AlwaysServerControlled;
				LockingConfigSynchronized = lockingConfig?.SynchronizedConfig ?? false;
				LockingConfigServerControlled = lockingConfig?.IsServerControlled ?? false;
				LockingConfigHidden = lockingConfig?.IsHidden ?? false;
			}

			public bool Equals(FullSyncSnapshotKey other)
			{
				return Revision == other.Revision && Admin == other.Admin && string.Equals(ServerVersion, other.ServerVersion, StringComparison.Ordinal) && ConfigCount == other.ConfigCount && CustomValueCount == other.CustomValueCount && HasLockingConfig == other.HasLockingConfig && string.Equals(LockingConfigSection, other.LockingConfigSection, StringComparison.Ordinal) && string.Equals(LockingConfigKey, other.LockingConfigKey, StringComparison.Ordinal) && LockingConfigSyncMode == other.LockingConfigSyncMode && LockingConfigSynchronized == other.LockingConfigSynchronized && LockingConfigServerControlled == other.LockingConfigServerControlled && LockingConfigHidden == other.LockingConfigHidden;
			}

			public override bool Equals(object? obj)
			{
				return obj is FullSyncSnapshotKey other && Equals(other);
			}

			public override int GetHashCode()
			{
				long revision = Revision;
				int hashCode = revision.GetHashCode();
				int num = hashCode * 397;
				bool admin = Admin;
				hashCode = num ^ admin.GetHashCode();
				hashCode = (hashCode * 397) ^ (ServerVersion?.GetHashCode() ?? 0);
				hashCode = (hashCode * 397) ^ ConfigCount;
				hashCode = (hashCode * 397) ^ CustomValueCount;
				int num2 = hashCode * 397;
				admin = HasLockingConfig;
				hashCode = num2 ^ admin.GetHashCode();
				hashCode = (hashCode * 397) ^ (LockingConfigSection?.GetHashCode() ?? 0);
				hashCode = (hashCode * 397) ^ (LockingConfigKey?.GetHashCode() ?? 0);
				hashCode = (hashCode * 397) ^ (int)LockingConfigSyncMode;
				int num3 = hashCode * 397;
				admin = LockingConfigSynchronized;
				hashCode = num3 ^ admin.GetHashCode();
				int num4 = hashCode * 397;
				admin = LockingConfigServerControlled;
				hashCode = num4 ^ admin.GetHashCode();
				int num5 = hashCode * 397;
				admin = LockingConfigHidden;
				return num5 ^ admin.GetHashCode();
			}
		}

		private sealed class FullSyncSnapshot
		{
			internal FullSyncSnapshotKey Key;

			internal int RawSize;

			internal int WireSize;

			internal bool Compressed;

			internal bool SerializationMeasured;

			internal bool CompressionMeasured;

			internal double SerializationMilliseconds;

			internal double CompressionMilliseconds;

			internal byte[] WireBytes = Array.Empty<byte>();
		}

		private sealed class PendingSequencedPackage
		{
			internal readonly SendSlot Reservation;

			internal ZPackage? Package;

			internal PendingSequencedPackage(SendSlot reservation)
			{
				Reservation = reservation;
			}
		}

		internal static class ZNetUpdatePatch
		{
			internal static void Postfix()
			{
				DrainMainThreadQueue();
				FlushPendingBroadcastsForAllIfIdle();
			}
		}

		internal static class ZNetAwakePatch
		{
			internal static void Postfix(ZNet __instance)
			{
				EnsureDebugSupportInitialized();
				isServer = GameReflection.IsServer(__instance);
				sessionActive = true;
				if (isServer)
				{
					EnsurePolicySupportInitialized(createIfMissing: true);
				}
				ConditionalConfigSync[] array = configSyncs.ToArray();
				foreach (ConditionalConfigSync conditionalConfigSync in array)
				{
					conditionalConfigSync.RegisterForActiveSession();
				}
				if (isServer)
				{
					GameReflection.StartCoroutine(WatchAdminListChanges(), (MonoBehaviour?)(object)__instance);
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ConditionalConfigSync[] array2 = configSyncs.ToArray();
					foreach (ConditionalConfigSync configSync in array2)
					{
						configSync.StartBroadcastPackage(peers, () => configSync.ConfigsToPackage(null, null, new PackageEntry[1] { PackageEntry.LockExempt(isAdmin) }), sequenced: false, null);
					}
				}
				IEnumerator WatchAdminListChanges()
				{
					SyncedList adminList = GameReflection.GetAdminList(__instance) ?? throw new InvalidOperationException("ZNet admin list is unavailable.");
					List<string> currentList = GameReflection.GetSyncedListValues(adminList);
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!sessionActive || GameReflection.ZNetInstance != __instance)
						{
							break;
						}
						if (!GameReflection.GetSyncedListValues(adminList).SequenceEqual(currentList))
						{
							currentList = GameReflection.GetSyncedListValues(adminList);
							List<ZNetPeer> peers = GameReflection.GetPeers(__instance);
							List<ZNetPeer> adminPeer = peers.Where(IsPeerAdmin).ToList();
							List<ZNetPeer> nonAdminPeer = peers.Except(adminPeer).ToList();
							ConditionalConfigSync[] array2 = configSyncs.ToArray();
							foreach (ConditionalConfigSync sync in array2)
							{
								sync.DebugLog(ConditionalConfigSyncDebugLevel.Basic, "Admin", $"Admin list changed, admins={adminPeer.Count}, nonAdmins={nonAdminPeer.Count}");
							}
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		internal static class ZNetOnNewConnectionPatch
		{
			internal static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (!GameReflection.IsServer(__instance))
				{
					ConditionalConfigSync[] array = configSyncs.ToArray();
					foreach (ConditionalConfigSync conditionalConfigSync in array)
					{
						conditionalConfigSync.RegisterClientRpcHandler(peer);
					}
				}
			}
		}

		internal static class ZNetShutdownPatch
		{
			internal static void Postfix()
			{
				ConditionalConfigSync[] array = configSyncs.ToArray();
				sessionActive = false;
				ProcessingServerUpdate = true;
				lockExempt = false;
				ConditionalConfigSync[] array2 = array;
				foreach (ConditionalConfigSync conditionalConfigSync in array2)
				{
					conditionalConfigSync.ResetTransportState();
				}
				try
				{
					ConditionalConfigSync[] array3 = array;
					foreach (ConditionalConfigSync conditionalConfigSync2 in array3)
					{
						try
						{
							conditionalConfigSync2.DebugLog(ConditionalConfigSyncDebugLevel.Basic, "Shutdown", "Reset local values and source-of-truth state");
							conditionalConfigSync2.InitialSyncDone = false;
							conditionalConfigSync2.ResetConfigsFromServer();
							conditionalConfigSync2.IsSourceOfTruth = true;
							conditionalConfigSync2.ServerLockedSettingChanged();
						}
						catch (Exception arg)
						{
							conditionalConfigSync2.DebugWarning("Shutdown", $"Failed to reset one synchronization instance; continuing. Error: {arg}");
						}
					}
				}
				finally
				{
					ResetNetworkSessionState();
					isServer = false;
					ProcessingServerUpdate = false;
				}
				ConditionalConfigSync[] array4 = array;
				foreach (ConditionalConfigSync conditionalConfigSync3 in array4)
				{
					conditionalConfigSync3.InvokeEventHandlers(conditionalConfigSync3.ServerConnectionReset, "ServerConnectionReset");
				}
			}
		}

		internal static class ZNetRpcPeerInfoSyncPatch
		{
			internal class BufferingSocket : ZPlayFabSocket, ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				internal BufferingSocket(ISocket original)
				{
					Original = original;
				}

				public bool IsConnected()
				{
					return GameReflection.SocketIsConnected(Original);
				}

				public ZPackage Recv()
				{
					return GameReflection.SocketRecv(Original);
				}

				public int GetSendQueueSize()
				{
					return GameReflection.SocketGetSendQueueSize(Original);
				}

				public int GetCurrentSendRate()
				{
					return GameReflection.SocketGetCurrentSendRate(Original);
				}

				public bool IsHost()
				{
					return GameReflection.SocketIsHost(Original);
				}

				public void Dispose()
				{
					GameReflection.SocketDispose(Original);
				}

				public bool GotNewData()
				{
					return GameReflection.SocketGotNewData(Original);
				}

				public void Close()
				{
					GameReflection.SocketClose(Original);
				}

				public string GetEndPointString()
				{
					return GameReflection.SocketGetEndPointString(Original);
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					GameReflection.SocketGetAndResetStats(Original, out totalSent, out totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					GameReflection.SocketGetConnectionQuality(Original, out localQuality, out remoteQuality, out ping, out outByteSec, out inByteSec);
				}

				public ISocket Accept()
				{
					return GameReflection.SocketAccept(Original);
				}

				public int GetHostPort()
				{
					return GameReflection.SocketGetHostPort(Original);
				}

				public bool Flush()
				{
					return GameReflection.SocketFlush(Original);
				}

				public string GetHostName()
				{
					return GameReflection.SocketGetHostName(Original);
				}

				public void VersionMatch()
				{
					if (finished)
					{
						GameReflection.SocketVersionMatch(Original);
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				private static bool ShouldBufferInitialPackage(int methodHash)
				{
					return methodHash == GameReflection.StableHash("PeerInfo") || methodHash == GameReflection.StableHash("PlayerList") || methodHash == GameReflection.StableHash("HistoricalPlayerList") || methodHash == GameReflection.StableHash("AdminList") || methodHash == GameReflection.StableHash("RoutedRPC") || methodHash == GameReflection.StableHash("ZDOData") || methodHash == GameReflection.StableHash("ConditionalConfigSync RemoteConsumerSnapshot");
				}

				public void Send(ZPackage pkg)
				{
					int position = GameReflection.PackageGetPos(pkg);
					GameReflection.PackageSetPos(pkg, 0);
					int methodHash = GameReflection.PackageReadInt(pkg);
					GameReflection.PackageSetPos(pkg, position);
					if (!finished && ShouldBufferInitialPackage(methodHash))
					{
						ZPackage val = GameReflection.NewPackage(GameReflection.PackageGetArray(pkg));
						GameReflection.PackageSetPos(val, position);
						Package.Add(val);
					}
					else
					{
						GameReflection.SocketSend(Original, pkg);
					}
				}
			}

			internal static void Prefix(ref BufferingSocket? __state, ZNet __instance, ZRpc rpc)
			{
				if (!GameReflection.IsServer(__instance))
				{
					return;
				}
				BufferingSocket bufferingSocket = new BufferingSocket(GameReflection.GetRpcSocket(rpc) ?? throw new InvalidOperationException("RPC socket is unavailable."));
				GameReflection.SetRpcSocket(rpc, (ISocket)(object)bufferingSocket);
				ZNetPeer peer = GameReflection.GetPeer(rpc, __instance);
				if (peer != null && !object.Equals(GameReflection.GetOnlineBackend(), (object)(OnlineBackendType)0))
				{
					ISocket? peerSocket = GameReflection.GetPeerSocket(peer);
					ZPlayFabSocket val = (ZPlayFabSocket)(object)((peerSocket is ZPlayFabSocket) ? peerSocket : null);
					if (val != null)
					{
						GameReflection.SetPlayFabRemotePlayerId((ZPlayFabSocket)(object)bufferingSocket, GameReflection.GetPlayFabRemotePlayerId(val));
					}
					GameReflection.SetPeerSocket(peer, (ISocket)(object)bufferingSocket);
				}
				__state = bufferingSocket;
			}

			internal static void Postfix(BufferingSocket? __state, ZNet __instance, ZRpc rpc)
			{
				if (!GameReflection.IsServer(__instance) || __state == null)
				{
					return;
				}
				ZNetPeer peer = GameReflection.GetPeer(rpc, __instance);
				if (peer == null)
				{
					SendBufferedData();
					return;
				}
				KeyValuePair<ConditionalConfigSync, SendSlot?>[] initialSends = (from sync in configSyncs.ToArray()
					select new KeyValuePair<ConditionalConfigSync, SendSlot>(sync, sync.ReserveSendSlot())).ToArray();
				try
				{
					if (GameReflection.StartCoroutine(sendAsync(), (MonoBehaviour?)(object)__instance) == null)
					{
						ReleaseInitialSends();
						SendBufferedData();
					}
				}
				catch
				{
					ReleaseInitialSends();
					SendBufferedData();
					throw;
				}
				void ReleaseInitialSends()
				{
					KeyValuePair<ConditionalConfigSync, SendSlot>[] array = initialSends;
					for (int i = 0; i < array.Length; i++)
					{
						KeyValuePair<ConditionalConfigSync, SendSlot> keyValuePair = array[i];
						if (keyValuePair.Value != null)
						{
							keyValuePair.Key.ReleaseSendSlot(keyValuePair.Value);
						}
					}
				}
				void SendBufferedData()
				{
					BufferingSocket bufferingSocket = __state;
					if ((object)GameReflection.GetRpcSocket(rpc) == bufferingSocket)
					{
						GameReflection.SetRpcSocket(rpc, bufferingSocket.Original);
					}
					ZNetPeer peer2 = GameReflection.GetPeer(rpc, __instance);
					if (peer2 != null && (object)GameReflection.GetPeerSocket(peer2) == bufferingSocket)
					{
						GameReflection.SetPeerSocket(peer2, bufferingSocket.Original);
					}
					if (bufferingSocket.finished)
					{
						return;
					}
					bufferingSocket.finished = true;
					try
					{
						if (sessionActive && GameReflection.ZNetInstance == __instance && GameReflection.SocketIsConnected(bufferingSocket.Original))
						{
							for (int i = 0; i < bufferingSocket.Package.Count; i++)
							{
								if (i == bufferingSocket.versionMatchQueued)
								{
									GameReflection.SocketVersionMatch(bufferingSocket.Original);
								}
								GameReflection.SocketSend(bufferingSocket.Original, bufferingSocket.Package[i]);
							}
							if (bufferingSocket.Package.Count == bufferingSocket.versionMatchQueued)
							{
								GameReflection.SocketVersionMatch(bufferingSocket.Original);
							}
						}
					}
					finally
					{
						bufferingSocket.Package.Clear();
						bufferingSocket.versionMatchQueued = -1;
					}
				}
				IEnumerator sendAsync()
				{
					try
					{
						KeyValuePair<ConditionalConfigSync, SendSlot?>[] array = initialSends;
						for (int i = 0; i < array.Length; i++)
						{
							KeyValuePair<ConditionalConfigSync, SendSlot?> entry = array[i];
							if (entry.Value != null && entry.Key.IsCurrentSend(entry.Value))
							{
								yield return GameReflection.StartCoroutine(entry.Key.SendFullSyncPackage(peer, "InitialSync", "Sending full sync to", entry.Value), (MonoBehaviour?)(object)__instance);
							}
						}
					}
					finally
					{
						ReleaseInitialSends();
						SendBufferedData();
					}
				}
			}
		}

		[Description("True while an incoming synchronization package is being applied. Usually diagnostic only.")]
		public static bool ProcessingServerUpdate = false;

		[Description("Stable unique synchronization identifier, normally the owning mod GUID.")]
		public readonly string Name;

		[Description("Human-readable mod name used in logs.")]
		public string? DisplayName;

		[Description("Current version of the owning mod used for peer compatibility checks.")]
		public string? CurrentVersion;

		[Description("Oldest compatible remote mod version accepted by this instance.")]
		public string? MinimumRequiredVersion;

		[Description("Allows unlocked non-admin clients to publish changes. Disabled by default.")]
		public bool AllowClientConfigUpdatesWhenUnlocked = false;

		private bool? forceConfigLocking;

		private bool isSourceOfTruth = true;

		private static readonly HashSet<ConditionalConfigSync> configSyncs = new HashSet<ConditionalConfigSync>();

		private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>();

		private readonly HashSet<ConfigFile> observedConfigFiles = new HashSet<ConfigFile>();

		private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>();

		private static bool isServer;

		private static bool lockExempt = false;

		private OwnConfigEntryBase? lockedConfig = null;

		private bool? lastNotifiedLockState;

		private static readonly Regex assemblyVersionTypeIdentityPattern = new Regex(",\\s*Version=[^,\\]\\[]+", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

		[Description("Enables shared ConditionalConfigSync diagnostic logging programmatically.")]
		public static bool DebugLoggingEnabled = false;

		[Description("Selects diagnostic logging verbosity.")]
		public static ConditionalConfigSyncDebugLevel DebugLoggingLevel = ConditionalConfigSyncDebugLevel.Basic;

		[Description("Optional case-insensitive filter matched against mod sync names and display names.")]
		public static string DebugLoggingFilter = "";

		private static bool debugConfigEnabled;

		private static ConditionalConfigSyncDebugLevel debugConfigLevel = ConditionalConfigSyncDebugLevel.Basic;

		private static string debugConfigFilter = "";

		private static bool debugSupportInitialized;

		private static bool debugConfigReloadScheduled;

		private static bool debugCommandsRegistered;

		private static FileSystemWatcher? debugConfigWatcher;

		private static readonly object debugSupportLock = new object();

		private const int largeStringCustomValueWarningBytes = 131072;

		private readonly HashSet<string> largeStringCustomValueWarnings = new HashSet<string>(StringComparer.Ordinal);

		private const string SyncPolicyFileName = "ConditionalConfigSync.SyncPolicy.cfg";

		private const string HiddenConfigsFileName = "ConditionalConfigSync.HiddenConfigs.cfg";

		private const string ModRequirementsFileName = "ConditionalConfigSync.ModRequirements.cfg";

		private const string PolicyDumpFileName = "ConditionalConfigSync.PolicyDump.txt";

		private static readonly object policyLock = new object();

		private static bool policySupportInitialized;

		private static bool policyReloadScheduled;

		private static long policyReadGeneration;

		private static long policyAppliedGeneration;

		private static FileSystemWatcher? syncPolicyWatcher;

		private static FileSystemWatcher? hiddenConfigsWatcher;

		private static FileSystemWatcher? modRequirementsWatcher;

		private static Dictionary<string, ConfigPolicyOverride> syncPolicy = new Dictionary<string, ConfigPolicyOverride>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> hiddenConfigPolicy = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static Dictionary<string, ModRequirementPolicyOverride> modRequirementPolicy = new Dictionary<string, ModRequirementPolicyOverride>(StringComparer.OrdinalIgnoreCase);

		private const string PolicyChangeRpcSuffix = " ConditionalConfigSync Policy Change";

		private const int MaxPolicyChangeRequestSize = 4096;

		private const int MaxPolicyIdentifierLength = 1024;

		private const int PolicyChangeCapability = 1;

		private bool remotePolicyChangeSupported;

		private static ManualLogSource? logSource;

		private static readonly object runtimeLock = new object();

		private static bool runtimeInitialized;

		private static int mainThreadId;

		private static readonly object mainThreadQueueLock = new object();

		private static readonly Queue<Action> mainThreadQueue = new Queue<Action>();

		private static long mainThreadQueueGeneration;

		private const string ConfigDirectoryName = "shudnal.ConditionalConfigSync";

		private const string DebugConfigFileName = "ConditionalConfigSync.Debug.cfg";

		private static readonly object configDirectoryLock = new object();

		private static bool configDirectoryInitialized;

		private readonly LinkedList<SendSlot> sendQueue = new LinkedList<SendSlot>();

		private SendSlot? pendingStateSendSlot;

		private long transportGeneration;

		private int waitingSequencedSendCount;

		private bool initialSyncRepairRequested;

		private static int packagePreparationDepth;

		private static bool flushingAllPendingBroadcasts;

		private const string ResyncRpcSuffix = " ConditionalConfigSync Resync";

		private const int StableReadAttempts = 5;

		private const int StableReadDelayMilliseconds = 50;

		private const int FullSyncSnapshotBuildAttempts = 5;

		private const int FullSyncSnapshotStableFrames = 2;

		private readonly VersionCheck versionCheck;

		private bool serverRpcsRegistered;

		private readonly HashSet<ZRpc> registeredClientRpcs = new HashSet<ZRpc>();

		private readonly HashSet<OwnConfigEntryBase> lateRegisteredConfigs = new HashSet<OwnConfigEntryBase>();

		private readonly HashSet<CustomSyncedValueBase> lateRegisteredCustomValues = new HashSet<CustomSyncedValueBase>();

		private bool lateRegistrationSyncScheduled;

		private long fullSyncStateRevision = 1L;

		private FullSyncSnapshot? fullSyncAdminSnapshot;

		private FullSyncSnapshot? fullSyncNonAdminSnapshot;

		private static bool sessionActive;

		private static Harmony? runtimeHarmony;

		private int processingCount;

		private bool lastHandledPackageWasFull;

		private readonly HashSet<ConfigEntryBase> pendingConfigBroadcasts = new HashSet<ConfigEntryBase>();

		private readonly HashSet<CustomSyncedValueBase> pendingCustomValueBroadcasts = new HashSet<CustomSyncedValueBase>();

		private readonly LinkedList<PendingSequencedPackage> pendingSequencedCustomValuePackages = new LinkedList<PendingSequencedPackage>();

		private bool flushingPendingBroadcasts;

		private readonly HashSet<ConfigEntryBase> configsBeingApplied = new HashSet<ConfigEntryBase>();

		private readonly HashSet<CustomSyncedValueBase> customValuesBeingApplied = new HashSet<CustomSyncedValueBase>();

		private readonly Dictionary<long, long> authoritativeCorrectionTimes = new Dictionary<long, long>();

		private static readonly long AuthoritativeCorrectionIntervalTicks = TimeSpan.FromSeconds(1.0).Ticks;

		private const byte PARTIAL_CONFIGS = 1;

		private const byte FRAGMENTED_CONFIG = 2;

		private const byte COMPRESSED_CONFIG = 4;

		private const byte V2_PACKAGE = 8;

		private const int packageSliceSize = 250000;

		private const int maximumSendQueueSize = 20000;

		private const int compressMinSize = 10000;

		private const int maxPackageEntries = 8192;

		private const int maxPayloadSize = 20971520;

		private const int maxFragments = 128;

		private const int maxFragmentSize = 300000;

		private const int maxFragmentAssembliesPerSender = 4;

		private const int maxFragmentCacheBytesPerSender = 20971520;

		private const int maxFragmentCacheBytesGlobal = 67108864;

		private const int maxPendingSequencedUpdates = 100;

		private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>();

		private readonly Dictionary<string, int> configValueCacheExpectedFragments = new Dictionary<string, int>();

		private readonly Dictionary<string, int> configValueCacheBytes = new Dictionary<string, int>();

		private readonly Dictionary<string, long> configValueCacheSenders = new Dictionary<string, long>();

		private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>();

		private static long packageCounter = 0L;

		[Description("Author-defined default for whether the owning mod must exist compatibly on the remote peer.")]
		public bool ModRequired { get; set; } = false;

		[Description("Whether the server may override the author-defined ModRequired default for incoming clients.")]
		public ModRequirementMode ModRequirementMode { get; set; } = ModRequirementMode.Fixed;

		private bool ServerLockEnabled => forceConfigLocking ?? (lockedConfig != null && ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0);

		[Description("Effective local lock state. Unlocked non-admin writes still require explicit mod opt-in.")]
		public bool IsLocked
		{
			get
			{
				return ServerLockEnabled && !lockExempt;
			}
			set
			{
				bool isLocked = IsLocked;
				forceConfigLocking = value;
				if (isLocked != IsLocked)
				{
					ServerLockedSettingChanged();
				}
			}
		}

		[Description("Whether the local side is the source of truth or has a server admin exemption.")]
		public bool IsAdmin => lockExempt || isSourceOfTruth;

		[Description("Whether the local side currently owns and publishes synchronized values.")]
		public bool IsSourceOfTruth
		{
			get
			{
				return isSourceOfTruth;
			}
			private set
			{
				if (value == isSourceOfTruth)
				{
					return;
				}
				isSourceOfTruth = value;
				foreach (CustomSyncedValueBase allCustomValue in allCustomValues)
				{
					allCustomValue.SetLocalOwnership(value);
				}
				ServerLockedSettingChanged();
				InvokeEventHandlers(this.SourceOfTruthChanged, value, "SourceOfTruthChanged");
			}
		}

		[Description("Whether initial server synchronization has completed for this mod instance.")]
		public bool InitialSyncDone { get; private set; } = false;

		private bool CanPublishConfigStateNotifications => !IsProcessing && configsBeingApplied.Count == 0 && customValuesBeingApplied.Count == 0;

		private static bool IsDebugActive => DebugLoggingEnabled || debugConfigEnabled;

		private static ConditionalConfigSyncDebugLevel EffectiveDebugLevel
		{
			get
			{
				int num = 0;
				if (DebugLoggingEnabled)
				{
					num = Math.Max(num, (int)DebugLoggingLevel);
				}
				if (debugConfigEnabled)
				{
					num = Math.Max(num, (int)debugConfigLevel);
				}
				return (num <= 0) ? ConditionalConfigSyncDebugLevel.Basic : ((ConditionalConfigSyncDebugLevel)num);
			}
		}

		private static string EffectiveDebugFilter => (!string.IsNullOrWhiteSpace(DebugLoggingFilter)) ? DebugLoggingFilter : debugConfigFilter;

		private static string SyncPolicyPath => Path.Combine(ConfigDirectoryPath, "ConditionalConfigSync.SyncPolicy.cfg");

		private static string HiddenConfigsPath => Path.Combine(ConfigDirectoryPath, "ConditionalConfigSync.HiddenConfigs.cfg");

		private static string ModRequirementsPath => Path.Combine(ConfigDirectoryPath, "ConditionalConfigSync.ModRequirements.cfg");

		private static ManualLogSource LogSource => logSource ?? (logSource = Logger.CreateLogSource("ConditionalConfigSync"));

		private static string ConfigDirectoryPath => Path.Combine(Paths.ConfigPath, "shudnal.ConditionalConfigSync");

		private static string DebugConfigPath => Path.Combine(ConfigDirectoryPath, "ConditionalConfigSync.Debug.cfg");

		private static bool IsMainThread => mainThreadId == 0 || Thread.CurrentThread.ManagedThreadId == mainThreadId;

		private bool IsSending => sendQueue.Count > 0;

		private bool IsProcessing => processingCount > 0;

		private bool ShouldDeferOutgoingBroadcasts => ProcessingServerUpdate || packagePreparationDepth > 0 || IsProcessing || IsSending || flushingPendingBroadcasts;

		[Description("Raised when this process changes between authoritative and client-replica roles.")]
		public event Action<bool>? SourceOfTruthChanged;

		[Description("Raised after the first complete server synchronization has been applied on a client.")]
		public event Action? InitialSyncCompleted;

		[Description("Raised after server state is cleared and local fallback values are restored.")]
		public event Action? ServerConnectionReset;

		[Description("Raised for any effective policy-state transition of a registered config entry.")]
		public event EventHandler<PolicyStateChangedEventArgs>? PolicyStateChanged;

		[Description("Raised when a config entry changes between server-controlled and client-controlled.")]
		public event Action<OwnConfigEntryBase, bool>? ServerControlledChanged;

		[Description("Raised when a config entry changes between hidden and visible.")]
		public event Action<OwnConfigEntryBase, bool>? HiddenStateChanged;

		[Description("Raised when the effective configuration lock changes.")]
		public event Action<bool>? LockStateChanged;

		[Description("Raised when synchronization is rejected for permissions, safety limits, malformed data, or an exception.")]
		public event EventHandler<SyncRejectedEventArgs>? SyncRejected;

		private event Action? LockedConfigChanged;

		[Description("Creates one synchronization instance. Pass a stable mod GUID as the name.")]
		public ConditionalConfigSync(string name)
		{
			EnsureRuntimeReady();
			Name = name;
			configSyncs.Add(this);
			versionCheck = new VersionCheck(this);
			if (sessionActive)
			{
				QueueMainThread(RegisterForActiveSession);
			}
		}

		[Description("Registers a policy-controlled config that is server-controlled by default.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry)
		{
			return AddConfigEntry<T>(configEntry, ConfigSyncMode.Conditional, serverControlledByDefault: true);
		}

		[Description("Registers a Conditional config with an explicit server/client default.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry, bool synchronizedSetting)
		{
			return AddConfigEntry<T>(configEntry, ConfigSyncMode.Conditional, synchronizedSetting);
		}

		[Description("Registers a config with an explicit synchronization mode.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry, ConfigSyncMode syncMode)
		{
			return AddConfigEntry<T>(configEntry, syncMode, serverControlledByDefault: true);
		}

		[Description("Registers a fully configured config without a temporary synchronization state.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry, ConfigSyncMode syncMode, bool serverControlledByDefault)
		{
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			if (!Enum.IsDefined(typeof(ConfigSyncMode), syncMode))
			{
				throw new ArgumentOutOfRangeException("syncMode", syncMode, "Unknown config synchronization mode.");
			}
			bool flag = syncMode switch
			{
				ConfigSyncMode.AlwaysServerControlled => true, 
				ConfigSyncMode.AlwaysClientControlled => false, 
				_ => serverControlledByDefault, 
			};
			if (GetConfigData((ConfigEntryBase)(object)configEntry) is SyncedConfigEntry<T> result)
			{
				return result;
			}
			ConfigDefinition definition = ((ConfigEntryBase)configEntry).Definition;
			if (allConfigs.Any((OwnConfigEntryBase config) => config.BaseConfig.Definition.Equals(definition)))
			{
				throw new InvalidOperationException("Config entry '" + definition.Section + " -> " + definition.Key + "' is already registered in sync '" + Name + "'.");
			}
			SyncedConfigEntry<T> syncedConfigEntry = new SyncedConfigEntry<T>(configEntry)
			{
				SyncMode = syncMode,
				SynchronizedConfig = flag
			};
			syncedConfigEntry.StoreLastAcceptedValue(((ConfigEntryBase)configEntry).BoxedValue);
			ConfigDescription description = ((ConfigEntryBase)configEntry).Description;
			object[] array = new object[1]
			{
				new ConfigurationManagerAttributes()
			}.Concat((description.Tags ?? Array.Empty<object>()).Where((object tag) => !(tag is OwnConfigEntryBase) && !(tag is ConfigurationManagerAttributes))).Concat(new SyncedConfigEntry<T>[1] { syncedConfigEntry }).ToArray();
			ConfigDescription value = new ConfigDescription(description.Description, description.AcceptableValues, array);
			(AccessTools.DeclaredField(typeof(ConfigEntryBase), "<Description>k__BackingField") ?? throw new MissingFieldException(typeof(ConfigEntryBase).FullName, "<Description>k__BackingField")).SetValue(configEntry, value);
			allConfigs.Add(syncedConfigEntry);
			if (!observedConfigFiles.Add(((ConfigEntryBase)configEntry).ConfigFile))
			{
				((ConfigEntryBase)configEntry).ConfigFile.SettingChanged -= OnObservedConfigFileChanged;
			}
			((ConfigEntryBase)configEntry).ConfigFile.SettingChanged += OnObservedConfigFileChanged;
			InvalidateFullSyncSnapshot("registered config: " + definition.Section + " -> " + definition.Key);
			bool flag2 = IsSourceOfTruth && isServer && GameReflection.HasZNet && policySupportInitialized;
			syncedConfigEntry.IsServerControlled = (flag2 ? ComputeServerControlled(syncedConfigEntry) : GetDefaultServerControlled(syncedConfigEntry));
			syncedConfigEntry.IsHidden = flag2 && ComputeHidden(syncedConfigEntry);
			syncedConfigEntry.IsPolicyStateInitialized = flag2;
			ConfigurationManagerAttributes configAttribute = GetConfigAttribute<ConfigurationManagerAttributes>((ConfigEntryBase)(object)configEntry);
			configAttribute.ReadOnly = !IsWritableConfig(syncedConfigEntry);
			configAttribute.Browsable = !syncedConfigEntry.IsHidden;
			DebugLog(ConditionalConfigSyncDebugLevel.Trace, "Register", string.Format("Added config {0}/{1}, type={2}, mode={3}, default={4}", definition.Section, definition.Key, ((ConfigEntryBase)configEntry).SettingType.Name, syncMode, flag ? "ServerControlled" : "ClientControlled"));
			ScheduleLateRegistrationSync(syncedConfigEntry);
			return syncedConfigEntry;
		}

		private void OnObservedConfigFileChanged(object? sender, SettingChangedEventArgs args)
		{
			OwnConfigEntryBase configData = GetConfigData(args.ChangedSetting);
			if (configData != null && allConfigs.Contains(configData))
			{
				OnObservedConfigChange(args.ChangedSetting, configData);
			}
		}

		private void OnObservedConfigChange(ConfigEntryBase configEntry, OwnConfigEntryBase data)
		{
			try
			{
				OnConfigEntryChanged(configEntry, data);
			}
			finally
			{
				if (data == lockedConfig)
				{
					this.LockedConfigChanged?.Invoke();
				}
			}
		}

		[Description("Binds and registers a Conditional config with an explicit server/client default.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, string section, string key, T defaultValue, string description, bool synchronizedSetting)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(section, key, defaultValue, description), ConfigSyncMode.Conditional, synchronizedSetting);
		}

		[Description("Binds and registers a config in one call using a text description.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, string section, string key, T defaultValue, string description, ConfigSyncMode syncMode = ConfigSyncMode.Conditional, bool serverControlledByDefault = true)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(section, key, defaultValue, description), syncMode, serverControlledByDefault);
		}

		[Description("Binds and registers a Conditional ConfigDescription entry with an explicit server/client default.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, string section, string key, T defaultValue, ConfigDescription description, bool synchronizedSetting)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(section, key, defaultValue, description), ConfigSyncMode.Conditional, synchronizedSetting);
		}

		[Description("Binds and registers a config in one call using a ConfigDescription.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, string section, string key, T defaultValue, ConfigDescription description, ConfigSyncMode syncMode = ConfigSyncMode.Conditional, bool serverControlledByDefault = true)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(section, key, defaultValue, description), syncMode, serverControlledByDefault);
		}

		[Description("Binds and registers a Conditional ConfigDefinition entry with a text description and explicit default.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, ConfigDefinition definition, T defaultValue, string description, bool synchronizedSetting)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(definition.Section, definition.Key, defaultValue, description), ConfigSyncMode.Conditional, synchronizedSetting);
		}

		[Description("Binds and registers a ConfigDefinition entry with a text description.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, ConfigDefinition definition, T defaultValue, string description, ConfigSyncMode syncMode = ConfigSyncMode.Conditional, bool serverControlledByDefault = true)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(definition.Section, definition.Key, defaultValue, description), syncMode, serverControlledByDefault);
		}

		[Description("Binds and registers a Conditional ConfigDefinition entry with an explicit server/client default.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, ConfigDefinition definition, T defaultValue, ConfigDescription description, bool synchronizedSetting)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(definition.Section, definition.Key, defaultValue, description), ConfigSyncMode.Conditional, synchronizedSetting);
		}

		[Description("Binds and registers a config in one call using a ConfigDefinition.")]
		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigFile configFile, ConfigDefinition definition, T defaultValue, ConfigDescription description, ConfigSyncMode syncMode = ConfigSyncMode.Conditional, bool serverControlledByDefault = true)
		{
			return AddConfigEntry<T>(configFile.Bind<T>(definition.Section, definition.Key, defaultValue, description), syncMode, serverControlledByDefault);
		}

		[Description("Registers the protected server-controlled lock entry. Non-admin clients can never change it.")]
		public SyncedConfigEntry<T> AddLockingConfigEntry<T>(ConfigEntry<T> lockingConfig) where T : IConvertible
		{
			if (lockedConfig != null)
			{
				throw new Exception("Cannot initialize locking ConfigEntry twice");
			}
			lockedConfig = AddConfigEntry<T>(lockingConfig, ConfigSyncMode.AlwaysServerControlled);
			lockedConfig.SyncMode = ConfigSyncMode.AlwaysServerControlled;
			lockedConfig.SynchronizedConfig = true;
			lockedConfig.IsServerControlled = true;
			lockedConfig.IsPolicyStateInitialized = IsSourceOfTruth && isServer && GameReflection.HasZNet && policySupportInitialized;
			lockedConfig.StoreLastAcceptedValue(((ConfigEntryBase)lockingConfig).BoxedValue);
			LockedConfigChanged -= ServerLockedSettingChanged;
			LockedConfigChanged += ServerLockedSettingChanged;
			InvalidateFullSyncSnapshot("registered locking config");
			ServerLockedSettingChanged();
			ScheduleLateRegistrationSync(lockedConfig);
			return (SyncedConfigEntry<T>)lockedConfig;
		}

		internal void AddCustomValue(CustomSyncedValueBase customValue)
		{
			if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[2] { "serverversion", "lockexempt" }).Contains(customValue.Identifier))
			{
				throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion, lockexempt)");
			}
			allCustomValues.Add(customValue);
			allCustomValues = new HashSet<CustomSyncedValueBase>(from v in allCustomValues
				orderby v.Priority descending, v.RegistrationIndex
				select v);
			InvalidateFullSyncSnapshot("registered custom value: " + customValue.Identifier);
			DebugLog(ConditionalConfigSyncDebugLevel.Trace, "Register", $"Added custom value {customValue.Identifier}, type={customValue.Type.Name}, priority={customValue.Priority}, sequenced={customValue.PreserveUpdateSequence}");
			ScheduleLateRegistrationSync(null, customValue);
		}

		internal void ReportCustomValueSubscriberFailure(string identifier, Exception exception)
		{
			DebugWarning("CustomValue", $"ValueChanged subscriber for '{identifier}' failed; continuing with the remaining subscribers. Error: {exception}");
		}

		internal void ReportCustomValuePublicationFailure(string identifier, Exception exception)
		{
			DebugWarning("CustomValue", $"Failed to publish custom value '{identifier}' after its notification callbacks completed. Error: {exception}");
		}

		[Description("Gets the compatibility state of a CCS consumer on a connected routed peer UID.")]
		public static RemoteConsumerState GetRemoteConsumerState(string consumerGuid, long peerUid)
		{
			if (string.IsNullOrWhiteSpace(consumerGuid) || peerUid == 0)
			{
				return RemoteConsumerState.Unknown;
			}
			return VersionCheck.GetRemoteConsumerState(consumerGuid.Trim(), peerUid);
		}

		[Description("Returns whether a connected routed peer has a compatible CCS consumer.")]
		public static bool HasCompatibleConsumer(string consumerGuid, long peerUid)
		{
			return GetRemoteConsumerState(consumerGuid, peerUid) == RemoteConsumerState.Compatible;
		}

		internal bool CanAcceptActiveCustomValueChange(CustomSyncedValueBase customValue)
		{
			if (customValuesBeingApplied.Contains(customValue) || IsSourceOfTruth || CanBroadcastFromThisSide())
			{
				return true;
			}
			string text = ((!InitialSyncDone) ? "initial server synchronization is not complete" : "the local side is not authorized to publish active custom values");
			DebugWarning("CustomValue", "Rejected local change to protected custom value " + customValue.Identifier + ": " + text);
			return false;
		}

		internal static bool IsWritableConfig(OwnConfigEntryBase config)
		{
			ConditionalConfigSync conditionalConfigSync = configSyncs.FirstOrDefault((ConditionalConfigSync cs) => cs.allConfigs.Contains(config));
			if (conditionalConfigSync == null)
			{
				return true;
			}
			if (conditionalConfigSync.IsSourceOfTruth || !config.IsServerControlled)
			{
				return true;
			}
			if (!conditionalConfigSync.InitialSyncDone)
			{
				return false;
			}
			if (config == conditionalConfigSync.lockedConfig)
			{
				return conditionalConfigSync.IsAdmin;
			}
			if (conditionalConfigSync.IsAdmin)
			{
				return true;
			}
			if (conditionalConfigSync.ServerLockEnabled)
			{
				return false;
			}
			return conditionalConfigSync.AllowClientConfigUpdatesWhenUnlocked;
		}

		internal static bool ShouldStoreLocalConfigValue(OwnConfigEntryBase config)
		{
			ConditionalConfigSync owningConfigSync = GetOwningConfigSync(config);
			return owningConfigSync != null && !owningConfigSync.IsSourceOfTruth && config.IsServerControlled;
		}

		private string GetWriteRejectionReason(OwnConfigEntryBase config)
		{
			if (!InitialSyncDone)
			{
				return "initial server synchronization is not complete";
			}
			if (config == lockedConfig)
			{
				return "the protected locking config requires administrator access";
			}
			if (ServerLockEnabled)
			{
				return "the server configuration is locked";
			}
			if (!AllowClientConfigUpdatesWhenUnlocked)
			{
				return "unlocked client updates are disabled by the mod";
			}
			return "the local side is not authorized to change this server-controlled config";
		}

		private void ServerLockedSettingChanged()
		{
			UpdateConfigMetadata();
			if (CanPublishConfigStateNotifications)
			{
				RaiseLockStateChangedIfNeeded();
			}
		}

		private void UpdateConfigMetadata()
		{
			DebugLog(ConditionalConfigSyncDebugLevel.Verbose, "Lock", $"Re-evaluating read-only state: serverLock={ServerLockEnabled}, effectiveLock={IsLocked}, admin={IsAdmin}, sourceOfTruth={IsSourceOfTruth}, initialSync={InitialSyncDone}, unlockedClientUpdates={AllowClientConfigUpdatesWhenUnlocked}");
			foreach (OwnConfigEntryBase allConfig in allConfigs)
			{
				ConfigurationManagerAttributes configAttribute = GetConfigAttribute<ConfigurationManagerAttributes>(allConfig.BaseConfig);
				configAttribute.ReadOnly = !IsWritableConfig(allConfig);
				configAttribute.Browsable = !allConfig.IsHidden;
			}
		}

		private void RestoreRejectedConfigChange(ConfigEntryBase configEntry, OwnConfigEntryBase syncedEntry, string reason)
		{
			object boxedValue = (syncedEntry.HasServerValue ? syncedEntry.ServerValue : (syncedEntry.HasLastAcceptedValue ? syncedEntry.LastAcceptedValue : (syncedEntry.HasLocalBaseValue ? syncedEntry.LocalBaseValue : configEntry.DefaultValue)));
			ConfigFile configFile = configEntry.ConfigFile;
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			configsBeingApplied.Add(configEntry);
			try
			{
				configEntry.BoxedValue = boxedValue;
				syncedEntry.StoreLastAcceptedValue(configEntry.BoxedValue);
			}
			catch (Exception arg)
			{
				ConfigDefinition definition = configEntry.Definition;
				DebugWarning("ConfigUpdate", $"Failed to restore protected config {definition.Section} -> {definition.Key} after a rejected local change. Error: {arg}");
				return;
			}
			finally
			{
				configsBeingApplied.Remove(configEntry);
				configFile.SaveOnConfigSet = saveOnConfigSet;
			}
			try
			{
				configFile.Save();
			}
			catch (Exception ex)
			{
				DebugWarning("ConfigUpdate", $"Failed to save local fallback after restoring {configEntry.Definition}: {ex.Message}");
			}
			DebugWarning("ConfigUpdate", "Restored protected config " + configEntry.Definition.Section + " -> " + configEntry.Definition.Key + " after a rejected local change: " + reason);
		}

		private void ResetConfigsFromServer(ParsedConfigs? retainedSnapshot = null)
		{
			remotePolicyChangeSupported = false;
			DebugLog(ConditionalConfigSyncDebugLevel.Verbose, "Reset", "Restoring local values after server sync/session end");
			Dictionary<ConfigFile, bool> dictionary = new Dictionary<ConfigFile, bool>();
			List<PolicyStateChangedEventArgs> list = new List<PolicyStateChangedEventArgs>();
			if (retainedSnapshot == null)
			{
				ClearPendingBroadcasts();
			}
			bool flag = retainedSnapshot == null && !isSourceOfTruth;
			if (flag)
			{
				isSourceOfTruth = true;
				foreach (CustomSyncedValueBase allCustomValue in allCustomValues)
				{
					allCustomValue.SetLocalOwnership(isOwner: true);
				}
			}
			OwnConfigEntryBase[] array = allConfigs.Where((OwnConfigEntryBase config) => retainedSnapshot == null || (!retainedSnapshot.configValues.ContainsKey(config) && !retainedSnapshot.configStates.ContainsKey(config))).ToArray();
			CustomSyncedValueBase[] source = allCustomValues.Where((CustomSyncedValueBase config) => retainedSnapshot == null || !retainedSnapshot.customValues.ContainsKey(config)).ToArray();
			OwnConfigEntryBase[] array2 = array;
			foreach (OwnConfigEntryBase ownConfigEntryBase in array2)
			{
				bool isServerControlled = ownConfigEntryBase.IsServerControlled;
				bool isHidden = ownConfigEntryBase.IsHidden;
				bool defaultServerControlled = GetDefaultServerControlled(ownConfigEntryBase);
				ownConfigEntryBase.ClearServerValue();
				ownConfigEntryBase.IsServerControlled = defaultServerControlled;
				ownConfigEntryBase.IsHidden = false;
				ownConfigEntryBase.IsPolicyStateInitialized = false;
				if (isServerControlled != defaultServerControlled || isHidden)
				{
					list.Add(new PolicyStateChangedEventArgs(ownConfigEntryBase, isServerControlled, defaultServerControlled, isHidden, newHidden: false, "server connection reset"));
				}
			}
			try
			{
				foreach (OwnConfigEntryBase item in array.Where((OwnConfigEntryBase config) => config.HasLocalBaseValue))
				{
					ConfigFile configFile = item.BaseConfig.ConfigFile;
					if (!dictionary.ContainsKey(configFile))
					{
						dictionary[configFile] = configFile.SaveOnConfigSet;
						configFile.SaveOnConfigSet = false;
					}
					object localBaseValue = item.LocalBaseValue;
					item.ClearLocalBaseValue();
					configsBeingApplied.Add(item.BaseConfig);
					try
					{
						item.BaseConfig.BoxedValue = localBaseValue;
						item.StoreLastAcceptedValue(item.BaseConfig.BoxedValue);
					}
					catch (Exception arg)
					{
						if (!item.HasLocalBaseValue)
						{
							item.StoreLocalBaseValue(localBaseValue);
						}
						ConfigDefinition definition = item.BaseConfig.Definition;
						DebugWarning("Reset", $"Failed to restore local config {definition.Section} -> {definition.Key}; continuing. Error: {arg}");
					}
					finally
					{
						configsBeingApplied.Remove(item.BaseConfig);
					}
				}
			}
			finally
			{
				foreach (KeyValuePair<ConfigFile, bool> item2 in dictionary)
				{
					item2.Key.SaveOnConfigSet = item2.Value;
				}
			}
			OwnConfigEntryBase[] array3 = array;
			foreach (OwnConfigEntryBase ownConfigEntryBase2 in array3)
			{
				ownConfigEntryBase2.StoreLastAcceptedValue(ownConfigEntryBase2.BaseConfig.BoxedValue);
			}
			foreach (CustomSyncedValueBase item3 in source.Where((CustomSyncedValueBase config) => config.HasLocalBaseValue))
			{
				object localBaseValue2 = item3.LocalBaseValue;
				item3.ClearLocalBaseValue();
				customValuesBeingApplied.Add(item3);
				try
				{
					item3.BoxedValue = localBaseValue2;
					item3.StoreLastAcceptedValue(item3.BoxedValue);
				}
				catch (Exception arg2)
				{
					if (!item3.HasLocalBaseValue)
					{
						item3.StoreLocalBaseValue(localBaseValue2);
					}
					DebugWarning("Reset", $"Failed to restore local custom value '{item3.Identifier}'; continuing. Error: {arg2}");
				}
				finally
				{
					customValuesBeingApplied.Remove(item3);
				}
			}
			if (retainedSnapshot != null)
			{
				retainedSnapshot.policyTransitions.AddRange(list);
				return;
			}
			ServerLockedSettingChanged();
			foreach (PolicyStateChangedEventArgs item4 in list)
			{
				RaisePolicyStateEvents(item4);
			}
			if (flag)
			{
				InvokeEventHandlers(this.SourceOfTruthChanged, value: true, "SourceOfTruthChanged");
			}
		}

		private static OwnConfigEntryBase? GetConfigData(ConfigEntryBase config)
		{
			return config.Description.Tags?.OfType<OwnConfigEntryBase>().SingleOrDefault((OwnConfigEntryBase entry) => entry.BaseConfig == config);
		}

		[Description("Returns the synchronization wrapper attached to a registered BepInEx config entry.")]
		public static SyncedConfigEntry<T>? ConfigData<T>(ConfigEntry<T> config)
		{
			return GetConfigData((ConfigEntryBase)(object)config) as SyncedConfigEntry<T>;
		}

		private static T GetConfigAttribute<T>(ConfigEntryBase config)
		{
			return config.Description.Tags.OfType<T>().First();
		}

		private static void WriteValueWithTypeToZPackage(ZPackage package, Type type, object value)
		{
			Type type2 = Nullable.GetUnderlyingType(type) ?? type;
			if (typeof(ISerializableParameter).IsAssignableFrom(type2))
			{
				RequireConstructibleSerializableParameter(type2);
				RequireExactRuntimeType(type2, value, "ISerializableParameter");
				GameReflection.SerializeParameter(value, ref package);
				return;
			}
			if (type2.IsEnum)
			{
				Type underlyingType = Enum.GetUnderlyingType(type2);
				WriteValueWithTypeToZPackage(package, underlyingType, ((IConvertible)value).ToType(underlyingType, CultureInfo.InvariantCulture));
				return;
			}
			if (type2.IsPrimitive || type2 == typeof(string))
			{
				GameReflection.PackageWrite(package, value);
				return;
			}
			if (type2.IsArray)
			{
				RequireVectorArray(type2);
				if (value is byte[] value2)
				{
					GameReflection.PackageWrite(package, value2);
					return;
				}
			}
			if (type2 != typeof(List<string>))
			{
				Type genericCollectionType = GetGenericCollectionType(type2);
				if (!type2.IsArray && genericCollectionType != null)
				{
					GetCollectionImplementationType(type2, genericCollectionType);
				}
				else if (!type2.IsArray && value is ICollection)
				{
					throw new NotSupportedException("Collection type '" + type2.FullName + "' has no symmetric count/element reader in the current protocol. Declare an ICollection<T>-based type or implement ISerializableParameter.");
				}
				if (value is ICollection collection)
				{
					GameReflection.PackageWrite(package, collection.Count);
					Type declaredElementType = (type2.IsArray ? type2.GetElementType() : (((object)genericCollectionType != null) ? genericCollectionType.GenericTypeArguments[0] : null));
					WriteCollectionElements(package, collection, declaredElementType);
					return;
				}
				if (genericCollectionType != null)
				{
					int value3 = (int)genericCollectionType.GetProperty("Count").GetValue(value);
					GameReflection.PackageWrite(package, value3);
					WriteCollectionElements(package, (IEnumerable)value, genericCollectionType.GenericTypeArguments[0]);
					return;
				}
			}
			if ((object)type2 != null && type2.IsValueType && !type2.IsPrimitive)
			{
				FieldInfo[] fields = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				GameReflection.PackageWrite(package, fields.Length);
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					GameReflection.PackageWrite(package, GetZPackageTypeString(fieldInfo.FieldType));
					WriteCustomValueToPackage(package, fieldInfo.FieldType, fieldInfo.GetValue(value));
				}
			}
			else
			{
				RequireExactRuntimeType(type2, value, "custom value");
				int num = GameReflection.PackageGetPos(package);
				GameReflection.Serialize(new object[1] { value }, ref package);
				if (GameReflection.PackageGetPos(package) == num)
				{
					throw new NotSupportedException("Custom value type '" + type2.FullName + "' has no package serializer. Implement ISerializableParameter for this type.");
				}
			}
		}

		private static void WriteCollectionElements(ZPackage package, IEnumerable collection, Type? declaredElementType)
		{
			foreach (object item in collection)
			{
				if (item == null)
				{
					throw new NotSupportedException("Null collection elements have no encoding in the current protocol. Use ISerializableParameter for a nullable collection format.");
				}
				if (declaredElementType == null)
				{
					WriteValueWithTypeToZPackage(package, item.GetType(), item);
					continue;
				}
				Type type = Nullable.GetUnderlyingType(declaredElementType) ?? declaredElementType;
				RequireExactRuntimeType(type, item, "collection element");
				RequireConstructibleSerializableParameter(type);
				WriteValueWithTypeToZPackage(package, type, item);
			}
		}

		private static void RequireExactRuntimeType(Type declaredType, object value, string context)
		{
			Type type = Nullable.GetUnderlyingType(declaredType) ?? declaredType;
			if (value.GetType() != type)
			{
				throw new NotSupportedException("Polymorphic " + context + " '" + value.GetType().FullName + "' cannot be encoded as declared type '" + type.FullName + "' by the current protocol. Use an exact declared element/value type or implement an explicit ISerializableParameter container format.");
			}
		}

		private static bool IsCompatibleZPackageTypeString(string receivedTypeName, Type expectedType)
		{
			string zPackageTypeString = GetZPackageTypeString(expectedType);
			return string.Equals(receivedTypeName, zPackageTypeString, StringComparison.Ordinal) || string.Equals(RemoveAssemblyVersionFromTypeIdentity(receivedTypeName), RemoveAssemblyVersionFromTypeIdentity(zPackageTypeString), StringComparison.Ordinal);
		}

		private static string RemoveAssemblyVersionFromTypeIdentity(string typeName)
		{
			return assemblyVersionTypeIdentityPattern.Replace(typeName, string.Empty);
		}

		private static void RequireConstructibleSerializableParameter(Type type)
		{
			Type type2 = Nullable.GetUnderlyingType(type) ?? type;
			if (!typeof(ISerializableParameter).IsAssignableFrom(type2) || (!type2.IsInterface && !type2.IsAbstract && !type2.ContainsGenericParameters && (type2.IsValueType || !(type2.GetConstructor(Type.EmptyTypes) == null))))
			{
				return;
			}
			throw new NotSupportedException("ISerializableParameter type '" + type2.FullName + "' cannot be constructed by the matching reader. Declare a closed concrete value type or a class with a public parameterless constructor.");
		}

		private static Type? GetGenericCollectionType(Type type)
		{
			if (type.IsValueType)
			{
				return null;
			}
			return type.GetInterfaces().Concat(new Type[1] { type }).FirstOrDefault((Type candidate) => candidate.IsGenericType && candidate.GetGenericTypeDefinition() == typeof(ICollection<>));
		}

		private static Type GetCollectionImplementationType(Type declaredType, Type collectionType)
		{
			if (!declaredType.IsInterface)
			{
				if (declaredType.IsAbstract || declaredType.GetConstructor(Type.EmptyTypes) == null)
				{
					throw new NotSupportedException("Collection type '" + declaredType.FullName + "' requires a concrete type with a public parameterless constructor or ISerializableParameter.");
				}
				return declaredType;
			}
			Type type = collectionType.GenericTypeArguments[0];
			Type type2 = typeof(List<>).MakeGenericType(type);
			if (declaredType.IsAssignableFrom(type2))
			{
				return type2;
			}
			Type type3 = typeof(HashSet<>).MakeGenericType(type);
			if (declaredType.IsAssignableFrom(type3))
			{
				return type3;
			}
			if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<, >))
			{
				Type type4 = typeof(Dictionary<, >).MakeGenericType(type.GenericTypeArguments);
				if (declaredType.IsAssignableFrom(type4))
				{
					return type4;
				}
			}
			throw new NotSupportedException("Collection interface '" + declaredType.FullName + "' has no compatible built-in implementation. Declare a constructible concrete type or implement ISerializableParameter.");
		}

		private static void RequireVectorArray(Type type)
		{
			if (type != type.GetElementType().MakeArrayType())
			{
				throw new NotSupportedException("Array type '" + type.FullName + "' requires shape metadata that is not present in the current protocol. Use a one-dimensional zero-based array or ISerializableParameter.");
			}
		}

		private static object ReadPrimitiveFromPackage(ZPackage package, Type type)
		{
			using BinaryReader binaryReader = new BinaryReader(GameReflection.PackageStream(package), Encoding.UTF8, leaveOpen: true);
			return Type.GetTypeCode(type) switch
			{
				TypeCode.Boolean => binaryReader.ReadBoolean(), 
				TypeCode.Byte => binaryReader.ReadByte(), 
				TypeCode.SByte => binaryReader.ReadSByte(), 
				TypeCode.Char => binaryReader.ReadChar(), 
				TypeCode.Int16 => binaryReader.ReadInt16(), 
				TypeCode.UInt16 => binaryReader.ReadUInt16(), 
				TypeCode.Int32 => binaryReader.ReadInt32(), 
				TypeCode.UInt32 => binaryReader.ReadUInt32(), 
				TypeCode.Int64 => binaryReader.ReadInt64(), 
				TypeCode.UInt64 => binaryReader.ReadUInt64(), 
				TypeCode.Single => binaryReader.ReadSingle(), 
				TypeCode.Double => binaryReader.ReadDouble(), 
				_ => throw new NotSupportedException("Primitive custom value type '" + type.FullName + "' has no package encoding."), 
			};
		}

		private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type)
		{
			Type type2 = Nullable.GetUnderlyingType(type) ?? type;
			if (typeof(ISerializableParameter).IsAssignableFrom(type2))
			{
				RequireConstructibleSerializableParameter(type2);
				object obj = Activator.CreateInstance(type2) ?? throw new MissingMethodException("Cannot create " + type2.FullName + " for ISerializableParameter deserialization");
				GameReflection.DeserializeParameter(obj, ref package);
				return obj;
			}
			if (type2.IsEnum)
			{
				object value = ReadValueWithTypeFromZPackage(package, Enum.GetUnderlyingType(type2));
				return Enum.ToObject(type2, value);
			}
			if (type2.IsPrimitive)
			{
				return ReadPrimitiveFromPackage(package, type2);
			}
			if (type2 == typeof(string))
			{
				return GameReflection.PackageReadString(package);
			}
			if (type2.IsArray)
			{
				RequireVectorArray(type2);
				if (type2 == typeof(byte[]))
				{
					return GameReflection.PackageReadByteArray(package, 20971520);
				}
				int num = GameReflection.PackageReadInt(package);
				Type elementType = type2.GetElementType();
				Array array = Array.CreateInstance(elementType, num);
				for (int i = 0; i < num; i++)
				{
					array.SetValue(ReadValueWithTypeFromZPackage(package, elementType), i);
				}
				return array;
			}
			if ((object)type2 != null && type2.IsValueType && !type2.IsPrimitive)
			{
				FieldInfo[] fields = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int num2 = GameReflection.PackageReadInt(package);
				if (num2 != fields.Length)
				{
					throw new InvalidDeserializationTypeException
					{
						received = $"(field count: {num2})",
						expected = $"(field count: {fields.Length})"
					};
				}
				object uninitializedObject = FormatterServices.GetUninitializedObject(type2);
				FieldInfo[] array2 = fields;
				foreach (FieldInfo fieldInfo in array2)
				{
					string text = GameReflection.PackageReadString(package);
					if (!IsCompatibleZPackageTypeString(text, fieldInfo.FieldType))
					{
						throw new InvalidDeserializationTypeException
						{
							received = text,
							expected = GetZPackageTypeString(fieldInfo.FieldType),
							field = fieldInfo.Name
						};
					}
					fieldInfo.SetValue(uninitializedObject, ReadCustomValueFromPackage(package, fieldInfo.FieldType));
				}
				return uninitializedObject;
			}
			if (type2.IsGenericType && type2.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				int num3 = GameReflection.PackageReadInt(package);
				IDictionary dictionary = (IDictionary)Activator.CreateInstance(type2);
				Type type3 = typeof(KeyValuePair<, >).MakeGenericType(type2.GenericTypeArguments);
				FieldInfo field = type3.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
				FieldInfo field2 = type3.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic);
				for (int k = 0; k < num3; k++)
				{
					object obj2 = ReadValueWithTypeFromZPackage(package, type3);
					dictionary.Add(field.GetValue(obj2), field2.GetValue(obj2));
				}
				return dictionary;
			}
			if (type2 != typeof(List<string>))
			{
				Type genericCollectionType = GetGenericCollectionType(type2);
				if ((object)genericCollectionType != null)
				{
					Type collectionImplementationType = GetCollectionImplementationType(type2, genericCollectionType);
					int num4 = GameReflection.PackageReadInt(package);
					object obj3 = Activator.CreateInstance(collectionImplementationType);
					Type type4 = genericCollectionType.GenericTypeArguments[0];
					MethodInfo method = genericCollectionType.GetMethod("Add");
					for (int l = 0; l < num4; l++)
					{
						method.Invoke(obj3, new object[1] { ReadValueWithTypeFromZPackage(package, type4) });
					}
					return obj3;
				}
			}
			ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo));
			AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type2);
			List<object> data = new List<object>();
			GameReflection.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref data);
			if (data.Count != 1)
			{
				throw new NotSupportedException("Custom value type '" + type2.FullName + "' has no package deserializer. Implement ISerializableParameter for this type.");
			}
			return data[0];
		}

		private static void EnsureDebugSupportInitialized()
		{
			lock (debugSupportLock)
			{
				if (!debugSupportInitialized)
				{
					debugSupportInitialized = true;
					LoadDebugConfig(createIfMissing: true, quiet: true);
					StartDebugConfigWatcher();
				}
			}
		}

		private static void StartDebugConfigWatcher()
		{
			try
			{
				EnsureConfigDirectory();
				FileSystemWatcher watcher = new FileSystemWatcher(ConfigDirectoryPath, "ConditionalConfigSync.Debug.cfg")
				{
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime)
				};
				watcher.Changed += delegate
				{
					ScheduleDebugConfigReload(watcher);
				};
				watcher.Created += delegate
				{
					ScheduleDebugConfigReload(watcher);
				};
				watcher.Renamed += delegate
				{
					ScheduleDebugConfigReload(watcher);
				};
				watcher.Deleted += delegate
				{
					ScheduleDebugConfigReload(watcher);
				};
				debugConfigWatcher = watcher;
				watcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				LogSource.LogWarning((object)("[DebugConfig] Could not start watcher for ConditionalConfigSync.Debug.cfg: " + ex.Message));
			}
		}

		private static void ScheduleDebugConfigReload(FileSystemWatcher watcher)
		{
			lock (debugSupportLock)
			{
				if (!debugSupportInitialized || watcher != debugConfigWatcher || debugConfigReloadScheduled)
				{
					return;
				}
				debugConfigReloadScheduled = true;
			}
			ThreadPool.QueueUserWorkItem(delegate
			{
				Thread.Sleep(500);
				lock (debugSupportLock)
				{
					if (!debugSupportInitialized || watcher != debugConfigWatcher)
					{
						return;
					}
					try
					{
						LoadDebugConfig(createIfMissing: false, quiet: false);
					}
					finally
					{
						debugConfigReloadScheduled = false;
					}
				}
			});
		}

		private static void LoadDebugConfig(bool createIfMissing, bool quiet)
		{
			try
			{
				EnsureConfigDirectory();
				if (!File.Exists(DebugConfigPath))
				{
					if (createIfMissing)
					{
						File.WriteAllText(DebugConfigPath, "[Debug]\n# Local debug logging for ConditionalConfigSync. This file is not synchronized.\nEnabled = false\nLevel = Basic\nFilter = \n");
						return;
					}
					debugConfigEnabled = false;
					debugConfigLevel = ConditionalConfigSyncDebugLevel.Basic;
					debugConfigFilter = "";
					if (!quiet && DebugLoggingEnabled)
					{
						LogSource.LogInfo((object)"[DebugConfig] ConditionalConfigSync.Debug.cfg was deleted; file-based debug settings were reset.");
					}
					return;
				}
				Dictionary<string, string> dictionary = ReadSimpleDebugConfig(DebugConfigPath);
				bool flag = ReadBool(dictionary, "Enabled", fallback: false);
				string value;
				ConditionalConfigSyncDebugLevel conditionalConfigSyncDebugLevel = ReadDebugLevel(dictionary.TryGetValue("Level", out value) ? value : null, ConditionalConfigSyncDebugLevel.Basic);
				string value2;
				string text = (dictionary.TryGetValue("Filter", out value2) ? value2.Trim() : "");
				debugConfigEnabled = flag;
				debugConfigLevel = conditionalConfigSyncDebugLevel;
				debugConfigFilter = text;
				if (!quiet && (flag || DebugLoggingEnabled))
				{
					LogSource.LogInfo((object)string.Format("[DebugConfig] Reloaded {0}: enabled={1}, level={2}, filter='{3}'", "ConditionalConfigSync.Debug.cfg", flag, conditionalConfigSyncDebugLevel, text));
				}
			}
			catch (Exception ex)
			{
				LogSource.LogWarning((object)("[DebugConfig] Failed to read ConditionalConfigSync.Debug.cfg: " + ex.Message));
			}
		}

		private static Dictionary<string, string> ReadSimpleDebugConfig(string path)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			string text = "";
			string[] array = ReadAllLinesStable(path);
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0 || text3.StartsWith("#") || text3.StartsWith(";"))
				{
					continue;
				}
				if (text3.StartsWith("[") && text3.EndsWith("]"))
				{
					text = text3.Substring(1, text3.Length - 2).Trim();
				}
				else if (text.Equals("Debug", StringComparison.OrdinalIgnoreCase))
				{
					int num = text3.IndexOf('=');
					if (num >= 0)
					{
						dictionary[text3.Substring(0, num).Trim()] = text3.Substring(num + 1).Trim();
					}
				}
			}
			return dictionary;
		}

		private static bool ReadBool(Dictionary<string, string> values, string key, bool fallback)
		{
			if (!values.TryGetValue(key, out string value))
			{
				return fallback;
			}
			if (bool.TryParse(value, out var result))
			{
				return result;
			}
			if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
			{
				return result2 != 0;
			}
			return fallback;
		}

		private static ConditionalConfigSyncDebugLevel ReadDebugLevel(string? raw, ConditionalConfigSyncDebugLevel fallback)
		{
			ConditionalConfigSyncDebugLevel result;
			return (Enum.TryParse<ConditionalConfigSyncDebugLevel>(raw, ignoreCase: true, out result) && Enum.IsDefined(typeof(ConditionalConfigSyncDebugLevel), result)) ? result : fallback;
		}

		private bool ShouldDebugLog(ConditionalConfigSyncDebugLevel level)
		{
			if (!IsDebugActive || level > EffectiveDebugLevel)
			{
				return false;
			}
			string effectiveDebugFilter = EffectiveDebugFilter;
			if (string.IsNullOrWhiteSpace(effectiveDebugFilter))
			{
				return true;
			}
			string text = DisplayName ?? Name;
			return text.IndexOf(effectiveDebugFilter, StringComparison.OrdinalIgnoreCase) >= 0 || Name.IndexOf(effectiveDebugFilter, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private void DebugLog(ConditionalConfigSyncDebugLevel level, string area, string message)
		{
			if (ShouldDebugLog(level))
			{
				LogSource.LogInfo((object)("[" + GetDebugModName() + "][" + GetDebugSide() + "][" + area + "] " + message));
			}
		}

		private void InfoLog(string message)
		{
			LogSource.LogInfo((object)("[" + GetDebugModName() + "][" + GetDebugSide() + "] " + message));
		}

		private void DebugWarning(string area, string message)
		{
			LogSource.LogWarning((object)("[" + GetDebugModName() + "][" + GetDebugSide() + "][" + area + "] " + message));
		}

		private static double ElapsedMilliseconds(long startTimestamp)
		{
			return (double)(Stopwatch.GetTimestamp() - startTimestamp) * 1000.0 / (double)Stopwatch.Frequency;
		}

		private static string FormatByteCount(int bytes)
		{
			if (bytes >= 1048576)
			{
				return string.Format("{0} MiB ({1} bytes)", ((double)bytes / 1048576.0).ToString("F2", CultureInfo.InvariantCulture), bytes);
			}
			if (bytes >= 1024)
			{
				return string.Format("{0} KiB ({1} bytes)", ((double)bytes / 1024.0).ToString("F1", CultureInfo.InvariantCulture), bytes);
			}
			return $"{bytes} bytes";
		}

		private static string FormatMilliseconds(double milliseconds)
		{
			return milliseconds.ToString("F2", CultureInfo.InvariantCulture) + " ms";
		}

		private static string FormatCompressionStats(int rawSize, int compressedSize)
		{
			if (rawSize <= 0)
			{
				return "raw=" + FormatByteCount(rawSize) + ", compressed=" + FormatByteCount(compressedSize);
			}
			double num = (double)compressedSize * 100.0 / (double)rawSize;
			double num2 = 100.0 - num;
			return "raw=" + FormatByteCount(rawSize) + ", compressed=" + FormatByteCount(compressedSize) + ", ratio=" + num.ToString("F1", CultureInfo.InvariantCulture) + "%, saved=" + num2.ToString("F1", CultureInfo.InvariantCulture) + "%";
		}

		private string GetDebugModName()
		{
			return (!string.IsNullOrWhiteSpace(DisplayName)) ? DisplayName : Name;
		}

		private static string GetDebugSide()
		{
			if (!GameReflection.HasZNet)
			{
				return "NoZNet";
			}
			return GameReflection.IsServer() ? "Server" : "Client";
		}

		private void InvokeEventHandlers(Action? handlers, string eventName)
		{
			if (handlers == null)
			{
				return;
			}
			Delegate[] invocationList = handlers.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((Action)obj)();
				}
				catch (Exception arg)
				{
					DebugWarning("Event", $"Subscriber of {eventName} failed; continuing. Error: {arg}");
				}
			}
		}

		private void InvokeEventHandlers<T>(Action<T>? handlers, T value, string eventName)
		{
			if (handlers == null)
			{
				return;
			}
			Delegate[] invocationList = handlers.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((Action<T>)obj)(value);
				}
				catch (Exception arg)
				{
					DebugWarning("Event", $"Subscriber of {eventName} failed; continuing. Error: {arg}");
				}
			}
		}

		private void InvokeEventHandlers<T1, T2>(Action<T1, T2>? handlers, T1 value1, T2 value2, string eventName)
		{
			if (handlers == null)
			{
				return;
			}
			Delegate[] invocationList = handlers.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((Action<T1, T2>)obj)(value1, value2);
				}
				catch (Exception arg)
				{
					DebugWarning("Event", $"Subscriber of {eventName} failed; continuing. Error: {arg}");
				}
			}
		}

		private void InvokeEventHandlers<TEventArgs>(EventHandler<TEventArgs>? handlers, TEventArgs args, string eventName) where TEventArgs : EventArgs
		{
			if (handlers == null)
			{
				return;
			}
			Delegate[] invocationList = handlers.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((EventHandler<TEventArgs>)obj)(this, args);
				}
				catch (Exception arg)
				{
					DebugWarning("Event", $"Subscriber of {eventName} failed; continuing. Error: {arg}");
				}
			}
		}

		private void RaiseInitialSyncCompletedIfNeeded()
		{
			if (!InitialSyncDone)
			{
				long num = transportGeneration;
				InitialSyncDone = true;
				ServerLockedSettingChanged();
				if (sessionActive && num == transportGeneration && InitialSyncDone)
				{
					InvokeEventHandlers(this.InitialSyncCompleted, "InitialSyncCompleted");
					ScheduleLateRegistrationSync();
				}
			}
		}

		private void RaisePolicyStateEvents(OwnConfigEntryBase config, bool oldServerControlled, bool newServerControlled, bool oldHidden, bool newHidden, string source)
		{
			if (oldServerControlled != newServerControlled || oldHidden != newHidden)
			{
				RaisePolicyStateEvents(new PolicyStateChangedEventArgs(config, oldServerControlled, newServerControlled, oldHidden, newHidden, source));
			}
		}

		private void RaisePolicyStateEvents(PolicyStateChangedEventArgs args)
		{
			InvokeEventHandlers(this.PolicyStateChanged, args, "PolicyStateChanged");
			if (args.OldServerControlled != args.NewServerControlled)
			{
				InvokeEventHandlers(this.ServerControlledChanged, args.Config, args.NewServerControlled, "ServerControlledChanged");
			}
			if (args.OldHidden != args.NewHidden)
			{
				InvokeEventHandlers(this.HiddenStateChanged, args.Config, args.NewHidden, "HiddenStateChanged");
			}
		}

		private void RaiseLockStateChangedIfNeeded()
		{
			bool isLocked = IsLocked;
			if (lastNotifiedLockState != isLocked)
			{
				lastNotifiedLockState = isLocked;
				InvokeEventHandlers(this.LockStateChanged, isLocked, "LockStateChanged");
			}
		}

		private void RejectSync(string reason, long? senderUid, bool incoming, Exception? exception = null)
		{
			DebugWarning("Reject", (exception == null) ? reason : $"{reason}{Environment.NewLine}{exception}");
			InvokeEventHandlers(this.SyncRejected, new SyncRejectedEventArgs(reason, senderUid, incoming, exception), "SyncRejected");
		}

		private static void RegisterDebugConsoleCommands()
		{
			if (debugCommandsRegistered)
			{
				return;
			}
			try
			{
				MethodInfo handler = AccessTools.DeclaredMethod(typeof(ConditionalConfigSync), "HandleDebugConsoleCommand", (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(ConditionalConfigSync).FullName, "HandleDebugConsoleCommand");
				MethodInfo handler2 = AccessTools.DeclaredMethod(typeof(ConditionalConfigSync), "HandlePolicyConsoleCommand", (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(ConditionalConfigSync).FullName, "HandlePolicyConsoleCommand");
				GameReflection.RegisterConsoleCommand("conditionalconfigsync_debug", "ConditionalConfigSync debug logging: status/on/off/level/filter/clearfilter", handler);
				GameReflection.RegisterConsoleCommand("conditionalconfigsync_debug_server", "ConditionalConfigSync server debug logging: status/on/off/level/filter/clearfilter", handler, isCheat: false, isNetwork: true, onlyServer: true, isSecret: false, allowInDevBuild: false, remoteCommand: true, onlyAdmin: true);
				RegisterPolicyConsoleCommand("conditionalconfigsync_status", "Show registered mods, config modes, and effective policy counts", handler2);
				RegisterPolicyConsoleCommand("conditionalconfigsync_policy_reload", "Reload and apply ConditionalConfigSync policy files", handler2);
				RegisterPolicyConsoleCommand("conditionalconfigsync_policy_validate", "Validate policy syntax, identifiers, and ignored rules", handler2);
				RegisterPolicyConsoleCommand("conditionalconfigsync_policy_dump", "Write a copy-ready policy identifier file", handler2);
				debugCommandsRegistered = true;
			}
			catch (Exception ex)
			{
				LogSource.LogWarning((object)("[Console] Could not register ConditionalConfigSync commands: " + ex.Message));
			}
		}

		private static void RegisterPolicyConsoleCommand(string command, string description, MethodInfo handler)
		{
			GameReflection.RegisterConsoleCommand(command, description, handler, isCheat: false, isNetwork: true, onlyServer: true, isSecret: false, allowInDevBuild: false, remoteCommand: true, onlyAdmin: true);
		}

		private static object HandleDebugConsoleCommand(ConsoleEventArgs args)
		{
			EnsureDebugSupportInitialized();
			bool flag = GameReflection.ConsoleArgsLength(args) <= 1;
			bool? flag2 = null;
			ConditionalConfigSyncDebugLevel? conditionalConfigSyncDebugLevel = null;
			string text = null;
			for (int i = 1; i < GameReflection.ConsoleArgsLength(args); i++)
			{
				string text2 = GameReflection.ConsoleArg(args, i).Trim();
				switch (text2.ToLowerInvariant())
				{
				case "status":
					flag = true;
					break;
				case "on":
				case "enable":
				case "enabled":
					flag2 = true;
					flag = false;
					break;
				case "off":
				case "disable":
				case "disabled":
					flag2 = false;
					flag = false;
					break;
				case "basic":
				case "verbose":
				case "trace":
					conditionalConfigSyncDebugLevel = ReadDebugLevel(text2, DebugLoggingLevel);
					flag = false;
					break;
				case "level":
					if (i + 1 < GameReflection.ConsoleArgsLength(args))
					{
						conditionalConfigSyncDebugLevel = ReadDebugLevel(GameReflection.ConsoleArg(args, ++i), DebugLoggingLevel);
						flag = false;
					}
					break;
				case "filter":
					if (i + 1 < GameReflection.ConsoleArgsLength(args))
					{
						text = GameReflection.ConsoleArg(args, ++i);
						flag = false;
					}
					break;
				case "clearfilter":
				case "nofilter":
					text = "";
					flag = false;
					break;
				default:
					return "Unknown argument '" + text2 + "'";
				}
			}
			if (flag)
			{
				WriteDebugStatus(args);
				return true;
			}
			DebugLoggingEnabled = flag2 ?? DebugLoggingEnabled;
			DebugLoggingLevel = conditionalConfigSyncDebugLevel ?? DebugLoggingLevel;
			DebugLoggingFilter = text ?? DebugLoggingFilter;
			AddConsoleLine(args, $"ConditionalConfigSync debug: enabled={DebugLoggingEnabled}, level={DebugLoggingLevel}, filter='{DebugLoggingFilter}'");
			return true;
		}

		private static void WriteDebugStatus(ConsoleEventArgs args)
		{
			AddConsoleLine(args, $"ConditionalConfigSync debug: enabled={DebugLoggingEnabled}, configEnabled={debugConfigEnabled}, level={EffectiveDebugLevel}, filter='{EffectiveDebugFilter}'");
		}

		private static void AddConsoleLine(ConsoleEventArgs args, string text)
		{
			GameReflection.ConsoleAddString(args, text);
			LogSource.LogInfo((object)("[Console] " + text));
		}

		internal static void VersionDebugLog(string area, string modName, string message)
		{
			EnsureDebugSupportInitialized();
			if (IsDebugActive && ConditionalConfigSyncDebugLevel.Basic <= EffectiveDebugLevel)
			{
				string effectiveDebugFilter = EffectiveDebugFilter;
				if (string.IsNullOrWhiteSpace(effectiveDebugFilter) || modName.IndexOf(effectiveDebugFilter, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSource.LogInfo((object)("[" + modName + "][" + GetDebugSide() + "][" + area + "] " + message));
				}
			}
		}

		internal static void VersionInfoLog(string area, string modName, string message)
		{
			LogSource.LogInfo((object)("[" + modName + "][" + GetDebugSide() + "][" + area + "] " + message));
		}

		internal static void VersionWarningLog(string area, string modName, string message)
		{
			LogSource.LogWarning((object)("[" + modName + "][" + GetDebugSide() + "][" + area + "] " + message));
		}

		internal static void VersionErrorLog(string area, string modName, string message)
		{
			LogSource.LogError((object)("[" + modName + "][" + GetDebugSide() + "][" + area + "] " + message));
		}

		private void ApplyParsedConfigs(ParsedConfigs configs, bool receivedFromServer)
		{
			DebugLog(ConditionalConfigSyncDebugLevel.Verbose, "Apply", $"Applying configs={configs.configValues.Count}, custom={configs.customValues.Count}, states={configs.configStates.Count}");
			Dictionary<ConfigFile, bool> saveOnConfigSet = new Dictionary<ConfigFile, bool>();
			List<PolicyStateChangedEventArgs> policyTransitions = configs.policyTransitions;
			long generation = transportGeneration;
			if (receivedFromServer)
			{
				lateRegisteredConfigs.ExceptWith(configs.configValues.Keys);
				lateRegisteredConfigs.ExceptWith(configs.configStates.Keys);
				lateRegisteredCustomValues.ExceptWith(configs.customValues.Keys);
			}
			try
			{
				if (receivedFromServer)
				{
					foreach (KeyValuePair<OwnConfigEntryBase, ReceivedConfigState> configState in configs.configStates)
					{
						bool isServerControlled = configState.Key.IsServerControlled;
						bool isHidden = configState.Key.IsHidden;
						configState.Key.IsServerControlled = configState.Value.ServerControlled;
						configState.Key.IsHidden = configState.Value.Hidden;
						configState.Key.IsPolicyStateInitialized = true;
						if (isServerControlled != configState.Value.ServerControlled || isHidden != configState.Value.Hidden)
						{
							policyTransitions.Add(new PolicyStateChangedEventArgs(configState.Key, isServerControlled, configState.Value.ServerControlled, isHidden, configState.Value.Hidden, "server package"));
						}
					}
				}
				foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in configs.configValues)
				{
					if (!IsCurrentApplication())
					{
						return;
					}
					if (receivedFromServer)
					{
						configValue.Key.StoreServerValue(configValue.Value);
						if (!configValue.Key.IsServerControlled)
						{
							RestoreLocalValueIfNeeded(configValue.Key);
							continue;
						}
						if (!configValue.Key.HasLocalBaseValue)
						{
							configValue.Key.StoreLocalBaseValue(configValue.Key.BaseConfig.BoxedValue);
						}
					}
					SetConfigValue(configValue.Key, configValue.Value);
				}
				if (receivedFromServer)
				{
					foreach (KeyValuePair<OwnConfigEntryBase, ReceivedConfigState> configState2 in configs.configStates)
					{
						if (!IsCurrentApplication())
						{
							return;
						}
						if (!configs.configValues.ContainsKey(configState2.Key))
						{
							if (configState2.Key.IsServerControlled)
							{
								ApplyServerValueIfAvailable(configState2.Key);
							}
							else
							{
								RestoreLocalValueIfNeeded(configState2.Key);
							}
						}
					}
				}
			}
			finally
			{
				foreach (KeyValuePair<ConfigFile, bool> item in saveOnConfigSet)
				{
					item.Key.SaveOnConfigSet = item.Value;
					if (IsCurrentApplication())
					{
						try
						{
							item.Key.Save();
						}
						catch (Exception arg)
						{
							DebugWarning("Apply", $"Failed to save config file '{item.Key.ConfigFilePath}' after applying synchronized values: {arg}");
						}
					}
				}
			}
			foreach (KeyValuePair<CustomSyncedValueBase, object> item2 in from entry in configs.customValues
				orderby entry.Key.Priority descending, entry.Key.RegistrationIndex
				select entry)
			{
				if (!IsCurrentApplication())
				{
					return;
				}
				if (!isServer && !item2.Key.HasLocalBaseValue)
				{
					item2.Key.StoreLocalBaseValue(item2.Key.BoxedValue);
				}
				customValuesBeingApplied.Add(item2.Key);
				try
				{
					item2.Key.BoxedValue = item2.Value;
					if (IsCurrentApplication())
					{
						item2.Key.StoreLastAcceptedValue(item2.Key.BoxedValue);
					}
				}
				catch (Exception arg2)
				{
					DebugWarning("Apply", $"Failed to apply custom value '{item2.Key.Identifier}'; continuing with the remaining entries. Error: {arg2}");
				}
				finally
				{
					customValuesBeingApplied.Remove(item2.Key);
				}
			}
			if (!IsCurrentApplication())
			{
				return;
			}
			if (receivedFromServer && configs.capabilities.HasValue)
			{
				remotePolicyChangeSupported = (configs.capabilities.Value & 1) != 0;
			}
			ConditionalConfigSync[] array = (receivedFromServer ? configSyncs.ToArray() : new ConditionalConfigSync[1] { this });
			ConditionalConfigSync[] array2 = array;
			foreach (ConditionalConfigSync conditionalConfigSync in array2)
			{
				if (!IsCurrentApplication())
				{
					return;
				}
				conditionalConfigSync.UpdateConfigMetadata();
			}
			ConditionalConfigSync[] array3 = array;
			foreach (ConditionalConfigSync conditionalConfigSync2 in array3)
			{
				if (!IsCurrentApplication())
				{
					return;
				}
				if (conditionalConfigSync2 == this || conditionalConfigSync2.CanPublishConfigStateNotifications)
				{
					conditionalConfigSync2.RaiseLockStateChangedIfNeeded();
				}
			}
			foreach (PolicyStateChangedEventArgs item3 in policyTransitions)
			{
				if (!IsCurrentApplication())
				{
					break;
				}
				RaisePolicyStateEvents(item3);
			}
			void ApplyServerValueIfAvailable(OwnConfigEntryBase config)
			{
				if (config.HasServerValue)
				{
					if (!config.HasLocalBaseValue)
					{
						config.StoreLocalBaseValue(config.BaseConfig.BoxedValue);
					}
					SetConfigValue(config, config.ServerValue);
				}
			}
			void DisableSaveOnConfigSet(ConfigFile configFile)
			{
				if (!saveOnConfigSet.ContainsKey(configFile))
				{
					saveOnConfigSet[configFile] = configFile.SaveOnConfigSet;
					configFile.SaveOnConfigSet = false;
				}
			}
			bool IsCurrentApplication()
			{
				return sessionActive && generation == transportGeneration;
			}
			void RestoreLocalValueIfNeeded(OwnConfigEntryBase config)
			{
				if (config.HasLocalBaseValue && SetConfigValue(config, config.LocalBaseValue))
				{
					config.ClearLocalBaseValue();
				}
			}
			bool SetConfigValue(OwnConfigEntryBase config, object? value)
			{
				if (IsCurrentApplication())
				{
					ConfigFile configFile = config.BaseConfig.ConfigFile;
					DisableSaveOnConfigSet(configFile);
					configsBeingApplied.Add(config.BaseConfig);
					try
					{
						config.BaseConfig.BoxedValue = value;
						if (!IsCurrentApplication())
						{
							return false;
						}
						config.StoreLastAcceptedValue(config.BaseConfig.BoxedValue);
						return true;
					}
					catch (Exception arg3)
					{
						ConfigDefinition definition = config.BaseConfig.Definition;
						DebugWarning("Apply", $"Failed to apply config {definition.Section} -> {definition.Key}; continuing with the remaining entries. Error: {arg3}");
						return false;
					}
					finally
					{
						configsBeingApplied.Remove(config.BaseConfig);
					}
				}
				return false;
			}
		}

		private static string GetSingleEntryReceiveDetails(ParsedConfigs configs)
		{
			List<string> list = new List<string>();
			if (configs.configValues.Count == 1)
			{
				ConfigDefinition definition = configs.configValues.Keys.First().BaseConfig.Definition;
				list.Add("config=" + definition.Section + " -> " + definition.Key);
			}
			if (configs.customValues.Count == 1)
			{
				list.Add("custom=" + configs.customValues.Keys.First().Identifier);
			}
			return (list.Count == 0) ? "" : (" (" + string.Join(", ", list) + ")");
		}

		private ParsedConfigs ReadConfigsFromPackage(ZPackage package, bool receivedFromServer, bool strictClientUpdate = false)
		{
			ParsedConfigs parsedConfigs = new ParsedConfigs();
			Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "\n" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c);
			Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			int num = (parsedConfigs.entryCount = GameReflection.PackageReadInt(package));
			if (num < 0 || num > 8192)
			{
				throw new InvalidDataException($"Invalid config entry count {num}");
			}
			for (int num2 = 0; num2 < num; num2++)
			{
				PackageEntryKind packageEntryKind = (PackageEntryKind)GameReflection.PackageReadByte(package);
				byte[] array = GameReflection.PackageReadByteArray(package, 20971520);
				if (array.Length > 20971520)
				{
					if (strictClientUpdate)
					{
						parsedConfigs.Reject($"entry {num2 + 1} exceeds the {20971520}-byte entry limit");
					}
					else
					{
						DebugWarning("Read", $"Skipping too large entry payload ({array.Length})");
					}
					continue;
				}
				ZPackage package2 = GameReflection.NewPackage(array);
				switch (packageEntryKind)
				{
				case PackageEntryKind.Config:
				{
					string text = GameReflection.PackageReadString(package2);
					string text2 = GameReflection.PackageReadString(package2);
					string text3 = GameReflection.PackageReadString(package2);
					string item = "config\n" + text + "\n" + text2;
					if (!hashSet.Add(item))
					{
						if (strictClientUpdate)
						{
							parsedConfigs.Reject("duplicate config entry " + text + " -> " + text2);
						}
						break;
					}
					if (dictionary.TryGetValue(text + "\n" + text2, out var value))
					{
						try
						{
							parsedConfigs.configValues[value] = TomlTypeConverter.ConvertToValue(text3, value.BaseConfig.SettingType);
						}
						catch (Exception ex)
						{
							if (strictClientUpdate)
							{
								parsedConfigs.Reject("config " + text + " -> " + text2 + " could not be parsed: " + ex.Message);
							}
							else
							{
								DebugWarning("Read", $"Config value of setting \"{value.BaseConfig.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}");
							}
						}
					}
					else if (strictClientUpdate)
					{
						parsedConfigs.Reject("unknown config entry " + text + " -> " + text2);
					}
					else
					{
						DebugWarning("Read", "Received unknown config entry " + text + "/" + text2 + ". This may happen if client and server versions of the mod do not match.");
					}
					if (strictClientUpdate && GameReflection.PackageGetPos(package2) != GameReflection.PackageSize(package2))
					{
						parsedConfigs.Reject("config entry " + text + " -> " + text2 + " contains trailing data");
					}
					break;
				}
				case PackageEntryKind.ConfigState:
				{
					string text4 = GameReflection.PackageReadString(package2);
					string text5 = GameReflection.PackageReadString(package2);
					bool serverControlled = GameReflection.PackageReadBool(package2);
					bool hidden = GameReflection.PackageReadBool(package2);
					string item2 = "state\n" + text4 + "\n" + text5;
					if (!hashSet.Add(item2))
					{
						if (strictClientUpdate)
						{
							parsedConfigs.Reject("duplicate config state " + text4 + " -> " + text5);
						}
						break;
					}
					if (dictionary.TryGetValue(text4 + "\n" + text5, out var value2))
					{
						if (strictClientUpdate)
						{
							p

ConditionalConfigSync.Plugin.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Conditional Config Sync Plugin")]
[assembly: AssemblyDescription("BepInEx bootstrap for the Conditional Config Sync package.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("shudnal")]
[assembly: AssemblyProduct("Conditional Config Sync")]
[assembly: AssemblyCopyright("Copyright © shudnal 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("815dc453-badf-4351-b8aa-92321836fcb3")]
[assembly: AssemblyFileVersion("1.0.10")]
[assembly: AssemblyInformationalVersion("1.0.10")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/shudnal/ConditionalConfigSync")]
[assembly: AssemblyMetadata("License", "Unlicense")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.10.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ConditionalConfigSync
{
	[BepInPlugin("_shudnal.ConditionalConfigSync", "Conditional Config Sync", "1.0.10")]
	[Description("Standalone BepInEx bootstrap that initializes ConditionalConfigSync.dll.")]
	public sealed class ConditionalConfigSyncPlugin : BaseUnityPlugin
	{
		[Description("BepInEx hard-dependency identifier used by mods that consume ConditionalConfigSync.")]
		public const string PluginGuid = "_shudnal.ConditionalConfigSync";

		[Description("Display name of the standalone BepInEx plugin.")]
		public const string PluginName = "Conditional Config Sync";

		[Description("Package version sourced from PluginInfo.PluginVersion.")]
		public const string PluginVersion = "1.0.10";

		private const string PluginAssemblyName = "ConditionalConfigSync.Plugin";

		private const string CoreAssemblyName = "ConditionalConfigSync";

		private const string ActiveBootstrapKey = "_shudnal.ConditionalConfigSync.ActiveBootstrapInstance";

		private bool ownsBootstrap;

		private void Awake()
		{
			string text = typeof(ConditionalConfigSyncPlugin).Assembly.GetName().Name ?? string.Empty;
			if (!string.Equals(text, "ConditionalConfigSync.Plugin", StringComparison.Ordinal))
			{
				((BaseUnityPlugin)this).Logger.LogFatal((object)("Embedded ConditionalConfigSync bootstrap detected inside assembly '" + text + "'. The bootstrap plugin must only run from ConditionalConfigSync.Plugin.dll."));
				((Behaviour)this).enabled = false;
				return;
			}
			string text2 = typeof(ConditionalConfigSync).Assembly.GetName().Name ?? string.Empty;
			if (!string.Equals(text2, "ConditionalConfigSync", StringComparison.Ordinal))
			{
				((BaseUnityPlugin)this).Logger.LogFatal((object)("ConditionalConfigSync core was resolved from unsupported assembly '" + text2 + "'. Remove embedded copies and install the standalone ConditionalConfigSync mod."));
				((Behaviour)this).enabled = false;
				return;
			}
			if (!TryClaimBootstrap())
			{
				((Behaviour)this).enabled = false;
				return;
			}
			try
			{
				ConditionalConfigSync.InitializeRuntime();
			}
			catch
			{
				ReleaseBootstrap();
				((Behaviour)this).enabled = false;
				throw;
			}
		}

		private bool TryClaimBootstrap()
		{
			AppDomain currentDomain = AppDomain.CurrentDomain;
			lock (currentDomain)
			{
				object data = currentDomain.GetData("_shudnal.ConditionalConfigSync.ActiveBootstrapInstance");
				if (data != null && data != this)
				{
					Assembly assembly = data.GetType().Assembly;
					Assembly assembly2 = typeof(ConditionalConfigSyncPlugin).Assembly;
					((BaseUnityPlugin)this).Logger.LogFatal((object)("A second ConditionalConfigSync bootstrap attempted to initialize while another bootstrap is already active. Active bootstrap: " + DescribeAssembly(assembly) + ". Attempted bootstrap: " + DescribeAssembly(assembly2) + "."));
					return false;
				}
				currentDomain.SetData("_shudnal.ConditionalConfigSync.ActiveBootstrapInstance", this);
				ownsBootstrap = true;
				return true;
			}
		}

		private static string DescribeAssembly(Assembly assembly)
		{
			string text;
			try
			{
				text = (assembly.IsDynamic ? "<dynamic>" : assembly.Location);
			}
			catch
			{
				text = "<unknown location>";
			}
			return "'" + assembly.FullName + "' at '" + text + "'";
		}

		private void ReleaseBootstrap()
		{
			if (!ownsBootstrap)
			{
				return;
			}
			AppDomain currentDomain = AppDomain.CurrentDomain;
			lock (currentDomain)
			{
				if (currentDomain.GetData("_shudnal.ConditionalConfigSync.ActiveBootstrapInstance") == this)
				{
					currentDomain.SetData("_shudnal.ConditionalConfigSync.ActiveBootstrapInstance", null);
				}
			}
			ownsBootstrap = false;
		}

		private void OnDestroy()
		{
			if (!ownsBootstrap)
			{
				return;
			}
			try
			{
				ConditionalConfigSync.ShutdownRuntime();
			}
			finally
			{
				ReleaseBootstrap();
			}
		}
	}
	public static class SoftDependencyBridge
	{
		private static readonly MethodInfo AddConfigEntryDefinition = typeof(ConditionalConfigSync).GetMethods(BindingFlags.Instance | BindingFlags.Public).Single(delegate(MethodInfo method)
		{
			if (method.Name != "AddConfigEntry" || !method.IsGenericMethodDefinition)
			{
				return false;
			}
			ParameterInfo[] parameters = method.GetParameters();
			return parameters.Length == 3 && parameters[0].ParameterType.IsGenericType && parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(ConfigEntry<>) && parameters[1].ParameterType == typeof(ConfigSyncMode) && parameters[2].ParameterType == typeof(bool);
		});

		private static readonly MethodInfo AddLockingConfigEntryDefinition = typeof(ConditionalConfigSync).GetMethods(BindingFlags.Instance | BindingFlags.Public).Single(delegate(MethodInfo method)
		{
			if (method.Name != "AddLockingConfigEntry" || !method.IsGenericMethodDefinition)
			{
				return false;
			}
			ParameterInfo[] parameters = method.GetParameters();
			return parameters.Length == 1 && parameters[0].ParameterType.IsGenericType && parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(ConfigEntry<>);
		});

		private static readonly object MethodCacheLock = new object();

		private static readonly Dictionary<Type, MethodInfo> AddConfigEntryMethods = new Dictionary<Type, MethodInfo>();

		private static readonly Dictionary<Type, MethodInfo> AddLockingConfigEntryMethods = new Dictionary<Type, MethodInfo>();

		public static int ApiVersion => 1;

		public static bool IsRuntimeReady
		{
			get
			{
				try
				{
					ConditionalConfigSync.EnsureRuntimeReady();
					return true;
				}
				catch
				{
					return false;
				}
			}
		}

		public static object CreateConfigSync(string name, string displayName, string currentVersion, string minimumRequiredVersion, bool modRequired, string modRequirementMode, bool allowClientConfigUpdatesWhenUnlocked)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			if (string.IsNullOrWhiteSpace(name))
			{
				throw new ArgumentException("A stable consumer GUID is required.", "name");
			}
			ConditionalConfigSync.EnsureRuntimeReady();
			if (!Enum.TryParse<ModRequirementMode>(modRequirementMode, ignoreCase: false, out ModRequirementMode result) || !Enum.IsDefined(typeof(ModRequirementMode), result))
			{
				throw new ArgumentOutOfRangeException("modRequirementMode", modRequirementMode, "Unknown Conditional Config Sync mod requirement mode.");
			}
			return (object)new ConfigSync(name)
			{
				DisplayName = (string.IsNullOrWhiteSpace(displayName) ? name : displayName),
				CurrentVersion = currentVersion,
				MinimumRequiredVersion = minimumRequiredVersion,
				ModRequired = modRequired,
				ModRequirementMode = result,
				AllowClientConfigUpdatesWhenUnlocked = allowClientConfigUpdatesWhenUnlocked
			};
		}

		public static void RegisterConfigEntry(object configSyncInstance, ConfigEntryBase configEntry, string syncMode, bool serverControlledByDefault)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			ConditionalConfigSync.EnsureRuntimeReady();
			ConditionalConfigSync val = (ConditionalConfigSync)((configSyncInstance is ConditionalConfigSync) ? configSyncInstance : null);
			if (val == null)
			{
				throw new ArgumentException("The supplied context was not created by Conditional Config Sync.", "configSyncInstance");
			}
			if (configEntry == null)
			{
				throw new ArgumentNullException("configEntry");
			}
			if (!Enum.TryParse<ConfigSyncMode>(syncMode, ignoreCase: false, out ConfigSyncMode result) || !Enum.IsDefined(typeof(ConfigSyncMode), result))
			{
				throw new ArgumentOutOfRangeException("syncMode", syncMode, "Unknown Conditional Config Sync config mode.");
			}
			MethodInfo closedMethod = GetClosedMethod(AddConfigEntryDefinition, AddConfigEntryMethods, configEntry.SettingType);
			Invoke(closedMethod, val, new object[3] { configEntry, result, serverControlledByDefault });
		}

		public static void RegisterLockingConfigEntry(object configSyncInstance, ConfigEntryBase configEntry)
		{
			ConditionalConfigSync.EnsureRuntimeReady();
			ConditionalConfigSync val = (ConditionalConfigSync)((configSyncInstance is ConditionalConfigSync) ? configSyncInstance : null);
			if (val == null)
			{
				throw new ArgumentException("The supplied context was not created by Conditional Config Sync.", "configSyncInstance");
			}
			if (configEntry == null)
			{
				throw new ArgumentNullException("configEntry");
			}
			Type settingType = configEntry.SettingType;
			if (!typeof(IConvertible).IsAssignableFrom(settingType))
			{
				throw new ArgumentException("Locking config type '" + settingType.FullName + "' must implement IConvertible.", "configEntry");
			}
			MethodInfo closedMethod = GetClosedMethod(AddLockingConfigEntryDefinition, AddLockingConfigEntryMethods, settingType);
			Invoke(closedMethod, val, new object[1] { configEntry });
		}

		private static MethodInfo GetClosedMethod(MethodInfo definition, Dictionary<Type, MethodInfo> cache, Type settingType)
		{
			lock (MethodCacheLock)
			{
				if (!cache.TryGetValue(settingType, out MethodInfo value))
				{
					value = (cache[settingType] = definition.MakeGenericMethod(settingType));
				}
				return value;
			}
		}

		private static void Invoke(MethodInfo method, object target, object[] arguments)
		{
			try
			{
				method.Invoke(target, arguments);
			}
			catch (TargetInvocationException ex) when (ex.InnerException != null)
			{
				ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
				throw;
			}
		}
	}
}