Decompiled source of GroundReset v2.5.1

GroundReset.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using GroundReset.Compatibility.WardIsLove;
using GroundReset.Compatibility.kgMarketplace;
using GroundReset.DiscordMessenger;
using GroundReset.Patch;
using HarmonyLib;
using JFUtils;
using JFUtils.Valheim.WithPatch;
using JFUtils.WithPatch;
using JFUtils.zdos;
using JetBrains.Annotations;
using Marketplace.Modules.TerritorySystem;
using Microsoft.CodeAnalysis;
using ServerSync;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Guid("AE09A2AD-0D0C-4B4D-B5AE-0C528A2DD21D")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyProduct("GroundReset")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("GroundReset")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: <5306f3ec-fed7-4ac9-a53d-a4e69346e265>RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<d58fc846-f0fe-45b8-b95c-4d688d24fefa>Embedded]
	internal sealed class <d58fc846-f0fe-45b8-b95c-4d688d24fefa>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[<d58fc846-f0fe-45b8-b95c-4d688d24fefa>Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	internal sealed class <5306f3ec-fed7-4ac9-a53d-a4e69346e265>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <5306f3ec-fed7-4ac9-a53d-a4e69346e265>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GroundReset
{
	[Serializable]
	internal class ChunkData
	{
		public bool[] m_modifiedHeight;

		public float[] m_levelDelta;

		public float[] m_smoothDelta;

		public bool[] m_modifiedPaint;

		public Color[] m_paintMask;

		public ChunkData()
		{
			int num = Reseter.HeightmapWidth + 1;
			m_modifiedHeight = new bool[num * num];
			m_levelDelta = new float[m_modifiedHeight.Length];
			m_smoothDelta = new float[m_modifiedHeight.Length];
			m_modifiedPaint = new bool[Reseter.HeightmapWidth * Reseter.HeightmapWidth];
			m_paintMask = (Color[])(object)new Color[m_modifiedPaint.Length];
		}
	}
	public class FunctionTimer
	{
		private class MonoBehaviourHook : MonoBehaviour
		{
			public Action OnUpdate;

			private void Update()
			{
				OnUpdate?.Invoke();
			}
		}

		public class FunctionTimerObject
		{
			private readonly Action callback;

			private float timer;

			public FunctionTimerObject(Action callback, float timer)
			{
				this.callback = callback;
				this.timer = timer;
			}

			public bool Update()
			{
				return Update(Time.deltaTime);
			}

			public bool Update(float deltaTime)
			{
				timer -= deltaTime;
				if (timer <= 0f)
				{
					callback();
					return true;
				}
				return false;
			}
		}

		private static List<FunctionTimer> timerList;

		private static GameObject initGameObject;

		private readonly string functionName = "NoneNameTimer";

		private readonly GameObject gameObject;

		private readonly Action onEndAction;

		private readonly bool useUnscaledDeltaTime;

		public float Timer { get; private set; }

		public FunctionTimer(GameObject gameObject, Action action, float timer, string functionName, bool useUnscaledDeltaTime)
		{
			this.gameObject = gameObject;
			onEndAction = action;
			Timer = timer;
			this.functionName = functionName;
			this.useUnscaledDeltaTime = useUnscaledDeltaTime;
		}

		private static void InitIfNeeded()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if ((Object)(object)initGameObject == (Object)null)
			{
				initGameObject = new GameObject("FunctionTimer_Global");
				timerList = new List<FunctionTimer>();
			}
		}

		public static FunctionTimer Create(Action action, float timer)
		{
			return Create(action, timer, "", useUnscaledDeltaTime: false, stopAllWithSameName: false);
		}

		public static FunctionTimer Create(Action action, float timer, string functionName)
		{
			return Create(action, timer, functionName, useUnscaledDeltaTime: false, stopAllWithSameName: false);
		}

		public static FunctionTimer Create(Action action, float timer, string functionName, bool useUnscaledDeltaTime)
		{
			return Create(action, timer, functionName, useUnscaledDeltaTime, stopAllWithSameName: false);
		}

		public static FunctionTimer Create(Action action, float timer, string functionName, bool useUnscaledDeltaTime, bool stopAllWithSameName)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			if (!ZNet.m_isServer)
			{
				return null;
			}
			InitIfNeeded();
			if (stopAllWithSameName)
			{
				StopAllTimersWithName(functionName);
			}
			GameObject val = new GameObject("FunctionTimer Object " + functionName, new Type[1] { typeof(MonoBehaviourHook) });
			FunctionTimer functionTimer = new FunctionTimer(val, action, timer, functionName, useUnscaledDeltaTime);
			val.GetComponent<MonoBehaviourHook>().OnUpdate = functionTimer.Update;
			timerList.Add(functionTimer);
			Plugin.timer = functionTimer;
			ModBase.Debug($"Timer was successfully created. Interval was set to {timer} seconds.");
			return functionTimer;
		}

		public static void RemoveTimer(FunctionTimer funcTimer)
		{
			InitIfNeeded();
			timerList.Remove(funcTimer);
		}

		public static void StopAllTimersWithName(string functionName)
		{
			if (Plugin.timer != null && Plugin.timer.functionName == functionName)
			{
				Plugin.timer = null;
			}
			InitIfNeeded();
			for (int i = 0; i < timerList.Count; i++)
			{
				if (timerList[i].functionName == functionName)
				{
					timerList[i].DestroySelf();
					i--;
				}
			}
		}

		public static void StopFirstTimerWithName(string functionName)
		{
			InitIfNeeded();
			for (int i = 0; i < timerList.Count; i++)
			{
				if (timerList[i].functionName == functionName)
				{
					timerList[i].DestroySelf();
					break;
				}
			}
		}

		private void Update()
		{
			if (useUnscaledDeltaTime)
			{
				Timer -= Time.unscaledDeltaTime;
			}
			else
			{
				Timer -= Time.deltaTime;
			}
			if (Timer <= 0f)
			{
				onEndAction();
				DestroySelf();
			}
		}

		private void DestroySelf()
		{
			RemoveTimer(this);
			if ((Object)(object)gameObject != (Object)null)
			{
				Object.Destroy((Object)(object)gameObject);
			}
		}

		public static FunctionTimerObject CreateObject(Action callback, float timer)
		{
			return new FunctionTimerObject(callback, timer);
		}
	}
	public class FunctionUpdater
	{
		private class MonoBehaviourHook : MonoBehaviour
		{
			public Action OnUpdate;

			private void Update()
			{
				if (OnUpdate != null)
				{
					OnUpdate();
				}
			}
		}

		private static List<FunctionUpdater> updaterList;

		private static GameObject initGameObject;

		private readonly string functionName;

		private readonly GameObject gameObject;

		private readonly Func<bool> updateFunc;

		private bool active;

		public FunctionUpdater(GameObject gameObject, Func<bool> updateFunc, string functionName, bool active)
		{
			this.gameObject = gameObject;
			this.updateFunc = updateFunc;
			this.functionName = functionName;
			this.active = active;
		}

		private static void InitIfNeeded()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if ((Object)(object)initGameObject == (Object)null)
			{
				initGameObject = new GameObject("FunctionUpdater_Global");
				updaterList = new List<FunctionUpdater>();
			}
		}

		public static FunctionUpdater Create(Action updateFunc)
		{
			return Create(delegate
			{
				updateFunc();
				return false;
			}, "", active: true, stopAllWithSameName: false);
		}

		public static FunctionUpdater Create(Action updateFunc, string functionName)
		{
			return Create(delegate
			{
				updateFunc();
				return false;
			}, functionName, active: true, stopAllWithSameName: false);
		}

		public static FunctionUpdater Create(Func<bool> updateFunc)
		{
			return Create(updateFunc, "", active: true, stopAllWithSameName: false);
		}

		public static FunctionUpdater Create(Func<bool> updateFunc, string functionName)
		{
			return Create(updateFunc, functionName, active: true, stopAllWithSameName: false);
		}

		public static FunctionUpdater Create(Func<bool> updateFunc, string functionName, bool active)
		{
			return Create(updateFunc, functionName, active, stopAllWithSameName: false);
		}

		public static FunctionUpdater Create(Func<bool> updateFunc, string functionName, bool active, bool stopAllWithSameName)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			InitIfNeeded();
			if (stopAllWithSameName)
			{
				StopAllUpdatersWithName(functionName);
			}
			GameObject val = new GameObject("FunctionUpdater Object " + functionName, new Type[1] { typeof(MonoBehaviourHook) });
			FunctionUpdater functionUpdater = new FunctionUpdater(val, updateFunc, functionName, active);
			val.GetComponent<MonoBehaviourHook>().OnUpdate = functionUpdater.Update;
			updaterList.Add(functionUpdater);
			return functionUpdater;
		}

		private static void RemoveUpdater(FunctionUpdater funcUpdater)
		{
			InitIfNeeded();
			updaterList.Remove(funcUpdater);
		}

		public static void DestroyUpdater(FunctionUpdater funcUpdater)
		{
			InitIfNeeded();
			funcUpdater?.DestroySelf();
		}

		public static void StopUpdaterWithName(string functionName)
		{
			InitIfNeeded();
			for (int i = 0; i < updaterList.Count; i++)
			{
				if (updaterList[i].functionName == functionName)
				{
					updaterList[i].DestroySelf();
					break;
				}
			}
		}

		public static void StopAllUpdatersWithName(string functionName)
		{
			InitIfNeeded();
			for (int i = 0; i < updaterList.Count; i++)
			{
				if (updaterList[i].functionName == functionName)
				{
					updaterList[i].DestroySelf();
					i--;
				}
			}
		}

		public void Pause()
		{
			active = false;
		}

		public void Resume()
		{
			active = true;
		}

		private void Update()
		{
			if (active && updateFunc())
			{
				DestroySelf();
			}
		}

		public void DestroySelf()
		{
			RemoveUpdater(this);
			if ((Object)(object)gameObject != (Object)null)
			{
				Object.Destroy((Object)(object)gameObject);
			}
		}
	}
	[BepInPlugin("com.Frogger.GroundReset", "GroundReset", "2.5.1")]
	public class Plugin : BaseUnityPlugin
	{
		private const string ModName = "GroundReset";

		private const string ModAuthor = "Frogger";

		private const string ModVersion = "2.5.1";

		private const string ModGUID = "com.Frogger.GroundReset";

		internal static Action onTimer;

		internal static FunctionTimer timer;

		internal static string vanillaPresetsMsg;

		internal static ConfigEntry<float> timeInMinutesConfig;

		internal static ConfigEntry<float> timePassedInMinutesConfig;

		internal static ConfigEntry<float> savedTimeUpdateIntervalConfig;

		internal static ConfigEntry<float> dividerConfig;

		internal static ConfigEntry<float> minHeightToSteppedResetConfig;

		internal static ConfigEntry<float> paintsCompairToleranceConfig;

		internal static ConfigEntry<string> paintsToIgnoreConfig;

		internal static ConfigEntry<bool> resetSmoothingConfig;

		internal static ConfigEntry<bool> resetSmoothingLastConfig;

		internal static ConfigEntry<bool> resetPaintLastConfig;

		internal static ConfigEntry<bool> debugConfig;

		internal static ConfigEntry<bool> debugTestConfig;

		internal static float timeInMinutes = -1f;

		internal static float paintsCompairTolerance = 0.3f;

		internal static float timePassedInMinutes;

		internal static float savedTimeUpdateInterval;

		internal static bool debug;

		internal static bool debug_test;

		internal static bool resetPaintLast = false;

		internal static List<Color> paintsToIgnore = new List<Color>();

		private Dictionary<string, Color> vanillaPresets;

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			vanillaPresets = new Dictionary<string, Color>();
			vanillaPresets.Add("Dirt", Heightmap.m_paintMaskDirt);
			vanillaPresets.Add("Cultivated", Heightmap.m_paintMaskCultivated);
			vanillaPresets.Add("Paved", Heightmap.m_paintMaskPaved);
			vanillaPresets.Add("Nothing", Heightmap.m_paintMaskNothing);
			vanillaPresetsMsg = "Vanilla presets: " + vanillaPresets.Keys.GetString();
			ModBase.CreateMod((BaseUnityPlugin)(object)this, "GroundReset", "Frogger", "2.5.1", "com.Frogger.GroundReset");
			ModBase.OnConfigurationChanged = (Action)Delegate.Combine(ModBase.OnConfigurationChanged, new Action(UpdateConfiguration));
			timeInMinutesConfig = ModBase.config("General", "TheTriggerTime", 4320f, "Time in real minutes between reset steps.");
			dividerConfig = ModBase.config("General", "Divider", 1.7f, "The divider for the terrain restoration. Current value will be divided by this value. Learn more on mod page.");
			minHeightToSteppedResetConfig = ModBase.config("General", "Min Height To Stepped Reset", 0.2f, "If the height delta is lower than this value, it will be counted as zero.");
			savedTimeUpdateIntervalConfig = ModBase.config("General", "SavedTime Update Interval (seconds)", 120f, "How often elapsed time will be saved to config file.");
			timePassedInMinutesConfig = ModBase.config("DO NOT TOUCH", "time has passed since the last trigger", 0f, new ConfigDescription("DO NOT TOUCH this", (AcceptableValueBase)null, new object[1]
			{
				new JFUtils.ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			paintsToIgnoreConfig = ModBase.config("General", "Paint To Ignore", "(Paved), (Cultivated)", "This paints will be ignored in the reset process.\n" + vanillaPresetsMsg);
			paintsCompairToleranceConfig = ModBase.config("General", "Paints Compair Tolerance", 0.3f, "The accuracy of the comparison of colors. Since the current values of the same paint may differ from the reference in different situations, they have to be compared with the difference in this value.");
			resetSmoothingConfig = ModBase.config("General", "Reset Smoothing", value: true, "Should the terrain smoothing be reset");
			resetPaintLastConfig = ModBase.config("General", "Process Paint Lastly", value: true, "Set to true so that the paint is reset only after the ground height delta and smoothing is completely reset. Otherwise, the paint will be reset at each reset step along with the height delta.");
			resetSmoothingLastConfig = ModBase.config("General", "Process Smoothing After Height", value: true, "Set to true so that the smoothing is reset only after the ground height delta is completely reset. Otherwise, the smoothing will be reset at each reset step along with the height delta.");
			debugConfig = ModBase.config("Debug", "Do some test debugs", value: false, "");
			debugTestConfig = ModBase.config("Debug", "Do some dev goofy debugs", value: false, "");
			onTimer = (Action)Delegate.Combine(onTimer, (Action)delegate
			{
				ModBase.Debug("Timer Triggered, Resetting...");
				Reseter.ResetAll();
				InitTimer();
			});
		}

		private void UpdateConfiguration()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (Math.Abs(timeInMinutes - timeInMinutesConfig.Value) > 1f)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).name == "main")
				{
					InitTimer();
				}
			}
			debug = debugConfig.Value;
			debug_test = debugTestConfig.Value;
			timeInMinutes = timeInMinutesConfig.Value;
			timePassedInMinutes = timePassedInMinutesConfig.Value;
			savedTimeUpdateInterval = savedTimeUpdateIntervalConfig.Value;
			paintsCompairTolerance = paintsCompairToleranceConfig.Value;
			resetPaintLast = resetPaintLastConfig.Value;
			TryParsePaints(paintsToIgnoreConfig.Value);
			InitWardsSettings.RegisterWards();
			if (debug)
			{
				ModBase.DebugWarning("paintsToIgnore = " + paintsToIgnore.GetString());
			}
			ModBase.Debug("Configuration Received");
		}

		private void TryParsePaints(string str)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			paintsToIgnore.Clear();
			string[] array = str.Split(new string[1] { "), (" }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.Trim('(', ')');
				if (vanillaPresets.TryGetValue(text2.Replace(" ", ""), out var value))
				{
					paintsToIgnore.Add(value);
					continue;
				}
				string[] array3 = text2.Split(new string[1] { ", " }, StringSplitOptions.RemoveEmptyEntries);
				if (array3.Length != 4)
				{
					ModBase.DebugError("Could not parse color: '" + array3.GetString() + "', expected format: (r, b, g, alpha)\n" + vanillaPresetsMsg);
					continue;
				}
				string text3 = array3[0];
				string text4 = array3[1];
				string text5 = array3[2];
				string text6 = array3[3];
				if (!float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					ModBase.DebugError("Could not parse a value: '" + text3 + "'");
					continue;
				}
				if (!float.TryParse(text4, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					ModBase.DebugError("Could not parse b value: '" + text4 + "'");
					continue;
				}
				if (!float.TryParse(text5, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
				{
					ModBase.DebugError("Could not parse g value: '" + text5 + "'");
					continue;
				}
				if (!float.TryParse(text6, NumberStyles.Float, CultureInfo.InvariantCulture, out var result4))
				{
					ModBase.DebugError("Could not parse alpha value: '" + text6 + "'");
					continue;
				}
				((Color)(ref value))..ctor(result, result2, result3, result4);
				paintsToIgnore.Add(value);
			}
		}

		private static void InitTimer()
		{
			FunctionTimer.StopAllTimersWithName("JF_GroundReset");
			FunctionTimer.Create(onTimer, timeInMinutesConfig.Value * 60f, "JF_GroundReset", useUnscaledDeltaTime: true, stopAllWithSameName: true);
		}
	}
	public static class Reseter
	{
		public const string terrCompPrefabName = "_TerrainCompiler";

		private static readonly int RadiusNetKey = StringExtensionMethods.GetStableHashCode("wardRadius");

		internal static readonly int HeightmapWidth = 64;

		internal static readonly int HeightmapScale = 1;

		private static List<ZDO> wards = new List<ZDO>();

		public static List<WardSettings> wardsSettingsList = new List<WardSettings>();

		public static Stopwatch watch = new Stopwatch();

		internal static async void ResetAll(bool checkIfNeed = true, bool checkWards = true, bool ranFromConsole = false)
		{
			await FindWards();
			await Terrains.ResetTerrains(checkWards);
			if (ranFromConsole)
			{
				((Terminal)Console.instance).AddString("<color=green> Done </color>");
			}
			wards.Clear();
		}

		private static async Task FindWards()
		{
			watch.Restart();
			wards.Clear();
			for (int i = 0; i < wardsSettingsList.Count; i++)
			{
				wards = Enumerable.Concat(second: await ZoneSystemExtension.GetWorldObjectsAsync(prefabName: wardsSettingsList[i].prefabName, zoneSystem: ZoneSystem.instance, customFilters: Array.Empty<Func<ZDO, bool>>()), first: wards).ToList();
			}
			ModBase.DebugWarning(string.Format(arg1: TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds).TotalSeconds, format: "Wards count: {0}. Took {1} seconds", arg0: wards.Count));
			watch.Restart();
		}

		public static Vector3 HmapToWorld(Vector3 heightmapPos, int x, int y)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			float num = ((float)x - (float)(HeightmapWidth / 2)) * (float)HeightmapScale;
			float num2 = ((float)y - (float)(HeightmapWidth / 2)) * (float)HeightmapScale;
			return heightmapPos + new Vector3(num, 0f, num2);
		}

		public static void WorldToVertex(Vector3 worldPos, Vector3 heightmapPos, out int x, out int y)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = worldPos - heightmapPos;
			x = Mathf.FloorToInt((float)((double)val.x / (double)HeightmapScale + 0.5)) + HeightmapWidth / 2;
			y = Mathf.FloorToInt((float)((double)val.z / (double)HeightmapScale + 0.5)) + HeightmapWidth / 2;
		}

		public static IEnumerator SaveTime()
		{
			yield return (object)new WaitForSeconds(Plugin.savedTimeUpdateInterval);
			Plugin.timePassedInMinutesConfig.Value = Plugin.timer.Timer / 60f;
			((MonoBehaviour)ZNetScene.instance).StartCoroutine(SaveTime());
		}

		public static bool IsInWard(Vector3 pos, float checkRadius = 0f)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			return wards.Exists(delegate(ZDO searchWard)
			{
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				WardSettings wardSettings = wardsSettingsList.Find((WardSettings s) => StringExtensionMethods.GetStableHashCode(s.prefabName) == searchWard.GetPrefab());
				if (!searchWard.GetBool(ZDOVars.s_enabled, false))
				{
					return false;
				}
				float num = (wardSettings.dynamicRadius ? wardSettings.getDynamicRadius(searchWard) : wardSettings.radius);
				return pos.DistanceXZ(searchWard.GetPosition()) <= num + checkRadius;
			}) || MarketplaceTerritorySystem.PointInTerritory(pos);
		}

		public static bool IsInWard(Vector3 zoneCenter, int w, int h)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return IsInWard(HmapToWorld(zoneCenter, w, h));
		}
	}
	public static class Terrains
	{
		public static async Task<int> ResetTerrains(bool checkWards)
		{
			Reseter.watch.Restart();
			List<ZDO> zdos = await ZoneSystem.instance.GetWorldObjectsAsync("_TerrainCompiler");
			ModBase.Debug($"Found {zdos.Count} chunks to reset");
			int resets = 0;
			foreach (ZDO zdo in zdos)
			{
				ResetTerrainComp(zdo, checkWards);
				resets++;
			}
			ModBase.Debug(string.Format(arg1: TimeSpan.FromMilliseconds(Reseter.watch.ElapsedMilliseconds).TotalSeconds, format: "{0} chunks have been reset. Took {1} seconds", arg0: resets));
			Reseter.watch.Restart();
			return resets;
		}

		private static void ResetTerrainComp(ZDO zdo, bool checkWards)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.dividerConfig.Value;
			bool value2 = Plugin.resetSmoothingConfig.Value;
			bool value3 = Plugin.resetSmoothingConfig.Value;
			float value4 = Plugin.minHeightToSteppedResetConfig.Value;
			Vector3 zonePos = ZoneSystem.instance.GetZonePos(ZoneSystem.instance.GetZone(zdo.GetPosition()));
			ChunkData chunkData = LoadOldData(zdo);
			int num = Reseter.HeightmapWidth + 1;
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					int num2 = i * num + j;
					if (!chunkData.m_modifiedHeight[num2] || (checkWards && Reseter.IsInWard(zonePos, j, i)))
					{
						continue;
					}
					chunkData.m_levelDelta[num2] /= value;
					if (Mathf.Abs(chunkData.m_levelDelta[num2]) < value4)
					{
						chunkData.m_levelDelta[num2] = 0f;
					}
					if (value2 && (!value3 || chunkData.m_levelDelta[num2] == 0f))
					{
						chunkData.m_smoothDelta[num2] /= value;
						if (Mathf.Abs(chunkData.m_smoothDelta[num2]) < value4)
						{
							chunkData.m_smoothDelta[num2] = 0f;
						}
					}
					bool flag = value2 && chunkData.m_smoothDelta[num2] != 0f;
					chunkData.m_modifiedHeight[num2] = chunkData.m_levelDelta[num2] != 0f || flag;
				}
			}
			num = Reseter.HeightmapWidth;
			int num3 = chunkData.m_modifiedPaint.Length - 1;
			for (int k = 0; k < num; k++)
			{
				for (int l = 0; l < num; l++)
				{
					int num4 = k * num + l;
					if (num4 > num3 || !chunkData.m_modifiedPaint[num4])
					{
						continue;
					}
					if (checkWards || Plugin.resetPaintLast)
					{
						Vector3 val = Reseter.HmapToWorld(zonePos, l, k);
						if (checkWards && Reseter.IsInWard(val))
						{
							continue;
						}
						if (Plugin.resetPaintLast)
						{
							Reseter.WorldToVertex(val, zonePos, out var x, out var y);
							int num5 = y * (Reseter.HeightmapWidth + 1) + x;
							if (chunkData.m_modifiedHeight.Length > num5 && chunkData.m_modifiedHeight[num5])
							{
								continue;
							}
						}
					}
					Color val2 = chunkData.m_paintMask[num4];
					if (Plugin.debug_test)
					{
						ModBase.Debug($"currentPaint = {val2}");
					}
					if (!IsPaintIgnored(val2))
					{
						chunkData.m_modifiedPaint[num4] = false;
						chunkData.m_paintMask[num4] = Color.clear;
					}
				}
			}
			SaveData(zdo, chunkData);
			ClutterSystem instance = ClutterSystem.instance;
			if (instance != null)
			{
				instance.ResetGrass(zonePos, (float)(Reseter.HeightmapWidth * Reseter.HeightmapScale / 2));
			}
			foreach (TerrainComp s_instance in TerrainComp.s_instances)
			{
				Heightmap hmap = s_instance.m_hmap;
				if (hmap != null)
				{
					hmap.Poke(false);
				}
			}
		}

		private static bool IsPaintIgnored(Color color)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return Plugin.paintsToIgnore.Exists((Color x) => Mathf.Abs(x.r - color.r) < Plugin.paintsCompairTolerance && Mathf.Abs(x.b - color.b) < Plugin.paintsCompairTolerance && Mathf.Abs(x.g - color.g) < Plugin.paintsCompairTolerance && Mathf.Abs(x.a - color.a) < Plugin.paintsCompairTolerance);
		}

		private static void SaveData(ZDO zdo, ChunkData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(0);
			val.Write(Vector3.zero);
			val.Write(0);
			val.Write(data.m_modifiedHeight.Length);
			for (int i = 0; i < data.m_modifiedHeight.Length; i++)
			{
				val.Write(data.m_modifiedHeight[i]);
				if (data.m_modifiedHeight[i])
				{
					val.Write(data.m_levelDelta[i]);
					val.Write(data.m_smoothDelta[i]);
				}
			}
			val.Write(data.m_modifiedPaint.Length);
			for (int j = 0; j < data.m_modifiedPaint.Length; j++)
			{
				val.Write(data.m_modifiedPaint[j]);
				if (data.m_modifiedPaint[j])
				{
					val.Write(data.m_paintMask[j].r);
					val.Write(data.m_paintMask[j].g);
					val.Write(data.m_paintMask[j].b);
					val.Write(data.m_paintMask[j].a);
				}
			}
			byte[] array = Utils.Compress(val.GetArray());
			zdo.Set(ZDOVars.s_TCData, array);
		}

		private static ChunkData LoadOldData(ZDO zdo)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			ChunkData chunkData = new ChunkData();
			int num = Reseter.HeightmapWidth + 1;
			byte[] byteArray = zdo.GetByteArray(ZDOVars.s_TCData, (byte[])null);
			ZPackage val = new ZPackage(Utils.Decompress(byteArray));
			val.ReadInt();
			val.ReadInt();
			val.ReadVector3();
			val.ReadSingle();
			int num2 = val.ReadInt();
			if (num2 != chunkData.m_modifiedHeight.Length)
			{
				ModBase.DebugWarning("Terrain data load error, height array missmatch");
			}
			for (int i = 0; i < num2; i++)
			{
				chunkData.m_modifiedHeight[i] = val.ReadBool();
				if (chunkData.m_modifiedHeight[i])
				{
					chunkData.m_levelDelta[i] = val.ReadSingle();
					chunkData.m_smoothDelta[i] = val.ReadSingle();
				}
				else
				{
					chunkData.m_levelDelta[i] = 0f;
					chunkData.m_smoothDelta[i] = 0f;
				}
			}
			int num3 = val.ReadInt();
			for (int j = 0; j < num3; j++)
			{
				chunkData.m_modifiedPaint[j] = val.ReadBool();
				if (chunkData.m_modifiedPaint[j])
				{
					chunkData.m_paintMask[j] = new Color
					{
						r = val.ReadSingle(),
						g = val.ReadSingle(),
						b = val.ReadSingle(),
						a = val.ReadSingle()
					};
				}
				else
				{
					chunkData.m_paintMask[j] = Color.black;
				}
			}
			return chunkData;
		}
	}
	public struct WardSettings
	{
		public string prefabName;

		public float radius;

		public bool dynamicRadius;

		public Func<ZDO, float> getDynamicRadius;

		public WardSettings(string prefabName, float radius)
		{
			getDynamicRadius = null;
			dynamicRadius = false;
			this.prefabName = prefabName;
			this.radius = radius;
		}

		public WardSettings(string prefabName, Func<ZDO, float> getDynamicRadius)
			: this(prefabName, 0f)
		{
			dynamicRadius = true;
			this.getDynamicRadius = getDynamicRadius;
		}
	}
}
namespace GroundReset.Patch
{
	[HarmonyPatch]
	internal class InitWardsSettings
	{
		[HarmonyWrapSafe]
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		internal static void Init(ZNetScene __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (!(((Scene)(ref activeScene)).name != "main") && ZNet.instance.IsServer())
			{
				RegisterWards();
			}
		}

		internal static void RegisterWards()
		{
			Reseter.wardsSettingsList.Clear();
			AddWard("guard_stone");
			AddWardThorward();
		}

		private static void AddWard(string name)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(StringExtensionMethods.GetStableHashCode(name));
			if (Object.op_Implicit((Object)(object)prefab))
			{
				PrivateArea component = prefab.GetComponent<PrivateArea>();
				Reseter.wardsSettingsList.Add(new WardSettings(name, component.m_radius));
			}
		}

		private static void AddWardThorward()
		{
			string text = "Thorward";
			GameObject prefab = ZNetScene.instance.GetPrefab(StringExtensionMethods.GetStableHashCode(text));
			if (Object.op_Implicit((Object)(object)prefab))
			{
				Reseter.wardsSettingsList.Add(new WardSettings(text, delegate(ZDO zdo)
				{
					float @float = zdo.GetFloat(AzuWardZdoKeys.wardRadius, 0f);
					return (@float == 0f) ? WardIsLovePlugin.WardRange().Value : @float;
				}));
			}
		}
	}
	[HarmonyPatch]
	public static class SendStartMessage
	{
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Game), "Start")]
		private static void Postfix(Game __instance)
		{
			Discord.SendStartMessage();
		}
	}
	[HarmonyPatch]
	internal class StartTimer
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		private static void ZNetSceneAwake_StartTimer(ZNetScene __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (!(((Scene)(ref activeScene)).name != "main") && ZNet.instance.IsServer())
			{
				float num = ((!(Plugin.timePassedInMinutes > 0f)) ? Plugin.timeInMinutes : Plugin.timePassedInMinutes);
				num *= 60f;
				FunctionTimer.Create(Plugin.onTimer, num, "JF_GroundReset", useUnscaledDeltaTime: true, stopAllWithSameName: true);
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private static void ZNet_SaveTime(ZNet __instance)
		{
			if (ZNet.instance.IsServer())
			{
				((MonoBehaviour)__instance).StartCoroutine(Reseter.SaveTime());
			}
		}
	}
}
namespace GroundReset.DiscordMessenger
{
	[Serializable]
	[HarmonyPatch]
	public class Author
	{
		[YamlMember(Alias = "name")]
		public string Name { get; set; }

		[YamlMember(Alias = "url")]
		public string Url { get; set; }

		[YamlMember(Alias = "icon_url", ApplyNamingConventions = false)]
		public string Icon { get; set; }

		[YamlMember(Alias = "proxy_icon_url", ApplyNamingConventions = false)]
		public string ProxyIcon { get; set; }
	}
	public static class Discord
	{
		[Description("Please don't be stupid.")]
		private const string startMsgWebhook = "https://discord.com/api/webhooks/1192166295450435626/H-obVjQBxvxUH3JikxTBSuHZ7Ekd0FFqAOUlFwLr9veC5ciOlSwwzxhG6spbjeQpp41J";

		private static bool startMessageSent;

		public static void SendStartMessage()
		{
			if (startMessageSent)
			{
				return;
			}
			startMessageSent = true;
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Mod version - " + ModBase.ModVersion);
				stringBuilder.AppendLine("Server name is " + (ZNet.m_ServerName.IsGood() ? ZNet.m_ServerName : "UNKNOWN"));
				stringBuilder.AppendLine($"Date - {DateTime.Now}");
				stringBuilder.AppendLine("----------------");
				new DiscordMessage().SetUsername("Mod Started").SetContent(stringBuilder.ToString()).SetAvatar("https://gcdn.thunderstore.io/live/repository/icons/Frogger-" + ModBase.ModName + "-" + ModBase.ModVersion + ".png.128x128_q95.png")
					.SendMessageAsync("https://discord.com/api/webhooks/1192166295450435626/H-obVjQBxvxUH3JikxTBSuHZ7Ekd0FFqAOUlFwLr9veC5ciOlSwwzxhG6spbjeQpp41J");
			}
			catch (Exception ex)
			{
				ModBase.DebugWarning("Can not send startup msg to discord because of error: " + ex.Message);
			}
		}
	}
	[Serializable]
	[HarmonyPatch]
	public class DiscordMessage
	{
		[YamlMember(Alias = "username")]
		public string Username { get; set; }

		[YamlMember(Alias = "avatar_url", ApplyNamingConventions = false)]
		public string AvatarUrl { get; set; }

		[YamlMember(Alias = "content")]
		public string Content { get; set; }

		[YamlMember(Alias = "tts")]
		public bool TTS { get; set; }

		[YamlMember(Alias = "embeds")]
		public List<Embed> Embeds { get; set; } = new List<Embed>();


		public DiscordMessage SetUsername(string username)
		{
			Username = username;
			return this;
		}

		public DiscordMessage SetAvatar(string avatar)
		{
			AvatarUrl = avatar;
			return this;
		}

		public DiscordMessage SetContent(string content)
		{
			Content = content;
			return this;
		}

		public DiscordMessage SetTTS(bool tts)
		{
			TTS = tts;
			return this;
		}

		public Embed AddEmbed()
		{
			Embed embed = new Embed(this);
			Embeds.Add(embed);
			return embed;
		}

		public void SendMessage(string url)
		{
			WebClient webClient = new WebClient();
			webClient.Headers.Add(HttpRequestHeader.ContentType, "application/json");
			ISerializer serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
			string s = serializer.Serialize(this);
			StringReader input = new StringReader(s);
			IDeserializer deserializer = new DeserializerBuilder().Build();
			object obj = deserializer.Deserialize(input);
			ISerializer serializer2 = new SerializerBuilder().JsonCompatible().Build();
			if (obj != null)
			{
				string graph = serializer2.Serialize(obj);
				webClient.UploadString(url, serializer2.Serialize(graph));
				return;
			}
			throw new Exception("Failed to serialize yaml object");
		}

		public void SendMessageAsync(string url)
		{
			ISerializer serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
			string s = serializer.Serialize(this);
			StringReader input = new StringReader(s);
			IDeserializer deserializer = new DeserializerBuilder().Build();
			object obj = deserializer.Deserialize(input);
			ISerializer serializer2 = new SerializerBuilder().JsonCompatible().Build();
			if (obj != null)
			{
				string content = serializer2.Serialize(obj);
				PostToDiscord(content, url);
			}
			else
			{
				ModBase.DebugError("Failed to serialize yaml object");
			}
		}

		public static void PostToDiscord(string content, string url)
		{
			if (content == "" || url == "")
			{
				return;
			}
			WebRequest discordAPI = WebRequest.Create(url);
			discordAPI.Method = "POST";
			discordAPI.ContentType = "application/json";
			discordAPI.GetRequestStreamAsync().ContinueWith(delegate(Task<Stream> t)
			{
				using StreamWriter streamWriter = new StreamWriter(t.Result);
				streamWriter.WriteAsync(content).ContinueWith((Task _) => discordAPI.GetResponseAsync());
			});
		}
	}
	[Serializable]
	[HarmonyPatch]
	public class Embed
	{
		[YamlMember(Alias = "title")]
		public string Title { get; set; } = null;


		[YamlMember(Alias = "description")]
		public string Description { get; set; } = null;


		[YamlMember(Alias = "url")]
		public string Url { get; set; } = null;


		[YamlMember(Alias = "timestamp")]
		public string Timestamp { get; set; } = null;


		[YamlMember(Alias = "color")]
		public int Color { get; set; }

		[YamlMember(Alias = "footer")]
		public Footer Footer { get; set; } = null;


		[YamlMember(Alias = "image")]
		public Image Image { get; set; } = null;


		[YamlMember(Alias = "thumbnail")]
		public Thumbnail Thumbnail { get; set; } = null;


		[YamlMember(Alias = "video")]
		public Video Video { get; set; } = null;


		[YamlMember(Alias = "provider")]
		public Provider Provider { get; set; } = null;


		[YamlMember(Alias = "author")]
		public Author Author { get; set; } = null;


		[YamlMember(Alias = "fields")]
		public List<Field> Fields { get; set; } = new List<Field>();


		[YamlIgnore]
		private DiscordMessage MessageInstance { get; set; } = null;


		public Embed()
		{
		}

		public Embed(DiscordMessage messageInstance)
		{
			MessageInstance = messageInstance;
		}

		public Embed SetTitle(string title)
		{
			Title = title;
			return this;
		}

		public Embed SetDescription(string description)
		{
			Description = description;
			return this;
		}

		public Embed SetUrl(string url)
		{
			Url = url;
			return this;
		}

		public Embed SetTimestamp(DateTime time)
		{
			Timestamp = time.ToString("yyyy-MM-ddTHH:mm:ssZ");
			return this;
		}

		public Embed SetColor(int color)
		{
			Color = color;
			return this;
		}

		public Embed SetFooter(string text, string icon = null, string proxyIcon = null)
		{
			Footer = new Footer
			{
				Text = text,
				Icon = icon,
				ProxyIcon = proxyIcon
			};
			return this;
		}

		public Embed SetImage(string url, string height = null, string width = null, string proxyIcon = null)
		{
			Image = new Image
			{
				Url = url,
				Height = height,
				Width = width,
				ProxyIcon = proxyIcon
			};
			return this;
		}

		public Embed SetThumbnail(string url, string height = null, string width = null, string proxyIcon = null)
		{
			Thumbnail = new Thumbnail
			{
				Url = url,
				Height = height,
				Width = width,
				ProxyIcon = proxyIcon
			};
			return this;
		}

		public Embed SetVideo(string url, string height = null, string width = null, string proxyVideo = null)
		{
			Video = new Video
			{
				Url = url,
				Height = height,
				Width = width,
				ProxyVideo = proxyVideo
			};
			return this;
		}

		public Embed SetProvider(string name, string url = null)
		{
			Provider = new Provider
			{
				Name = name,
				Url = url
			};
			return this;
		}

		public Embed SetAuthor(string name, string url = null, string icon = null, string proxyIcon = null)
		{
			Author = new Author
			{
				Name = name,
				Icon = icon,
				ProxyIcon = proxyIcon,
				Url = url
			};
			return this;
		}

		public Embed AddField(string key, string value, bool inline = false)
		{
			Fields.Add(new Field
			{
				Key = key,
				Value = value,
				Inline = inline
			});
			return this;
		}

		public DiscordMessage Build()
		{
			return MessageInstance;
		}
	}
	[Serializable]
	[HarmonyPatch]
	public class Field
	{
		[YamlMember(Alias = "name")]
		public string Key { get; set; }

		[YamlMember(Alias = "value")]
		public string Value { get; set; }

		[YamlMember(Alias = "inline")]
		public bool Inline { get; set; }
	}
	[Serializable]
	[HarmonyPatch]
	public class Footer
	{
		[YamlMember(Alias = "text")]
		public string Text { get; set; }

		[YamlMember(Alias = "icon_url", ApplyNamingConventions = false)]
		public string Icon { get; set; }

		[YamlMember(Alias = "proxy_icon_url", ApplyNamingConventions = false)]
		public string ProxyIcon { get; set; }
	}
	[Serializable]
	[HarmonyPatch]
	public class Image
	{
		[YamlMember(Alias = "url")]
		public string Url { get; set; }

		[YamlMember(Alias = "proxy_url", ApplyNamingConventions = false)]
		public string ProxyIcon { get; set; }

		[YamlMember(Alias = "width")]
		public string Width { get; set; }

		[YamlMember(Alias = "height")]
		public string Height { get; set; }
	}
	[Serializable]
	[HarmonyPatch]
	public class Provider
	{
		[YamlMember(Alias = "name")]
		public string Name { get; set; }

		[YamlMember(Alias = "url")]
		public string Url { get; set; }
	}
	[Serializable]
	[HarmonyPatch]
	public class Thumbnail
	{
		[YamlMember(Alias = "url")]
		public string Url { get; set; }

		[YamlMember(Alias = "proxy_url", ApplyNamingConventions = false)]
		public string ProxyIcon { get; set; }

		[YamlMember(Alias = "width")]
		public string Width { get; set; }

		[YamlMember(Alias = "height")]
		public string Height { get; set; }
	}
	[Serializable]
	[HarmonyPatch]
	public class Video
	{
		[YamlMember(Alias = "url")]
		public string Url { get; set; }

		[YamlMember(Alias = "proxy_url", ApplyNamingConventions = false)]
		public string ProxyVideo { get; set; }

		[YamlMember(Alias = "width")]
		public string Width { get; set; }

		[YamlMember(Alias = "height")]
		public string Height { get; set; }
	}
}
namespace GroundReset.Compatibility
{
	public class ModCompat
	{
		public static T InvokeMethod<T>(Type type, object instance, string methodName, object[] parameter)
		{
			return (T)(type.GetMethod(methodName)?.Invoke(instance, parameter));
		}

		public static T GetField<T>(Type type, object instance, string fieldName)
		{
			return (T)(type.GetField(fieldName)?.GetValue(instance));
		}
	}
}
namespace GroundReset.Compatibility.WardIsLove
{
	public class AzuWardZdoKeys
	{
		public static readonly int wardRadius = StringExtensionMethods.GetStableHashCode("wardRadius");

		public static readonly int accessMode = StringExtensionMethods.GetStableHashCode("accessMode");

		public static readonly int bubbleMode = StringExtensionMethods.GetStableHashCode("bubbleMode");

		public static readonly int damageType = StringExtensionMethods.GetStableHashCode("damageType");

		public static readonly int healthRegen = StringExtensionMethods.GetStableHashCode("healthRegen");

		public static readonly int staminaBoost = StringExtensionMethods.GetStableHashCode("staminaBoost");

		public static readonly int bubbleOn = StringExtensionMethods.GetStableHashCode("bubbleOn");

		public static readonly int weatherDmgOn = StringExtensionMethods.GetStableHashCode("weatherDmgOn");

		public static readonly int autoPickupOn = StringExtensionMethods.GetStableHashCode("autoPickupOn");

		public static readonly int autoCloseDoorsOn = StringExtensionMethods.GetStableHashCode("autoCloseDoorsOn");

		public static readonly int fireplaceUnlimOn = StringExtensionMethods.GetStableHashCode("fireplaceUnlimOn");

		public static readonly int bathingUnlimOn = StringExtensionMethods.GetStableHashCode("bathingUnlimOn");

		public static readonly int cookingUnlimOn = StringExtensionMethods.GetStableHashCode("cookingUnlimOn");

		public static readonly int wardFireplaceList = StringExtensionMethods.GetStableHashCode("wardFireplaceList");

		public static readonly int noDeathPenOn = StringExtensionMethods.GetStableHashCode("noDeathPenOn");

		public static readonly int noFoodDrainOn = StringExtensionMethods.GetStableHashCode("noFoodDrainOn");

		public static readonly int pushoutPlayersOn = StringExtensionMethods.GetStableHashCode("pushoutPlayersOn");

		public static readonly int pushoutCreaturesOn = StringExtensionMethods.GetStableHashCode("pushoutCreaturesOn");

		public static readonly int pvpOn = StringExtensionMethods.GetStableHashCode("pvpOn");

		public static readonly int pveOn = StringExtensionMethods.GetStableHashCode("pveOn");

		public static readonly int teleportOn = StringExtensionMethods.GetStableHashCode("teleportOn");

		public static readonly int showFlashOn = StringExtensionMethods.GetStableHashCode("showFlashOn");

		public static readonly int showMarkerOn = StringExtensionMethods.GetStableHashCode("showMarkerOn");

		public static readonly int wardNotificationsOn = StringExtensionMethods.GetStableHashCode("wardNotificationsOn");

		public static readonly int wardNotifyMessageEntry = StringExtensionMethods.GetStableHashCode("wardNotifyMessageEntry");

		public static readonly int wardNotifyMessageExit = StringExtensionMethods.GetStableHashCode("wardNotifyMessageExit");

		public static readonly int wardDamageAmount = StringExtensionMethods.GetStableHashCode("wardDamageAmount");

		public static readonly int itemstandInteractOn = StringExtensionMethods.GetStableHashCode("itemstandInteractOn");

		public static readonly int indestructibleOn = StringExtensionMethods.GetStableHashCode("indestructibleOn");

		public static readonly int indestructList = StringExtensionMethods.GetStableHashCode("indestructList");

		public static readonly int CreatDamageIncreaseAmount = StringExtensionMethods.GetStableHashCode("CreatDamageIncreaseAmount");

		public static readonly int structDamageReducAmount = StringExtensionMethods.GetStableHashCode("structDamageReducAmount");

		public static readonly int itemInteractOn = StringExtensionMethods.GetStableHashCode("itemInteractOn");

		public static readonly int doorInteractOn = StringExtensionMethods.GetStableHashCode("doorInteractOn");

		public static readonly int chestInteractOn = StringExtensionMethods.GetStableHashCode("chestInteractOn");

		public static readonly int portalInteractOn = StringExtensionMethods.GetStableHashCode("portalInteractOn");

		public static readonly int pickableInteractOn = StringExtensionMethods.GetStableHashCode("pickableInteractOn");

		public static readonly int shipInteractOn = StringExtensionMethods.GetStableHashCode("shipInteractOn");

		public static readonly int signInteractOn = StringExtensionMethods.GetStableHashCode("signInteractOn");

		public static readonly int craftingStationInteractOn = StringExtensionMethods.GetStableHashCode("craftingStationInteractOn");

		public static readonly int smelterInteractOn = StringExtensionMethods.GetStableHashCode("smelterInteractOn");

		public static readonly int beehiveInteractOn = StringExtensionMethods.GetStableHashCode("beehiveInteractOn");

		public static readonly int maptableInteractOn = StringExtensionMethods.GetStableHashCode("maptableInteractOn");

		public static readonly int OnlyPermOn = StringExtensionMethods.GetStableHashCode("OnlyPermOn");

		public static readonly int NotPermOn = StringExtensionMethods.GetStableHashCode("NotPermOn");

		public static readonly int ctaMessage = StringExtensionMethods.GetStableHashCode("ctaMessage");

		public static readonly int autoRepairOn = StringExtensionMethods.GetStableHashCode("autoRepairOn");

		public static readonly int autoRepairAmount = StringExtensionMethods.GetStableHashCode("autoRepairAmount");

		public static readonly int autoRepairTime = StringExtensionMethods.GetStableHashCode("autoRepairTime");

		public static readonly int raidProtectionOn = StringExtensionMethods.GetStableHashCode("raidProtectionOn");

		public static readonly int raidablePlayersNeeded = StringExtensionMethods.GetStableHashCode("raidablePlayersNeeded");

		public static readonly int wardIsLoveOn = StringExtensionMethods.GetStableHashCode("wardIsLoveOn");

		public static readonly int WILLimitedWard = StringExtensionMethods.GetStableHashCode("WILLimitedWard");

		public static readonly int WILLimitedWardTime = StringExtensionMethods.GetStableHashCode("WILLimitedWardTime");

		public static readonly int steamID = StringExtensionMethods.GetStableHashCode("steamID");

		public static readonly int steamName = StringExtensionMethods.GetStableHashCode("steamName");

		public static readonly int wardFresh = StringExtensionMethods.GetStableHashCode("wardFresh");

		public static readonly int wardColorCount = StringExtensionMethods.GetStableHashCode("wardColorCount");

		public static readonly int wardAlphaCount = StringExtensionMethods.GetStableHashCode("wardAlphaCount");

		public static readonly int wardModelKey = StringExtensionMethods.GetStableHashCode("wardModelKey");
	}
	public class CustomCheck : ModCompat
	{
		public static Type ClassType()
		{
			return Type.GetType("WardIsLove.Util.CustomCheck, WardIsLove");
		}

		public static bool CheckAccess(long playerID, Vector3 point, float radius = 0f, bool flash = true)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			return ModCompat.InvokeMethod<bool>(ClassType(), null, "CheckAccess", new object[4] { playerID, point, radius, flash });
		}
	}
	public class WardIsLovePlugin : ModCompat
	{
		private const string GUID = "Azumatt.WardIsLove";

		private static readonly System.Version MinVersion = new System.Version(2, 3, 3);

		public static Type ClassType()
		{
			return Type.GetType("WardIsLove.WardIsLovePlugin, WardIsLove");
		}

		public static bool IsLoaded()
		{
			return Chainloader.PluginInfos.ContainsKey("Azumatt.WardIsLove") && Chainloader.PluginInfos["Azumatt.WardIsLove"].Metadata.Version >= MinVersion;
		}

		public static ConfigEntry<bool> WardEnabled()
		{
			return ModCompat.GetField<ConfigEntry<bool>>(ClassType(), null, "WardEnabled");
		}

		public static ConfigEntry<float> WardRange()
		{
			return ModCompat.GetField<ConfigEntry<float>>(ClassType(), null, "WardRange");
		}
	}
	public class WardMonoscript : ModCompat
	{
		public object targetScript;

		public WardMonoscript(object targetScript)
		{
			this.targetScript = targetScript;
		}

		public static Type ClassType()
		{
			return Type.GetType("WardIsLove.Util.WardMonoscript, WardIsLove");
		}

		public static bool CheckInWardMonoscript(Vector3 point, bool flash = false)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return ModCompat.InvokeMethod<bool>(ClassType(), null, "CheckInWardMonoscript", new object[2] { point, flash });
		}

		public static bool CheckAccess(Vector3 point, float radius = 0f, bool flash = true, bool wardCheck = false)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return ModCompat.InvokeMethod<bool>(ClassType(), null, "CheckAccess", new object[4] { point, radius, flash, wardCheck });
		}

		public ZNetView GetZNetView()
		{
			if (targetScript == null)
			{
				return null;
			}
			return ModCompat.GetField<ZNetView>(ClassType(), targetScript, "m_nview");
		}

		public ZDO GetZDO()
		{
			ZNetView zNetView = GetZNetView();
			return ((Object)(object)zNetView != (Object)null && Object.op_Implicit((Object)(object)zNetView) && zNetView.IsValid()) ? zNetView.GetZDO() : null;
		}
	}
	public static class WardMonoscriptExt
	{
		public static Type ClassType()
		{
			return Type.GetType("WardIsLove.Extensions.WardMonoscriptExt, WardIsLove");
		}

		public static WardMonoscript GetWardMonoscript(Vector3 pos)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			object targetScript = ModCompat.InvokeMethod<object>(ClassType(), null, "GetWardMonoscript", new object[1] { pos });
			return new WardMonoscript(targetScript);
		}

		public static float GetWardRadius(this WardMonoscript wrapper)
		{
			return ModCompat.InvokeMethod<float>(ClassType(), null, "GetWardRadius", new object[1] { wrapper.targetScript });
		}

		public static bool GetDoorInteractOn(this WardMonoscript wrapper)
		{
			return ModCompat.InvokeMethod<bool>(ClassType(), null, "GetDoorInteractOn", new object[1] { wrapper.targetScript });
		}
	}
}
namespace GroundReset.Compatibility.kgMarketplace
{
	public class MarketplaceTerritorySystem
	{
		private const string GUID = "MarketplaceAndServerNPCs";

		public static bool IsLoaded()
		{
			return Chainloader.PluginInfos.ContainsKey("MarketplaceAndServerNPCs");
		}

		public static bool PointInTerritory(Vector3 pos)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (!IsLoaded())
			{
				return false;
			}
			return MarketplaceTerritorySystem_RAW.PointInTerritory(pos);
		}
	}
	public static class MarketplaceTerritorySystem_RAW
	{
		public static bool PointInTerritory(Vector3 pos)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			foreach (Territory item in TerritorySystem_DataTypes.SyncedTerritoriesData.Value)
			{
				if (item.IsInside(pos))
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<b2968985-fdc8-4de2-a1db-ada7053a98a8>Embedded]
	internal sealed class <b2968985-fdc8-4de2-a1db-ada7053a98a8>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<b2968985-fdc8-4de2-a1db-ada7053a98a8>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[<b2968985-fdc8-4de2-a1db-ada7053a98a8>Embedded]
	internal sealed class <8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[<b2968985-fdc8-4de2-a1db-ada7053a98a8>Embedded]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ServerSync
{
	[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
	[PublicAPI]
	[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
	internal abstract class OwnConfigEntryBase
	{
		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		public object LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
	[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
	[PublicAPI]
	internal class SyncedConfigEntry<[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)] T> : OwnConfigEntryBase
	{
		public readonly ConfigEntry<T> SourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public SyncedConfigEntry(ConfigEntry<T> sourceConfig)
		{
			SourceConfig = sourceConfig;
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(2)]
	[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
	internal abstract class CustomSyncedValueBase
	{
		public object LocalBaseValue;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(1)]
		public readonly string Identifier;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(1)]
		public readonly Type Type;

		private object boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

		public object BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke();
			}
		}

		public event Action ValueChanged;

		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
	[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
	internal sealed class CustomSyncedValue<[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)] T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
	[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
	internal class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		private static class SnatchCurrentlyHandlingRPC
		{
			[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
			public static ZRpc currentRpc;

			[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
			private static void Postfix(ZNet __instance)
			{
				try
				{
					isServer = __instance.IsServer();
					foreach (ConfigSync configSync2 in configSyncs)
					{
						ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
						if (isServer)
						{
							configSync2.InitialSyncDone = true;
							ModBase.Debug("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections");
						}
					}
					if (isServer)
					{
						((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
					}
				}
				catch (Exception)
				{
				}
				[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
				static IEnumerator WatchAdminListChanges()
				{
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = (from p in ZNet.instance.GetPeers()
								where adminList.Contains(p.m_rpc.GetSocket().GetHostName())
								select p).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		private static class RegisterClientRPCPatch
		{
			[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		private class ParsedConfigs
		{
			[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 1, 1, 2 })]
			public readonly Dictionary<OwnConfigEntryBase, object> configValues = new Dictionary<OwnConfigEntryBase, object>();

			[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 1, 1, 2 })]
			public readonly Dictionary<CustomSyncedValueBase, object> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
		private class SendConfigsAfterLogin
		{
			[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
			private class BufferingSocket : ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

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

				public readonly ISocket Original;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Expected O, but got Unknown
					int pos = pkg.GetPos();
					pkg.SetPos(0);
					int num = pkg.ReadInt();
					if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
					{
						ZPackage val = new ZPackage(pkg.GetArray());
						val.SetPos(pos);
						Package.Add(val);
					}
					else
					{
						pkg.SetPos(pos);
						Original.Send(pkg);
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix([<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 2, 1, 1 })] ref Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				if (__instance.IsServer())
				{
					BufferingSocket value = new BufferingSocket(rpc.GetSocket());
					AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, value);
					object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
					ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (val != null && (int)ZNet.m_onlineBackend > 0)
					{
						AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, value);
					}
					if (__state == null)
					{
						__state = new Dictionary<Assembly, BufferingSocket>();
					}
					__state[Assembly.GetExecutingAssembly()] = value;
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				ZNetPeer peer;
				if (__instance.IsServer())
				{
					object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
					peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						((MonoBehaviour)__instance).StartCoroutine(sendAsync());
					}
				}
				void SendBufferedData()
				{
					if (rpc.GetSocket() is BufferingSocket bufferingSocket)
					{
						AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original);
						object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
						ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
						if (val != null)
						{
							AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original);
						}
					}
					BufferingSocket bufferingSocket2 = __state[Assembly.GetExecutingAssembly()];
					bufferingSocket2.finished = true;
					for (int i = 0; i < bufferingSocket2.Package.Count; i++)
					{
						if (i == bufferingSocket2.versionMatchQueued)
						{
							bufferingSocket2.Original.VersionMatch();
						}
						bufferingSocket2.Original.Send(bufferingSocket2.Package[i]);
					}
					if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
					{
						bufferingSocket2.Original.VersionMatch();
					}
				}
				IEnumerator sendAsync()
				{
					foreach (ConfigSync configSync in configSyncs)
					{
						List<PackageEntry> entries = new List<PackageEntry>();
						if (configSync.CurrentVersion != null)
						{
							entries.Add(new PackageEntry
							{
								section = "Internal",
								key = "serverversion",
								type = typeof(string),
								value = configSync.CurrentVersion
							});
						}
						MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						entries.Add(new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2]
							{
								adminList,
								rpc.GetSocket().GetHostName()
							}))
						});
						ZPackage package = ConfigsToPackage(configSync.allConfigs.Select([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false);
						yield return ((MonoBehaviour)__instance).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package));
					}
					SendBufferedData();
				}
			}
		}

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
		private class PackageEntry
		{
			public string section = null;

			public string key = null;

			public Type type = null;

			[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
			public object value;
		}

		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		[HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")]
		private static class PreventSavingServerInfo
		{
			[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase))
				{
					return true;
				}
				__result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType);
				return false;
			}
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")]
		[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)]
		private static class PreventConfigRereadChangingValues
		{
			[HarmonyPrefix]
			[<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(1)]
			private static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null)
				{
					return true;
				}
				try
				{
					ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType);
				}
				catch (Exception ex)
				{
					ModBase.DebugWarning($"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
				}
				return false;
			}
		}

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)]
		private class InvalidDeserializationTypeException : Exception
		{
			public string expected = null;

			public string received = null;

			public string field = "";
		}

		public static bool ProcessingServerUpdate;

		public readonly string Name;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		public string DisplayName;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		public string CurrentVersion;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		public string MinimumRequiredVersion;

		public bool ModRequired = false;

		private bool? forceConfigLocking;

		private bool isSourceOfTruth = true;

		private static readonly HashSet<ConfigSync> configSyncs;

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

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

		private static bool isServer;

		private static bool lockExempt;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		private OwnConfigEntryBase lockedConfig = null;

		private const byte PARTIAL_CONFIGS = 1;

		private const byte FRAGMENTED_CONFIG = 2;

		private const byte COMPRESSED_CONFIG = 4;

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

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 1, 0, 1 })]
		private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>();

		private static long packageCounter;

		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.GetValueOrDefault();
				}
				if (!num)
				{
					goto IL_0052;
				}
				int result = ((!lockExempt) ? 1 : 0);
				goto IL_0053;
				IL_0053:
				return (byte)result != 0;
				IL_0052:
				result = 0;
				goto IL_0053;
			}
			set
			{
				forceConfigLocking = value;
			}
		}

		public bool IsAdmin => lockExempt || isSourceOfTruth;

		public bool IsSourceOfTruth
		{
			get
			{
				return isSourceOfTruth;
			}
			private set
			{
				if (value != isSourceOfTruth)
				{
					isSourceOfTruth = value;
					this.SourceOfTruthChanged?.Invoke(value);
				}
			}
		}

		public bool InitialSyncDone { get; private set; } = false;


		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		[method: <8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(2)]
		[field: <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		public event Action<bool> SourceOfTruthChanged;

		[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		[method: <8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(2)]
		[field: <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		private event Action lockedConfigChanged;

		static ConfigSync()
		{
			ProcessingServerUpdate = false;
			configSyncs = new HashSet<ConfigSync>();
			lockExempt = false;
			packageCounter = 0L;
			RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle);
		}

		public ConfigSync(string name)
		{
			Name = name;
			configSyncs.Add(this);
			new VersionCheck(this);
		}

		public SyncedConfigEntry<T> AddConfigEntry<[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)] T>(ConfigEntry<T> configEntry)
		{
			OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry);
			SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>;
			if (syncedEntry == null)
			{
				syncedEntry = new SyncedConfigEntry<T>(configEntry);
				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 += [<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (object _, EventArgs _) =>
				{
					if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig)
					{
						Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry);
					}
				};
				allConfigs.Add(syncedEntry);
			}
			return syncedEntry;
		}

		public SyncedConfigEntry<T> AddLockingConfigEntry<[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(0)] T>(ConfigEntry<T> lockingConfig) where T : IConvertible
		{
			if (lockedConfig != null)
			{
				throw new Exception("Cannot initialize locking ConfigEntry twice");
			}
			lockedConfig = AddConfigEntry<T>(lockingConfig);
			lockingConfig.SettingChanged += [<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (object _, EventArgs _) =>
			{
				this.lockedConfigChanged?.Invoke();
			};
			return (SyncedConfigEntry<T>)lockedConfig;
		}

		internal void AddCustomValue(CustomSyncedValueBase customValue)
		{
			if (allCustomValues.Select([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue.Identifier))
			{
				throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)");
			}
			allCustomValues.Add(customValue);
			allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (CustomSyncedValueBase v) => v.Priority));
			customValue.ValueChanged += delegate
			{
				if (!ProcessingServerUpdate)
				{
					Broadcast(ZRoutedRpc.Everybody, customValue);
				}
			};
		}

		private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package)
		{
			lockedConfigChanged += serverLockedSettingChanged;
			IsSourceOfTruth = false;
			if (HandleConfigSyncRPC(0L, package, clientUpdate: false))
			{
				InitialSyncDone = true;
			}
		}

		private void RPC_FromOtherClientConfigSync(long sender, ZPackage package)
		{
			HandleConfigSyncRPC(sender, package, clientUpdate: true);
		}

		private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			try
			{
				if (isServer && IsLocked)
				{
					ZRpc currentRpc = SnatchCurrentlyHandlingRPC.currentRpc;
					object obj;
					if (currentRpc == null)
					{
						obj = null;
					}
					else
					{
						ISocket socket = currentRpc.GetSocket();
						obj = ((socket != null) ? socket.GetHostName() : null);
					}
					string text = (string)obj;
					if (text != null)
					{
						MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text }))))
						{
							return false;
						}
					}
				}
				cacheExpirations.RemoveAll(([<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 0, 1 })] KeyValuePair<long, string> kv) =>
				{
					if (kv.Key < DateTimeOffset.Now.Ticks)
					{
						configValueCache.Remove(kv.Value);
						return true;
					}
					return false;
				});
				byte b = package.ReadByte();
				if ((b & 2u) != 0)
				{
					long num = package.ReadLong();
					string text2 = sender.ToString() + num;
					if (!configValueCache.TryGetValue(text2, out var value))
					{
						value = new SortedDictionary<int, byte[]>();
						configValueCache[text2] = value;
						cacheExpirations.Add(new KeyValuePair<long, string>(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2));
					}
					int key = package.ReadInt();
					int num2 = package.ReadInt();
					value.Add(key, package.ReadByteArray());
					if (value.Count < num2)
					{
						return false;
					}
					configValueCache.Remove(text2);
					package = new ZPackage(value.Values.SelectMany([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (byte[] a) => a).ToArray());
					b = package.ReadByte();
				}
				ProcessingServerUpdate = true;
				if ((b & 4u) != 0)
				{
					byte[] buffer = package.ReadByteArray();
					MemoryStream stream = new MemoryStream(buffer);
					MemoryStream memoryStream = new MemoryStream();
					using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
					{
						deflateStream.CopyTo(memoryStream);
					}
					package = new ZPackage(memoryStream.ToArray());
					b = package.ReadByte();
				}
				if ((b & 1) == 0)
				{
					resetConfigsFromServer();
				}
				ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package);
				foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in parsedConfigs.configValues)
				{
					if (!isServer && configValue.Key.LocalBaseValue == null)
					{
						configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue;
					}
					configValue.Key.BaseConfig.BoxedValue = configValue.Value;
				}
				foreach (KeyValuePair<CustomSyncedValueBase, object> customValue in parsedConfigs.customValues)
				{
					if (!isServer)
					{
						CustomSyncedValueBase key2 = customValue.Key;
						if (key2.LocalBaseValue == null)
						{
							key2.LocalBaseValue = customValue.Key.BoxedValue;
						}
					}
					customValue.Key.BoxedValue = customValue.Value;
				}
				ModBase.Debug(string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name));
				if (!isServer)
				{
					serverLockedSettingChanged();
				}
				return true;
			}
			finally
			{
				ProcessingServerUpdate = false;
			}
		}

		private ParsedConfigs ReadConfigsFromPackage(ZPackage package)
		{
			ParsedConfigs parsedConfigs = new ParsedConfigs();
			Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.Where([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, [<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (OwnConfigEntryBase c) => c);
			Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (CustomSyncedValueBase c) => c.Identifier, [<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (CustomSyncedValueBase c) => c);
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string text = package.ReadString();
				string text2 = package.ReadString();
				string text3 = package.ReadString();
				Type type = Type.GetType(text3);
				if (text3 == "" || type != null)
				{
					object obj;
					try
					{
						obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type));
					}
					catch (InvalidDeserializationTypeException ex)
					{
						ModBase.DebugWarning("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected);
						continue;
					}
					OwnConfigEntryBase value2;
					if (text == "Internal")
					{
						CustomSyncedValueBase value;
						if (text2 == "serverversion")
						{
							if (obj?.ToString() != CurrentVersion)
							{
								ModBase.DebugWarning("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"));
							}
						}
						else if (text2 == "lockexempt")
						{
							if (obj is bool flag)
							{
								lockExempt = flag;
							}
						}
						else if (dictionary2.TryGetValue(text2, out value))
						{
							if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3)
							{
								parsedConfigs.customValues[value] = obj;
								continue;
							}
							ModBase.DebugWarning("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName);
						}
					}
					else if (dictionary.TryGetValue(text + "_" + text2, out value2))
					{
						Type type2 = configType(value2.BaseConfig);
						if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3)
						{
							parsedConfigs.configValues[value2] = obj;
							continue;
						}
						ModBase.DebugWarning("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName);
					}
					else
					{
						ModBase.DebugWarning("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.");
					}
					continue;
				}
				ModBase.DebugWarning("Got invalid type " + text3 + ", abort reading of received configs");
				return new ParsedConfigs();
			}
			return parsedConfigs;
		}

		private static bool isWritableConfig(OwnConfigEntryBase config)
		{
			ConfigSync configSync = configSyncs.FirstOrDefault([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (ConfigSync cs) => cs.allConfigs.Contains(config));
			if (configSync == null)
			{
				return true;
			}
			return configSync.IsSourceOfTruth || !config.SynchronizedConfig || config.LocalBaseValue == null || (!configSync.IsLocked && (config != configSync.lockedConfig || lockExempt));
		}

		private void serverLockedSettingChanged()
		{
			foreach (OwnConfigEntryBase allConfig in allConfigs)
			{
				configAttribute<ConfigurationManagerAttributes>(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig);
			}
		}

		private void resetConfigsFromServer()
		{
			foreach (OwnConfigEntryBase item in allConfigs.Where([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (OwnConfigEntryBase config) => config.LocalBaseValue != null))
			{
				item.BaseConfig.BoxedValue = item.LocalBaseValue;
				item.LocalBaseValue = null;
			}
			foreach (CustomSyncedValueBase item2 in allCustomValues.Where([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (CustomSyncedValueBase config) => config.LocalBaseValue != null))
			{
				item2.BoxedValue = item2.LocalBaseValue;
				item2.LocalBaseValue = null;
			}
			lockedConfigChanged -= serverLockedSettingChanged;
			serverLockedSettingChanged();
		}

		private IEnumerator<bool> distributeConfigToPeers(ZNetPeer peer, ZPackage package)
		{
			ZRoutedRpc rpc = ZRoutedRpc.instance;
			if (rpc == null)
			{
				yield break;
			}
			byte[] data = package.GetArray();
			if (data != null && data.LongLength > 250000)
			{
				int fragments = (int)(1 + (data.LongLength - 1) / 250000);
				long packageIdentifier = ++packageCounter;
				int fragment = 0;
				while (fragment < fragments)
				{
					foreach (bool item in waitForQueue())
					{
						yield return item;
					}
					if (peer.m_socket.IsConnected())
					{
						ZPackage fragmentedPackage = new ZPackage();
						fragmentedPackage.Write((byte)2);
						fragmentedPackage.Write(packageIdentifier);
						fragmentedPackage.Write(fragment);
						fragmentedPackage.Write(fragments);
						fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray());
						SendPackage(fragmentedPackage);
						if (fragment != fragments - 1)
						{
							yield return true;
						}
						int num = fragment + 1;
						fragment = num;
						continue;
					}
					break;
				}
				yield break;
			}
			foreach (bool item2 in waitForQueue())
			{
				yield return item2;
			}
			SendPackage(package);
			void SendPackage(ZPackage pkg)
			{
				string text = Name + " ConfigSync";
				if (isServer)
				{
					peer.m_rpc.Invoke(text, new object[1] { pkg });
				}
				else
				{
					rpc.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, text, new object[1] { pkg });
				}
			}
			IEnumerable<bool> waitForQueue()
			{
				float timeout = Time.time + 30f;
				while (peer.m_socket.GetSendQueueSize() > 20000)
				{
					if (Time.time > timeout)
					{
						ModBase.Debug($"Disconnecting {peer.m_uid} after 30 seconds config sending timeout");
						peer.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 });
						ZNet.instance.Disconnect(peer);
						break;
					}
					yield return false;
				}
			}
		}

		private IEnumerator sendZPackage(long target, ZPackage package)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return Enumerable.Empty<object>().GetEnumerator();
			}
			List<ZNetPeer> list = (List<ZNetPeer>)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance);
			if (target != ZRoutedRpc.Everybody)
			{
				list = list.Where([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (ZNetPeer p) => p.m_uid == target).ToList();
			}
			return sendZPackage(list, package);
		}

		private IEnumerator sendZPackage(List<ZNetPeer> peers, ZPackage package)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				yield break;
			}
			byte[] rawData = package.GetArray();
			if (rawData != null && rawData.LongLength > 10000)
			{
				ZPackage compressedPackage = new ZPackage();
				compressedPackage.Write((byte)4);
				MemoryStream output = new MemoryStream();
				using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal))
				{
					deflateStream.Write(rawData, 0, rawData.Length);
				}
				compressedPackage.Write(output.ToArray());
				package = compressedPackage;
			}
			List<IEnumerator<bool>> writers = (from peer in peers
				where peer.IsReady()
				select peer into p
				select distributeConfigToPeers(p, package)).ToList();
			writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext());
			while (writers.Count > 0)
			{
				yield return null;
				writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext());
			}
		}

		private void Broadcast(long target, params ConfigEntryBase[] configs)
		{
			if (!IsLocked || isServer)
			{
				ZPackage package = ConfigsToPackage(configs);
				ZNet instance = ZNet.instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package));
				}
			}
		}

		private void Broadcast(long target, params CustomSyncedValueBase[] customValues)
		{
			if (!IsLocked || isServer)
			{
				ZPackage package = ConfigsToPackage(null, customValues);
				ZNet instance = ZNet.instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package));
				}
			}
		}

		[return: <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)]
		private static OwnConfigEntryBase configData(ConfigEntryBase config)
		{
			return config.Description.Tags?.OfType<OwnConfigEntryBase>().SingleOrDefault();
		}

		[return: <7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 2, 1 })]
		public static SyncedConfigEntry<T> ConfigData<[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)] T>(ConfigEntry<T> config)
		{
			return ((ConfigEntryBase)config).Description.Tags?.OfType<SyncedConfigEntry<T>>().SingleOrDefault();
		}

		private static T configAttribute<[<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)] T>(ConfigEntryBase config)
		{
			return config.Description.Tags.OfType<T>().First();
		}

		private static Type configType(ConfigEntryBase config)
		{
			return configType(config.SettingType);
		}

		private static Type configType(Type type)
		{
			return type.IsEnum ? Enum.GetUnderlyingType(type) : type;
		}

		private static ZPackage ConfigsToPackage([<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 2, 1 })] IEnumerable<ConfigEntryBase> configs = null, [<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 2, 1 })] IEnumerable<CustomSyncedValueBase> customValues = null, [<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(new byte[] { 2, 1 })] IEnumerable<PackageEntry> packageEntries = null, bool partial = true)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			List<ConfigEntryBase> list = configs?.Where([<8c42ac5e-0e2a-49da-bece-c85523d81536>NullableContext(0)] (ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List<ConfigEntryBase>();
			List<CustomSyncedValueBase> list2 = customValues?.ToList() ?? new List<CustomSyncedValueBase>();
			ZPackage val = new ZPackage();
			val.Write((byte)(partial ? 1 : 0));
			val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0));
			foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>())
			{
				AddEntryToPackage(val, item);
			}
			foreach (CustomSyncedValueBase item2 in list2)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					section = "Internal",
					key = item2.Identifier,
					type = item2.Type,
					value = item2.BoxedValue
				});
			}
			foreach (ConfigEntryBase item3 in list)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					section = item3.Definition.Section,
					key = item3.Definition.Key,
					type = configType(item3),
					value = item3.BoxedValue
				});
			}
			return val;
		}

		private static void AddEntryToPackage(ZPackage package, PackageEntry entry)
		{
			package.Write(entry.section);
			package.Write(entry.key);
			package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type));
			AddValueToZPackage(package, entry.value);
		}

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

		private static void AddValueToZPackage(ZPackage package, [<7a459873-77c8-4cd4-81bd-1e5b9d6bca1c>Nullable(2)] object value)
		{
			Type type = value?.GetType();
			if (value is Enum)
			{
				value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture);
			}
			else
			{
				if (value is ICollection collection)
				{
					package.Write(collection.Count);
					{
						foreach (object item in collection)
						{
							AddValueToZPackage(package, item);
						}
						return;
					}
				}
				if ((object)type != null && type.IsValueType && !type.IsPrimitive)
				{
					FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					package.Write(fields.Length);
					FieldInfo[] array = fields;
					foreach (FieldInfo fieldInfo in array)
					{
						package.Write(GetZPackageTypeString(fieldInfo.FieldType));
						AddValueToZPackage(package, fieldInfo.GetValue(value));
					}
					return;
				}
			}
			ZRpc.Serialize(new object[1] { value }, ref package);
		}

		private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type)
		{
			if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum)
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int num = package.ReadInt();
				if (num != fields.Length)
				{
					throw new InvalidDeserializationTypeException
					{
						received = $"(field count: {num})",
						expected = $"(field count: {fields.Length})"
					};
				}
				object uninitializedObject = FormatterServices.GetUninitializedObject(type);
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					string text = package.ReadString();
					if (text != GetZPackageTypeString(fieldInfo.FieldType))
					{
						throw new InvalidDeserializationTypeException
						{
							received = text,
							expected = GetZPackageTypeString(fieldInfo.FieldType),
							field = fieldInfo.Name
						};
					}
					fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType));
				}
				return uninitializedObject;
			}
			if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				int num2 = package.ReadInt();
				IDictionary dictionary = (IDictionary)Activator.CreateInstance(type);
				Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments);
				FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
				FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic);
				for (int j = 0; j < num2; j++)
				{
					object obj = ReadValueWithTypeFromZPackage(package, type2);
					dictionary.Add(field.GetValue(obj), field2.GetValue(obj));
				}
				return dictionary;
			}
			if (type != typeof(List<string>) && type.IsGenericType)
			{
				Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]);
				if ((object)type3 != null && type3.IsAssignableFrom(type))
				{
					int num3 = package.ReadInt();
					object obj2 = Activator.CreateInstance(type);
					MethodInfo method = type3.GetMethod("Add");
					for (int k = 0; k < num3; k++)
					{
						method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) });
					}
					return obj2;
				}
			}
			ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo));
			AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type);
			List<object> source = new List<object>();
			ZRpc