Decompiled source of ConditionalConfigSync v1.0.0

ConditionalConfigSync.dll

Decompiled 19 hours 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.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
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")]
[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.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[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 ConfigEntryGetSerializedValuePatch
		{
			internal static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase configData = GetConfigData(__instance);
				if (configData == null || IsWritableConfig(configData))
				{
					return true;
				}
				__result = TomlTypeConverter.ConvertToString(configData.LocalBaseValue, __instance.SettingType);
				return false;
			}
		}

		internal static class ConfigEntrySetSerializedValuePatch
		{
			internal static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase configData = GetConfigData(__instance);
				if (configData == null || !configData.HasLocalBaseValue)
				{
					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>();
		}

		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 static PackageEntry ServerVersion(string version)
			{
				return new PackageEntry
				{
					kind = PackageEntryKind.ServerVersion,
					value = version
				};
			}

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

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

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

			public string received = null;

			public string field = "";
		}

		private enum ConfigPolicyOverride
		{
			Default,
			ForceServerControlled,
			ForceClientControlled
		}

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

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

		internal static class ZNetAwakePatch
		{
			internal static void Postfix(ZNet __instance)
			{
				EnsureDebugSupportInitialized();
				isServer = GameReflection.IsServer(__instance);
				sessionActive = true;
				if (isServer)
				{
					EnsurePolicySupportInitialized(createIfMissing: true);
				}
				foreach (ConditionalConfigSync configSync in configSyncs)
				{
					configSync.RegisterForActiveSession();
				}
				if (isServer)
				{
					GameReflection.StartCoroutine(WatchAdminListChanges(), __instance);
				}
				void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { PackageEntry.LockExempt(isAdmin) });
					ConditionalConfigSync conditionalConfigSync = configSyncs.FirstOrDefault();
					if (conditionalConfigSync != null)
					{
						GameReflection.StartCoroutine(conditionalConfigSync.SendZPackage(peers, package), __instance);
					}
				}
				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 (!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();
							foreach (ConditionalConfigSync sync in configSyncs)
							{
								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))
				{
					return;
				}
				foreach (ConditionalConfigSync configSync in configSyncs)
				{
					configSync.RegisterClientRpcHandler(peer);
				}
			}
		}

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

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

				public void Send(ZPackage pkg)
				{
					int position = GameReflection.PackageGetPos(pkg);
					GameReflection.PackageSetPos(pkg, 0);
					int num = GameReflection.PackageReadInt(pkg);
					if ((num == GameReflection.StableHash("PeerInfo") || num == GameReflection.StableHash("RoutedRPC") || num == GameReflection.StableHash("ZDOData")) && !finished)
					{
						ZPackage val = GameReflection.NewPackage(GameReflection.PackageGetArray(pkg));
						GameReflection.PackageSetPos(val, position);
						Package.Add(val);
					}
					else
					{
						GameReflection.PackageSetPos(pkg, position);
						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)
			{
				ZNetPeer peer;
				if (GameReflection.IsServer(__instance) && __state != null)
				{
					peer = GameReflection.GetPeer(rpc, __instance);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						GameReflection.StartCoroutine(sendAsync(), __instance);
					}
				}
				void SendBufferedData()
				{
					BufferingSocket bufferingSocket2;
					if (GameReflection.GetRpcSocket(rpc) is BufferingSocket bufferingSocket)
					{
						GameReflection.SetRpcSocket(rpc, bufferingSocket.Original);
						ZNetPeer peer2 = GameReflection.GetPeer(rpc, __instance);
						if (peer2 != null)
						{
							GameReflection.SetPeerSocket(peer2, bufferingSocket.Original);
						}
						bufferingSocket2 = bufferingSocket;
					}
					else
					{
						bufferingSocket2 = __state;
					}
					if (!bufferingSocket2.finished)
					{
						bufferingSocket2.finished = true;
						for (int i = 0; i < bufferingSocket2.Package.Count; i++)
						{
							if (i == bufferingSocket2.versionMatchQueued)
							{
								GameReflection.SocketVersionMatch(bufferingSocket2.Original);
							}
							GameReflection.SocketSend(bufferingSocket2.Original, bufferingSocket2.Package[i]);
						}
						if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
						{
							GameReflection.SocketVersionMatch(bufferingSocket2.Original);
						}
					}
				}
				IEnumerator sendAsync()
				{
					try
					{
						foreach (ConditionalConfigSync configSync in configSyncs)
						{
							ZPackage package = configSync.CreateFullSyncPackage(peer);
							configSync.DebugLog(ConditionalConfigSyncDebugLevel.Basic, "InitialSync", $"Sending full sync to {FormatPeer(peer)}, admin={IsPeerAdmin(peer)}, configs={configSync.allConfigs.Count}, custom={configSync.allCustomValues.Count}, size={GameReflection.PackageSize(package)}");
							yield return GameReflection.StartCoroutine(configSync.SendZPackage(new List<ZNetPeer> { peer }, package), __instance);
						}
					}
					finally
					{
						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 clients to publish changes, matching ServerSync unlocked-client behavior.")]
		public bool AllowClientConfigUpdatesWhenUnlocked = true;

		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 HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>();

		private static bool isServer;

		private static bool lockExempt = false;

		private OwnConfigEntryBase? lockedConfig = null;

		private bool? lastNotifiedLockState;

		[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 string SyncPolicyFileName = "ConditionalConfigSync.SyncPolicy.cfg";

		private const string HiddenConfigsFileName = "ConditionalConfigSync.HiddenConfigs.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 Dictionary<string, ConfigPolicyOverride> syncPolicy = new Dictionary<string, ConfigPolicyOverride>(StringComparer.OrdinalIgnoreCase);

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

		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 const string ConfigDirectoryName = "shudnal.ConditionalConfigSync";

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

		private static readonly object configDirectoryLock = new object();

		private static bool configDirectoryInitialized;

		private const string ResyncRpcSuffix = " ConditionalConfigSync Resync";

		private const int StableReadAttempts = 5;

		private const int StableReadDelayMilliseconds = 50;

		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 static bool sessionActive;

		private static Harmony? runtimeHarmony;

		private static AssemblyLoadEventHandler? assemblyLoadHandler;

		private short sendCount;

		private short processingCount;

		private bool lastHandledPackageWasFull;

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

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

		private readonly Queue<ZPackage> pendingSequencedCustomValuePackages = new Queue<ZPackage>();

		private bool flushingPendingBroadcasts;

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

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

		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("Whether the owning mod must be installed and compatible on the remote peer.")]
		public bool ModRequired { get; set; } = false;

		[Description("Whether non-admin clients are currently blocked from publishing server-controlled settings.")]
		public bool IsLocked
		{
			get
			{
				bool? flag = forceConfigLocking;
				bool num;
				if (!flag.HasValue)
				{
					if (lockedConfig == null)
					{
						goto IL_0052;
					}
					num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0;
				}
				else
				{
					num = flag == true;
				}
				if (!num)
				{
					goto IL_0052;
				}
				int result = ((!lockExempt) ? 1 : 0);
				goto IL_0053;
				IL_0052:
				result = 0;
				goto IL_0053;
				IL_0053:
				return (byte)result != 0;
			}
			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)
				{
					isSourceOfTruth = value;
					InvokeEventHandlers(this.SourceOfTruthChanged, value, "SourceOfTruthChanged");
				}
			}
		}

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

		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 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 => sendCount > 0;

		private bool IsProcessing => processingCount > 0;

		private bool ShouldDeferOutgoingBroadcasts => ProcessingServerUpdate || 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)
		{
			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> syncedEntry = new SyncedConfigEntry<T>(configEntry)
			{
				SyncMode = syncMode,
				SynchronizedConfig = flag
			};
			AccessTools.DeclaredField(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, new object[1]
			{
				new ConfigurationManagerAttributes()
			}.Concat(((ConfigEntryBase)configEntry).Description.Tags ?? Array.Empty<object>()).Concat(new SyncedConfigEntry<T>[1] { syncedEntry }).ToArray());
			configEntry.SettingChanged += delegate
			{
				OnConfigEntryChanged((ConfigEntryBase)(object)configEntry, syncedEntry);
			};
			allConfigs.Add(syncedEntry);
			bool flag2 = IsSourceOfTruth && isServer && GameReflection.HasZNet && policySupportInitialized;
			syncedEntry.IsServerControlled = (flag2 ? ComputeServerControlled(syncedEntry) : GetDefaultServerControlled(syncedEntry));
			syncedEntry.IsHidden = flag2 && ComputeHidden(syncedEntry);
			syncedEntry.PolicyStateInitialized = flag2;
			ConfigurationManagerAttributes configAttribute = GetConfigAttribute<ConfigurationManagerAttributes>((ConfigEntryBase)(object)configEntry);
			configAttribute.ReadOnly = !IsWritableConfig(syncedEntry);
			configAttribute.Browsable = !syncedEntry.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(syncedEntry);
			return syncedEntry;
		}

		[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.IsServerControlled = true;
			lockedConfig.PolicyStateInitialized = false;
			lockingConfig.SettingChanged += delegate
			{
				this.LockedConfigChanged?.Invoke();
			};
			LockedConfigChanged -= ServerLockedSettingChanged;
			LockedConfigChanged += ServerLockedSettingChanged;
			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);
			customValue.ValueChanged += delegate
			{
				OnCustomValueChanged(customValue);
			};
			DebugLog(ConditionalConfigSyncDebugLevel.Trace, "Register", $"Added custom value {customValue.Identifier}, type={customValue.Type.Name}, priority={customValue.Priority}, sequenced={customValue.PreserveUpdateSequence}");
			ScheduleLateRegistrationSync(null, customValue);
		}

		private static bool IsWritableConfig(OwnConfigEntryBase config)
		{
			ConditionalConfigSync conditionalConfigSync = configSyncs.FirstOrDefault((ConditionalConfigSync cs) => cs.allConfigs.Contains(config));
			if (conditionalConfigSync == null)
			{
				return true;
			}
			return conditionalConfigSync.IsSourceOfTruth || !config.IsServerControlled || !config.HasLocalBaseValue || (!conditionalConfigSync.IsLocked && (config != conditionalConfigSync.lockedConfig || lockExempt));
		}

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

		private void ResetConfigsFromServer()
		{
			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>();
			try
			{
				foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.HasLocalBaseValue))
				{
					ConfigFile configFile = item.BaseConfig.ConfigFile;
					if (!dictionary.ContainsKey(configFile))
					{
						dictionary[configFile] = configFile.SaveOnConfigSet;
						configFile.SaveOnConfigSet = false;
					}
					configsBeingApplied.Add(item.BaseConfig);
					try
					{
						item.BaseConfig.BoxedValue = item.LocalBaseValue;
						item.ClearLocalBaseValue();
						item.ClearServerValue();
					}
					catch (Exception arg)
					{
						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;
				}
			}
			foreach (OwnConfigEntryBase allConfig in allConfigs)
			{
				bool isServerControlled = allConfig.IsServerControlled;
				bool isHidden = allConfig.IsHidden;
				bool defaultServerControlled = GetDefaultServerControlled(allConfig);
				allConfig.ClearServerValue();
				allConfig.IsServerControlled = defaultServerControlled;
				allConfig.IsHidden = false;
				allConfig.PolicyStateInitialized = false;
				if (isServerControlled != defaultServerControlled || isHidden)
				{
					list.Add(new PolicyStateChangedEventArgs(allConfig, isServerControlled, defaultServerControlled, isHidden, newHidden: false, "server connection reset"));
				}
			}
			foreach (CustomSyncedValueBase item3 in allCustomValues.Where((CustomSyncedValueBase config) => config.HasLocalBaseValue))
			{
				customValuesBeingApplied.Add(item3);
				try
				{
					item3.BoxedValue = item3.LocalBaseValue;
					item3.ClearLocalBaseValue();
				}
				catch (Exception arg2)
				{
					DebugWarning("Reset", $"Failed to restore local custom value '{item3.Identifier}'; continuing. Error: {arg2}");
				}
				finally
				{
					customValuesBeingApplied.Remove(item3);
				}
			}
			ServerLockedSettingChanged();
			foreach (PolicyStateChangedEventArgs item4 in list)
			{
				RaisePolicyStateEvents(item4);
			}
		}

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

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

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

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

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

		private static void ScheduleDebugConfigReload()
		{
			lock (debugSupportLock)
			{
				if (debugConfigReloadScheduled)
				{
					return;
				}
				debugConfigReloadScheduled = true;
			}
			ThreadPool.QueueUserWorkItem(delegate
			{
				Thread.Sleep(500);
				lock (debugSupportLock)
				{
					debugConfigReloadScheduled = false;
				}
				LoadDebugConfig(createIfMissing: false, quiet: 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) ? 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 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)
			{
				InitialSyncDone = true;
				InvokeEventHandlers(this.InitialSyncCompleted, "InitialSyncCompleted");
			}
		}

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

		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> list = new List<PolicyStateChangedEventArgs>();
			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.PolicyStateInitialized = true;
						if (isServerControlled != configState.Value.ServerControlled || isHidden != configState.Value.Hidden)
						{
							list.Add(new PolicyStateChangedEventArgs(configState.Key, isServerControlled, configState.Value.ServerControlled, isHidden, configState.Value.Hidden, "server package"));
						}
					}
				}
				foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in configs.configValues)
				{
					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 (!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;
					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> customValue in configs.customValues)
			{
				if (!isServer && !customValue.Key.HasLocalBaseValue)
				{
					customValue.Key.StoreLocalBaseValue(customValue.Key.BoxedValue);
				}
				customValuesBeingApplied.Add(customValue.Key);
				try
				{
					customValue.Key.BoxedValue = customValue.Value;
				}
				catch (Exception arg2)
				{
					DebugWarning("Apply", $"Failed to apply custom value '{customValue.Key.Identifier}'; continuing with the remaining entries. Error: {arg2}");
				}
				finally
				{
					customValuesBeingApplied.Remove(customValue.Key);
				}
			}
			if (receivedFromServer)
			{
				foreach (ConditionalConfigSync configSync in configSyncs)
				{
					configSync.ServerLockedSettingChanged();
				}
			}
			foreach (PolicyStateChangedEventArgs item2 in list)
			{
				RaisePolicyStateEvents(item2);
			}
			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;
				}
			}
			void RestoreLocalValueIfNeeded(OwnConfigEntryBase config)
			{
				if (config.HasLocalBaseValue && SetConfigValue(config, config.LocalBaseValue))
				{
					config.ClearLocalBaseValue();
				}
			}
			bool SetConfigValue(OwnConfigEntryBase config, object? value)
			{
				ConfigFile configFile = config.BaseConfig.ConfigFile;
				DisableSaveOnConfigSet(configFile);
				configsBeingApplied.Add(config.BaseConfig);
				try
				{
					config.BaseConfig.BoxedValue = value;
					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);
				}
			}
		}

		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)
		{
			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);
			int num = 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)
				{
					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);
					if (dictionary.TryGetValue(text + "\n" + text2, out var value))
					{
						try
						{
							parsedConfigs.configValues[value] = TomlTypeConverter.ConvertToValue(text3, value.BaseConfig.SettingType);
						}
						catch (Exception ex)
						{
							DebugWarning("Read", $"Config value of setting \"{value.BaseConfig.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}");
						}
					}
					else
					{
						DebugWarning("Read", "Received unknown config entry " + text + "/" + text2 + ". This may happen if client and server versions of the mod do not match.");
					}
					break;
				}
				case PackageEntryKind.ConfigState:
				{
					string text5 = GameReflection.PackageReadString(package2);
					string text6 = GameReflection.PackageReadString(package2);
					bool serverControlled = GameReflection.PackageReadBool(package2);
					bool hidden = GameReflection.PackageReadBool(package2);
					if (dictionary.TryGetValue(text5 + "\n" + text6, out var value2))
					{
						parsedConfigs.configStates[value2] = new ReceivedConfigState(serverControlled, hidden);
						break;
					}
					DebugWarning("Read", "Received unknown config state " + text5 + "/" + text6 + ". This may happen if client and server versions of the mod do not match.");
					break;
				}
				case PackageEntryKind.CustomValue:
				{
					string text7 = GameReflection.PackageReadString(package2);
					string text8 = GameReflection.PackageReadString(package2);
					if (!dictionary2.TryGetValue(text7, out var value3))
					{
						DebugWarning("Read", "Received unknown custom synced value " + text7 + ". This may happen if client and server versions of the mod do not match.");
						break;
					}
					string zPackageTypeString = GetZPackageTypeString(value3.Type);
					if (text8 != zPackageTypeString)
					{
						DebugWarning("Read", "Got unexpected type " + text8 + " for custom synced value " + text7 + ", expecting " + zPackageTypeString);
						break;
					}
					try
					{
						parsedConfigs.customValues[value3] = ReadCustomValueFromPackage(package2, value3.Type);
					}
					catch (InvalidDeserializationTypeException ex2)
					{
						DebugWarning("Read", "Got unexpected struct internal type " + ex2.received + " for field " + ex2.field + " struct " + text8 + " for custom synced value " + text7 + ", expecting " + ex2.expected);
					}
					catch (Exception arg)
					{
						DebugWarning("Read", $"Could not deserialize custom synced value {text7}: {arg}");
					}
					break;
				}
				case PackageEntryKind.ServerVersion:
				{
					string text4 = GameReflection.PackageReadString(package2);
					if (receivedFromServer && text4 != CurrentVersion)
					{
						DebugWarning("Version", "Received server version is not equal: server version=" + text4 + ", local version=" + (CurrentVersion ?? "unknown"));
					}
					break;
				}
				case PackageEntryKind.LockExempt:
				{
					bool flag = GameReflection.PackageReadBool(package2);
					if (receivedFromServer)
					{
						lockExempt = flag;
					}
					break;
				}
				default:
					DebugWarning("Read", $"Received unknown config entry kind {(byte)packageEntryKind}");
					break;
				}
			}
			return parsedConfigs;
		}

		private static ZPackage ConfigsToPackage(IEnumerable<ConfigEntryBase>? configs = null, IEnumerable<CustomSyncedValueBase>? customValues = null, IEnumerable<PackageEntry>? packageEntries = null, bool partial = true, bool includeConfigValues = true, bool includeAllProvidedConfigStates = false)
		{
			List<OwnConfigEntryBase> list = new List<OwnConfigEntryBase>();
			if (configs != null)
			{
				foreach (ConfigEntryBase config in configs)
				{
					OwnConfigEntryBase configData = GetConfigData(config);
					if (configData != null && (includeAllProvidedConfigStates || ShouldIncludeConfigInPackage(configData)) && !list.Contains(configData))
					{
						list.Add(configData);
					}
				}
			}
			List<OwnConfigEntryBase> list2 = (includeConfigValues ? list.Where(GetPackageServerControlled).ToList() : new List<OwnConfigEntryBase>());
			List<CustomSyncedValueBase> list3 = customValues?.ToList() ?? new List<CustomSyncedValueBase>();
			List<PackageEntry> list4 = packageEntries?.ToList() ?? new List<PackageEntry>();
			ZPackage val = GameReflection.NewPackage();
			GameReflection.PackageWrite(val, (byte)((partial ? 1 : 0) | 8));
			GameReflection.PackageWrite(val, list2.Count + list.Count + list3.Count + list4.Count);
			foreach (PackageEntry item in list4)
			{
				AddEntryToPackage(val, item);
			}
			foreach (OwnConfigEntryBase item2 in list)
			{
				AddEntryToPackage(val, PackageEntry.ConfigState(item2.BaseConfig, GetPackageServerControlled(item2), GetPackageHidden(item2)));
			}
			foreach (CustomSyncedValueBase item3 in list3)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					kind = PackageEntryKind.CustomValue,
					key = item3.Identifier,
					type = item3.Type,
					value = item3.BoxedValue
				});
			}
			foreach (OwnConfigEntryBase item4 in list2)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					kind = PackageEntryKind.Config,
					section = item4.BaseConfig.Definition.Section,
					key = item4.BaseConfig.Definition.Key,
					type = item4.BaseConfig.SettingType,
					value = item4.BaseConfig.BoxedValue
				});
			}
			return val;
		}

		private static void AddEntryToPackage(ZPackage package, PackageEntry entry)
		{
			ZPackage package2 = GameReflection.NewPackage();
			switch (entry.kind)
			{
			case PackageEntryKind.Config:
				GameReflection.PackageWrite(package2, entry.section);
				GameReflection.PackageWrite(package2, entry.key);
				GameReflection.PackageWrite(package2, TomlTypeConverter.ConvertToString(entry.value, entry.type));
				break;
			case PackageEntryKind.CustomValue:
				GameReflection.PackageWrite(package2, entry.key);
				GameReflection.PackageWrite(package2, GetZPackageTypeString(entry.type));
				WriteCustomValueToPackage(package2, entry.type, entry.value);
				break;
			case PackageEntryKind.ServerVersion:
				GameReflection.PackageWrite(package2, entry.value?.ToString() ?? "");
				break;
			case PackageEntryKind.LockExempt:
			{
				object value = entry.value;
				bool flag = default(bool);
				int num;
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
				GameReflection.PackageWrite(package2, (byte)((uint)num & (flag ? 1u : 0u)) != 0);
				break;
			}
			case PackageEntryKind.ConfigState:
				GameReflection.PackageWrite(package2, entry.section);
				GameReflection.PackageWrite(package2, entry.key);
				GameReflection.PackageWrite(package2, entry.serverControlled);
				GameReflection.PackageWrite(package2, entry.hidden);
				break;
			default:
				throw new ArgumentOutOfRangeException("kind", entry.kind, null);
			}
			GameReflection.PackageWrite(package, (byte)entry.kind);
			GameReflection.PackageWrite(package, GameReflection.PackageGetArray(package2));
		}

		private static string GetZPackageTypeString(Type type)
		{
			return type.AssemblyQualifiedName;
		}

		private static void WriteCustomValueToPackage(ZPackage package, Type type, object? value)
		{
			GameReflection.PackageWrite(package, value != null);
			if (value != null)
			{
				WriteValueWithTypeToZPackage(package, type, value);
			}
		}

		private static object? ReadCustomValueFromPackage(ZPackage package, Type type)
		{
			if (!GameReflection.PackageReadBool(package))
			{
				return null;
			}
			return ReadValueWithTypeFromZPackage(package, type);
		}

		private static void WriteValueWithTypeToZPackage(ZPackage package, Type type, object value)
		{
			Type type2 = Nullable.GetUnderlyingType(type) ?? type;
			if (typeof(ISerializableParameter).IsAssignableFrom(type2))
			{
				GameReflection.SerializeParameter(value, ref package);
				return;
			}
			if (type2.IsEnum)
			{
				WriteValueWithTypeToZPackage(package, Enum.GetUnderlyingType(type2), ((IConvertible)value).ToType(Enum.GetUnderlyingType(type2), CultureInfo.InvariantCulture));
				return;
			}
			if (value is ICollection collection && type2 != typeof(string) && type2 != typeof(List<string>))
			{
				GameReflection.PackageWrite(package, collection.Count);
				{
					foreach (object item in collection)
					{
						WriteValueWithTypeToZPackage(package, item.GetType(), item);
					}
					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));
					object value2 = fieldInfo.GetValue(value);
					WriteCustomValueToPackage(package, fieldInfo.FieldType, value2);
				}
			}
			else
			{
				GameReflection.Serialize(new object[1] { value }, ref package);
			}
		}

		private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type)
		{
			Type type2 = Nullable.GetUnderlyingType(type) ?? type;
			if (typeof(ISerializableParameter).IsAssignableFrom(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 ((object)type2 != null && type2.IsValueType && !type2.IsPrimitive)
			{
				FieldInfo[] fields = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int num = GameReflection.PackageReadInt(package);
				if (num != fields.Length)
				{
					throw new InvalidDeserializationTypeException
					{
						received = $"(field count: {num})",
						expected = $"(field count: {fields.Length})"
					};
				}
				object uninitializedObject = FormatterServices.GetUninitializedObject(type2);
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					string text = GameReflection.PackageReadString(package);
					if (text != GetZPackageTypeString(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 num2 = 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 j = 0; j < num2; j++)
				{
					object obj2 = ReadValueWithTypeFromZPackage(package, type3);
					dictionary.Add(field.GetValue(obj2), field2.GetValue(obj2));
				}
				return dictionary;
			}
			if (type2 != typeof(List<string>) && type2.IsGenericType)
			{
				Type type4 = typeof(ICollection<>).MakeGenericType(type2.GenericTypeArguments[0]);
				if ((object)type4 != null && type4.IsAssignableFrom(type2))
				{
					int num3 = GameReflection.PackageReadInt(package);
					object obj3 = Activator.CreateInstance(type2);
					MethodInfo method = type4.GetMethod("Add");
					for (int k = 0; k < num3; k++)
					{
						method.Invoke(obj3, new object[1] { ReadValueWithTypeFromZPackage(package, type2.GenericTypeArguments[0]) });
					}
					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);
			return data.First();
		}

		private static ArraySegment<byte> GetPackageArraySegment(ZPackage package)
		{
			if (GameReflection.PackageStream(package).TryGetBuffer(out var buffer))
			{
				return new ArraySegment<byte>(buffer.Array, buffer.Offset, GameReflection.PackageSize(package));
			}
			byte[] array = GameReflection.PackageGetArray(package);
			return new ArraySegment<byte>(array, 0, array.Length);
		}

		private static void WriteByteArray(ZPackage package, ArraySegment<byte> data)
		{
			GameReflection.PackageWrite(package, data.Count);
			GameReflection.PackageStream(package).Write(data.Array, data.Offset, data.Count);
		}

		private static byte[] DecompressLimited(byte[] data, int maxBytes)
		{
			using MemoryStream stream = new MemoryStream(data);
			using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[81920];
			while (true)
			{
				int num = deflateStream.Read(array, 0, array.Length);
				if (num <= 0)
				{
					break;
				}
				if (memoryStream.Length + num > maxBytes)
				{
					throw new InvalidDataException($"Decompressed package exceeds limit {maxBytes}");
				}
				memoryStream.Write(array, 0, num);
			}
			return memoryStream.ToArray();
		}

		private static void EnsurePolicySupportInitialized(bool createIfMissing = false)
		{
			bool flag;
			lock (policyLock)
			{
				flag = !policySupportInitialized || syncPolicyWatcher == null || hiddenConfigsWatcher == null;
				policySupportInitialized = true;
			}
			LoadPolicyFiles(createIfMissing, quiet: true, "server startup");
			if (flag)
			{
				StartPolicyWatchers();
			}
		}

		private static void StartPolicyWatchers()
		{
			try
			{
				EnsureConfigDirectory();
				if (syncPolicyWatcher == null)
				{
					syncPolicyWatcher = CreatePolicyWatcher("ConditionalConfigSync.SyncPolicy.cfg");
				}
				if (hiddenConfigsWatcher == null)
				{
					hiddenConfigsWatcher = CreatePolicyWatcher("ConditionalConfigSync.HiddenConfigs.cfg");
				}
			}
			catch (Exception ex)
			{
				LogSource.LogWarning((object)("[Policy] Could not start policy watchers: " + ex.Message));
			}
		}

		private static FileSystemWatcher CreatePolicyWatcher(string fileName)
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(ConfigDirectoryPath, fileName)
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
				EnableRaisingEvents = true
			};
			fileSystemWatcher.Changed += delegate
			{
				SchedulePolicyReload();
			};
			fileSystemWatcher.Created += delegate
			{
				SchedulePolicyReload();
			};
			fileSystemWatcher.Renamed += delegate
			{
				SchedulePolicyReload();
			};
			fileSystemWatcher.Deleted += delegate
			{
				SchedulePolicyReload();
			};
			return fileSystemWatcher;
		}

		private static void SchedulePolicyReload()
		{
			long generation;
			lock (policyLock)
			{
				if (policyReloadScheduled)
				{
					return;
				}
				policyReloadScheduled = true;
				generation = ++policyReadGeneration;
			}
			ThreadPool.QueueUserWorkItem(delegate
			{
				Thread.Sleep(500);
				if (!TryReadPolicyFiles(createIfMissing: false, out Dictionary<string, ConfigPolicyOverride> newSyncPolicy, out HashSet<string> newHiddenPolicy, out List<SyncPolicyRecord> syncRecords, out List<HiddenPolicyRecord> hiddenRecords, out string error))
				{
					lock (policyLock)
					{
						policyReloadScheduled = false;
					}
					LogSource.LogWarning((object)("[Policy] Failed to read policy files: " + error));
				}
				else
				{
					lock (policyLock)
					{
						policyReloadScheduled = false;
					}
					EnqueueMainThread(delegate
					{
						ApplyPolicyFiles(newSyncPolicy, newHiddenPolicy, syncRecords, hiddenRecords, quiet: false, "policy file watcher", generation);
					});
				}
			});
		}

		private static bool LoadPolicyFiles(bool createIfMissing, bool quiet, string source)
		{
			if (!TryReadPolicyFiles(createIfMissing, out Dictionary<string, ConfigPolicyOverride> newSyncPolicy, out HashSet<string> newHiddenPolicy, out List<SyncPolicyRecord> syncRecords, out List<HiddenPolicyRecord> hiddenRecords, out string error))
			{
				LogSource.LogWarning((object)("[Policy] Failed to read policy files: " + error));
				return false;
			}
			long generation = Interlocked.Increment(ref policyReadGeneration);
			if (IsMainThread)
			{
				ApplyPolicyFiles(newSyncPolicy, newHiddenPolicy, syncRecords, hiddenRecords, quiet, source, generation);
			}
			else
			{
				EnqueueMainThread(delegate
				{
					ApplyPolicyFiles(newSyncPolicy, newHiddenPolicy, syncRecords, hiddenRecords, quiet, source, generation);
				});
			}
			return true;
		}

		private static bool TryReadPolicyFiles(bool createIfMissing, out Dictionary<string, ConfigPolicyOverride> newSyncPolicy, out HashSet<string> newHiddenPolicy, out List<SyncPolicyRecord> syncRecords, out List<HiddenPolicyRecord> hiddenRecords, out string? error)
		{
			newSyncPolicy = new Dictionary<string, ConfigPolicyOverride>(StringComparer.OrdinalIgnoreCase);
			newHiddenPolicy = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			syncRecords = new List<SyncPolicyRecord>();
			hiddenRecords = new List<HiddenPolicyRecord>();
			error = null;
			try
			{
				EnsureConfigDirectory();
				if (createIfMissing)
				{
					EnsurePolicyFilesExist();
				}
				newSyncPolicy = ReadSyncPolicyFile(SyncPolicyPath, out syncRecords);
				newHiddenPolicy = ReadHiddenConfigsFile(HiddenConfigsPath, out hiddenRecords);
				return true;
			}
			catch (Exception ex)
			{
				error = ex.Message;
				return false;
			}
		}

		private static void ApplyPolicyFiles(Dictionary<string, ConfigPolicyOverride> newSyncPolicy, HashSet<string> newHiddenPolicy, List<SyncPolicyRecord> syncRecords, List<HiddenPolicyRecord> hiddenRecords, bool quiet, string source, long generation)
		{
			lock (policyLock)
			{
				if (generation < policyAppliedGeneration)
				{
					return;
				}
				policyAppliedGeneration = generation;
				syncPolicy = newSyncPolicy;
				hiddenConfigPolicy = newHiddenPolicy;
			}
			LogPolicyFileRecords(syncRecords, hiddenRecords, source);
			if (!quiet)
			{
				int num = newSyncPolicy.Count<KeyValuePair<string, ConfigPolicyOverride>>((KeyValuePair<string, ConfigPolicyOverride> kv) => kv.Value == ConfigPolicyOverride.ForceServerControlled);
				int num2 = newSyncPolicy.Count<KeyValuePair<string, ConfigPolicyOverride>>((KeyValuePair<string, ConfigPolicyOverride> kv) => kv.Value == ConfigPolicyOverride.ForceClientControlled);
				LogSource.LogInfo((object)$"[Policy] Reloaded: forceServer={num}, forceClient={num2}, hidden={newHiddenPolicy.Count}, source={source}");
			}
			RefreshPolicyStatesForAll(source, !quiet);
		}

		private static void EnsurePolicyFilesExist()
		{
			if (!File.Exists(SyncPolicyPath))
			{
				File.WriteAllText(SyncPolicyPath, "# ConditionalConfigSync sync policy. Server-side only.\n# Exact setting: + ModGuid.Section.Key or - ModGuid.Section.Key\n# Whole section: + ModGuid.Section or - ModGuid.Section\n# + forces server-controlled; - forces client-controlled.\n# Exact-setting rules take precedence over section rules.\n# Rules apply only to configs registered as Conditional.\n");
			}
			if (!File.Exists(HiddenConfigsPath))
			{
				File.WriteAllText(HiddenConfigsPath, "# ConditionalConfigSync hidden config policy. Server-side only.\n# Exact setting: ModGuid.Section.Key\n# Whole section: ModGuid.Section\n# Exact and section entries may be combined.\n");
			}
		}

		private static Dictionary<string, ConfigPolicyOverride> ReadSyncPolicyFile(string path, out List<SyncPolicyRecord> records)
		{
			Dictionary<string, ConfigPolicyOverride> dictionary = new Dictionary<string, ConfigPolicyOverride>(StringComparer.OrdinalIgnoreCase);
			records = new List<SyncPolicyRecord>();
			string[] array = ReadAllLinesStable(path, missingIsEmpty: true);
			foreach (string line in array)
			{
				string text = StripPolicyComment(line).Trim();
				if (text.Length == 0)
				{
					continue;
				}
				char c = text[0];
				if (c != '+' && c != '-')
				{
					records.Add(new SyncPolicyRecord(text, null, ConfigPolicyOverride.Default, "expected '+' or '-'"));
					continue;
				}
				string text2 = text.Substring(1).Trim();
				if (text2.Length == 0)
				{
					records.Add(new SyncPolicyRecord(text, null, ConfigPolicyOverride.Default, "config record is empty"));
					continue;
				}
				ConfigPolicyOverride configPolicyOverride = ((c == '+') ? ConfigPolicyOverride.ForceServerControlled : ConfigPolicyOverride.ForceClientControlled);
				records.Add(new SyncPolicyRecord(text2, text2, configPolicyOverride, null));
				dictionary[text2] = configPolicyOverride;
			}
			return dictionary;
		}

		private static HashSet<string> ReadHiddenConfigsFile(string path, out List<HiddenPolicyRecord> records)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			records = new List<HiddenPolicyRecord>();
			string[] array = ReadAllLinesStable(path, missingIsEmpty: true);
			foreach (string line in array)
			{
				string text = StripPolicyComment(line).Trim();
				if (text.Length != 0)
				{
					records.Add(new HiddenPolicyRecord(text, text, null));
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		private static string StripPolicyComment(string line)
		{
			int num = line.IndexOf('#');
			int num2 = line.IndexOf(';');
			int num3 = ((num < 0) ? num2 : ((num2 < 0) ? num : Math.Min(num, num2)));
			return (num3 < 0) ? line : line.Substring(0, num3);
		}

		private static void RefreshPolicyStatesForAll(string source, bool broadcast)
		{
			foreach (ConditionalConfigSync configSync in configSyncs)
			{
				configSync.RefreshPolicyStates(source, broadcast);
			}
		}

		private void RefreshPolicyStates(string source, bool broadcast)
		{
			if (!IsSourceOfTruth)
			{
				return;
			}
			List<OwnConfigEntryBase> list = new List<OwnConfigEntryBase>();
			List<PolicyStateChangedEventArgs> list2 = new List<PolicyStateChangedEventArgs>();
			foreach (OwnConfigEntryBase allConfig in allConfigs)
			{
				bool flag = !allConfig.PolicyStateInitialized;
				bool flag2 = (flag ? GetDefaultServerControlled(allConfig) : allConfig.IsServerControlled);
				bool flag3 = !flag && allConfig.IsHidden;
				bool isServerControlled = allConfig.IsServerControlled;
				bool isHidden = allConfig.IsHidden;
				bool flag4 = ComputeServerControlled(allConfig);
				bool flag5 = ComputeHidden(allConfig);
				allConfig.IsServerControlled = flag4;
				allConfig.IsHidden = flag5;
				allConfig.PolicyStateInitialized = true;
				bool flag6 = isServerControlled != flag4 || isHidden != flag5;
				bool flag7 = flag2 != flag4 || flag3 != flag5;
				if (flag6 || flag7)
				{
					list.Add(allConfig);
					if (flag7)
					{
						list2.Add(new PolicyStateChangedEventArgs(allConfig, flag2, flag4, flag3, flag5, source));
					}
				}
			}
			if (list.Count > 0)
			{
				ServerLockedSettingChanged();
			}
			foreach (PolicyStateChangedEventArgs item in list2)
			{
				RaisePolicyStateEvents(item);
			}
			if (broadcast && isServer && GameReflection.HasZNet && list.Count > 0)
			{
				StartBroadcastPackage(GameReflection.Everybody, ConfigsToPackage(list.Select((OwnConfigEntryBase c) => c.BaseConfig), null, null, partial: true, includeConfigValues: true, includeAllProvidedConfigStates: true));
			}
		}

		private static void LogPolicyFileRecords(IReadOnlyList<SyncPolicyRecord> syncRecords, IReadOnlyList<HiddenPolicyRecord> hiddenRecords, string source)
		{
			LogSyncPolicyRecords(syncRecords, source);
			LogHiddenPolicyRecords(hiddenRecords, source);
		}

		private static void LogSyncPolicyRecords(IReadOnlyList<SyncPolicyRecord> records, string source)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < records.Count; i++)
			{
				if (records[i].Key != null)
				{
					dictionary[records[i].Key] = i;
				}
			}
			for (int j = 0; j < records.Count; j++)
			{
				SyncPolicyRecord record = records[j];
				string policySourceSuffix = GetPolicySourceSuffix(source);
				if (record.Error != null || record.Key == null)
				{
					LogSource.LogWarning((object)("[SyncPolicy] " + record.DisplayText + ": " + record.Error + policySourceSuffix));
					continue;
				}
				PolicyTargetResolution policyTargetResolution = ResolvePolicyTarget(record.Key);
				if (LogPolicyTargetFailure(policyTargetResolution, record.DisplayText, "SyncPolicy", policySourceSuffix))
				{
					continue;
				}
				ConditionalConfigSync configSync = policyTargetResolution.ConfigSync;
				string text = "[SyncPolicy][" + configSync.GetDebugModName() + "]";
				string policyOverrideName = GetPolicyOverrideName(record.PolicyOverride);
				if (dictionary[record.Key] != j)
				{
					LogSource.LogWarning((object)(text + " " + record.DisplayText + ": overridden by a later rule" + policySourceSuffix));
					continue;
				}
				string matchedKey;
				List<OwnConfigEntryBase> list = policyTargetResolution.Configs.Where((OwnConfigEntryBase config) => configSync.GetPolicyOverride(config, out matchedKey) != ConfigPolicyOverride.Default && string.Equals(matchedKey, record.Key, StringComparison.OrdinalIgnoreCase)).ToList();
				if (list.Count == 0)
				{
					LogSource.LogInfo((object)(text + " " + record.DisplayText + ": " + policyOverrideName + " has no effect on mod behavior" + policySourceSuffix));
					continue;
				}
				List<OwnConfigEntryBase> list2 = list.Where((OwnConfigEntryBase config) => config.SyncMode == ConfigSyncMode.Conditional).ToList();
				if (list2.Count == 0)
				{
					ConfigSyncMode[] array = list.Select((OwnConfigEntryBase config) => config.SyncMode).Distinct().ToArray();
					string text2 = ((array.Length == 1) ? $"ignored because its mode is {array[0]}" : "ignored because matching configs are not Conditional");
					LogSource.LogInfo((object)(text + " " + record.DisplayText + ": " + text2 + policySourceSuffix));
					continue;
				}
				bool targetServerControlled = record.PolicyOverride == ConfigPolicyOverride.ForceServerControlled;
				if (list2.Any((OwnConfigEntryBase config) => config.SynchronizedConfig != targetServerControlled))
				{
					LogSource.LogWarning((object)(text + " " + record.DisplayText + ": " + policyOverrideName + " changes mod behavior" + policySourceSuffix));
				}
				else
				{
					LogSource.LogInfo((object)(text + " " + record.DisplayText + ": " + policyOverrideName + " has no effect on mod behavior" + policySourceSuffix));
				}
			}
		}

		private static void LogHiddenPolicyRecords(IReadOnlyList<HiddenPolicyRecord> records, string source)
		{
			foreach (HiddenPolicyRecord record in records)
			{
				string policySourceSuffix = GetPolicySourceSuffix(source);
				if (record.Error != null || record.Key == null)
				{
					LogSource.LogWarning((object)("[HiddenConfigs] " + record.DisplayText + ": " + record.Error + policySourceSuffix));
					continue;
				}
				PolicyTargetResolution policyTargetResolution = ResolvePolicyTarget(record.Key);
				if (!LogPolicyTargetFailure(policyTargetResolution, record.DisplayText, "HiddenConfigs", policySourceSuffix))
				{
					ConditionalConfigSync configSync = policyTargetResolution.ConfigSync;
					LogSource.LogWarning((object)("[HiddenConfigs][" + configSync.GetDebugModName() + "] " + record.DisplayText + ": is now hidden in configuration manager" + policySourceSuffix));
				}
			}
		}

		private static bool LogPolicyTargetFailure(PolicyTargetResolution resolution, string displayText, string area, string sourceSuffix)
		{
			if (resolution.Failure == PolicyTargetFailure.None)
			{
				return false;
			}
			if (resolution.Failure == PolicyTargetFailure.Mod)
			{
				LogSource.LogWarning((object)("[" + area + "] " + displayText + ": can not find mod by GUID" + sourceSuffix));
				return true;
			}
			string debugModName = resolution.ConfigSync.GetDebugModName();
			string text = ((resolution.Failure == PolicyTargetFailure.Section) ? "can not find config section" : "can not find config name");
			LogSource.LogWarning((object)("[" + area + "][" + debugModName + "] " + displayText + ": " + text + sourceSuffix));
			return true;
		}

		private static PolicyTargetResolution ResolvePolicyTarget(string key)
		{
			PolicyTargetResolution policyTargetResolution = new PolicyTargetResolution();
			ConditionalConfigSync configSync = (from sync in configSyncs
				where key.StartsWith(sync.Name + ".", StringComparison.OrdinalIgnoreCase)
				orderby sync.Name.Length descending
				select sync).FirstOrDefault();
			if (configSync == null)
			{
				policyTargetResolution.Failure = PolicyTargetFailure.Mod;
				return policyTargetResolution;
			}
			policyTargetResolution.ConfigSync = configSync;
			OwnConfigEntryBase ownConfigEntryBase = configSync.allConfigs.FirstOrDefault((OwnConfigEntryBase config) => string.Equals(configSync.GetPolicyKey(config), key, StringComparison.OrdinalIgnoreCase));
			if (ownConfigEntryBase != null)
			{
				policyTargetResolution.Configs.Add(ownConfigEntryBase);
				return policyTargetResolution;
			}
			List<OwnConfigEntryBase> list = configSync.allConfigs.Where((OwnConfigEntryBase config) => string.Equals(configSync.GetPolicySectionKey(config), key, StringComparison.OrdinalIgnoreCase)).ToList();
			if (list.Count > 0)
			{
				policyTargetResolution.Configs.AddRange(list);
				return policyTargetResolution;
			}
			string remainder = key.Substring(configSync.Name.Length + 1);
			bool flag = configSync.allConfigs.Select((OwnConfigEntryBase config) => config.BaseConfig.Definition.Section).Distinct<string>(StringComparer.OrdinalIgnoreCase).Any((string section) => remainder.StartsWith(section + ".", StringComparison.OrdinalIgnoreCase));
			policyTargetResolution.Failure = (flag ? PolicyTargetFailure.Config : PolicyTargetFailure.Section);
			return policyTargetResolution;
		}

		private static string GetPolicyOverrideName(ConfigPolicyOverride policyOverride)
		{
			return (policyOverride == ConfigPolicyOverride.ForceServerControlled) ? "ForceServerControlled" : "ForceClientControlled";
		}

		private static string GetPolicySourceSuffix(string source)
		{
			return (IsDebugActive && EffectiveDebugLevel >= ConditionalConfigSyncDebugLevel.Verbose) ? (", source=" + source) : "";
		}

		private static List<string> ValidatePolicyFiles(out int syncRuleCount, out int hiddenRuleCount)
		{
			List<string> list = new List<string>();
			Dictionary<string, ConfigPolicyOverride> dictionary = new Dictionary<string, ConfigPolicyOverride>(StringComparer.OrdinalIgnoreCase);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			EnsureConfigDirectory();
			ValidateSyncPolicyFile(dictionary, list);
			ValidateHiddenPolicyFile(hashSet, list);
			syncRuleCount = dictionary.Count;
			hiddenRuleCount = hashSet.Count;
			HashSet<string> hashSet2 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (ConditionalConfigSync configSync in configSyncs)
			{
				foreach (OwnConfigEntryBase allConfig in configSync.allConfigs)
				{
					hashSet2.Add(configSync.GetPolicyKey(allConfig));
					hashSet2.Add(configSync.GetPolicySectionKey(allConfig));
				}
			}
			foreach (string item in dictionary.Keys.Concat(hashSet).Distinct<string>(StringComparer.OrdinalIgnoreCase))
			{
				if (!hashSet2.Contains(item))
				{
					list.Add("Unknown identifier: " + item);
				}
			}
			foreach (ConditionalConfigSync configSync2 in configSyncs)
			{
				foreach (OwnConfigEntryBase allConfig2 in configSync2.allConfigs)
				{
					string matchedKey;
					ConfigPolicyOverride configPolicyOverride = ResolvePolicyOverride(dictionary, configSync2.GetPolicyKey(allConfig2), configSync2.GetPolicySectionKey(allConfig2), out matchedKey);
					if (configPolicyOverride != ConfigPolicyOverride.Default)
					{
						if (allConfig2 == configSync2.lockedConfig && configPolicyOverride == ConfigPolicyOverride.ForceClientControlled)
						{
							list.Add("ForceClientControlled is ignored for protected locking config " + configSync2.GetPolicyKey(allConfig2) + " (matched rule: " + matchedKey + ").");
						}
						else if (allConfig2.SyncMode != ConfigSyncMode.Conditional)
						{
							list.Add($"Rule {matchedKey} is ignored for {configSync2.GetPolicyKey(allConfig2)} because its mode is {allConfig2.SyncMode}.");
						}
					}
				}
			}
			return list;
		}

		private static void ValidateSyncPolicyFile(Dictionary<string, ConfigPolicyOverride> result, List<string> diagnostics)
		{
			if (!File.Exists(SyncPolicyPath))
			{
				diagnostics.Add("File does not exist: " + SyncPolicyPath);
				return;
			}
			string[] array = ReadAllLinesStable(SyncPolicyPath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				string text2 = StripPolicyComment(text).Trim();
				if (text2.Length == 0)
				{
					continue;
				}
				char c = text2[0];
				if (c != '+' && c != '-')
				{
					diagnostics.Add(string.Format("{0}:{1}: expected '+' or '-': {2}", "ConditionalConfigSync.SyncPolicy.cfg", i + 1, text));
					continue;
				}
				string text3 = text2.Substring(1).Trim();
				if (text3.Length == 0)
				{
					diagnostics.Add(string.Format("{0}:{1}: identifier is empty.", "ConditionalConfigSync.SyncPolicy.cfg", i + 1));
					continue;
				}
				ConfigPolicyOverride configPolicyOverride = ((c == '+') ? ConfigPolicyOverride.ForceServerControlled : ConfigPolicyOverride.ForceClientControlled);
				if (result.TryGetValue(text3, out var value))
				{
					diagnostics.Add((value == configPolicyOverride) ? string.Format("{0}:{1}: duplicate rule: {2}", "ConditionalConfigSync.SyncPolicy.cfg", i + 1, text3) : string.Format("{0}:{1}: conflicting rule overrides an earlier entry: {2}", "ConditionalConfigSync.SyncPolicy.cfg", i + 1, text3));
				}
				result[text3] = configPolicyOverride;
			}
		}

		private static void ValidateHiddenPolicyFile(HashSet<string> result, List<string> diagnostics)
		{
			if (!File.Exists(HiddenConfigsPath))
			{
				diagnostics.Add("File does not exist: " + HiddenConfigsPath);
				return;
			}
			string[] array = ReadAllLinesStable(HiddenConfigsPath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = StripPolicyComment(array[i]).Trim();
				if (text.Length != 0 && !result.Add(text))
				{
					diagnostics.Add(string.Format("{0}:{1}: duplicate rule: {2}", "ConditionalConfigSync.HiddenConfigs.cfg", i + 1, text));
				}
			}
		}

		private static ConfigPolicyOverride ResolvePolicyOverride(IReadOnlyDictionary<string, ConfigPolicyOverride> policy, string exactKey, string sectionKey, out string? matchedKey)
		{
			if (policy.TryGetValue(exactKey, out var value))
			{
				matchedKey = exactKey;
				return value;
			}
			if (policy.TryGetValue(sectionKey, out var value2))
			{
				matchedKey = sectionKey;
				return value2;
			}
			matchedKey = null;
			return ConfigPolicyOverride.Default;
		}

		private static string WritePolicyDumpFile()
		{
			EnsureConfigDirectory();
			string text = Path.Combine(ConfigDirectoryPath, "ConditionalConfigSync.PolicyDump.txt");
			List<string> list = new List<string> { "# ConditionalConfigSync policy identifiers", "# Copy an identifier into SyncPolicy.cfg and prefix it with '+' or '-'.", "# Copy an identifier into HiddenConfigs.cfg without a prefix.", "# To target a whole section, copy the section identifier shown after '# Section:'.", "" };
			foreach (ConditionalConfigSync item in configSyncs.OrderBy<ConditionalConfigSync, string>((ConditionalConfigSync sync) => sync.Name, StringComparer.OrdinalIgnoreCase))
			{
				string text2 = null;
				foreach (OwnConfigEntryBase item2 in item.allConfigs.OrderBy<OwnConfigEntryBase, string>((OwnConfigEntryBase entry) => entry.BaseConfig.Definition.Section, StringComparer.OrdinalIgnoreCase).ThenBy<OwnConfigEntryBase, string>((OwnConfigEntryBase entry) => entry.BaseConfig.Definition.Key, StringComparer.OrdinalIgnoreCase))
				{
					string policySectionKey = item.GetPolicySectionKey(item2);
					if (!string.Equals(text2, policySectionKey, StringComparison.OrdinalIgnoreCase))
					{
						if (text2 != null)
						{
							list.Add("");
						}
						list.Add("# Section: " + policySectionKey);
						text2 = policySectionKey;
					}
					list.Add(item.GetPolicyKey(item2));
					list.Add(string.Format("Policy: {0}; Default: {1}", item2.SyncMode, GetDefaultServerControlled(item2) ? "ServerControlled" : "ClientControlled"));
				}
				list.Add("");
			}
			File.WriteAllLines(text, list);
			return text;
		}

		private static object HandlePolicyConsoleCommand(ConsoleEventArgs args)
		{
			string text = GameReflection.ConsoleArg(args, 0).Trim().ToLowerInvariant();
			if (!GameReflection.HasZNet || !GameReflection.IsServer())
			{
				return "This command is available only on the server.";
			}
			switch (text)
			{
			case "conditionalconfigsync_status":
				WritePolicyStatus(args);
				return true;
			case "conditionalconfigsync_policy_reload":
			{
				bool flag = LoadPolicyFiles(createIfMissing: true, quiet: false, "console command");
				AddConsoleLine(args, flag ? "ConditionalConfigSync policy reloaded." : "ConditionalConfigSync policy reload failed. See the server log.");
				return flag;
			}
			case "conditionalconfigsync_policy_validate":
			{
				int syncRuleCount;
				int hiddenRuleCount;
				List<string> list = ValidatePolicyFiles(out syncRuleCount, out hiddenRuleCount);
				AddConsoleLine(args, $"ConditionalConfigSync policy validation: syncR

ConditionalConfigSync.Plugin.dll

Decompiled 19 hours ago
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
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.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[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.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
{
	[BepInPlugin("_shudnal.ConditionalConfigSync", "Conditional Config Sync", "1.0.0")]
	[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.0";

		private const string PluginAssemblyName = "ConditionalConfigSync.Plugin";

		private const string CoreAssemblyName = "ConditionalConfigSync";

		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;
			}
			else
			{
				ConditionalConfigSync.InitializeRuntime();
			}
		}

		private void OnDestroy()
		{
			ConditionalConfigSync.ShutdownRuntime();
		}
	}
}