Decompiled source of Ravenview v1.5.1

plugins/Ravenview.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Rendering;
using UnityEngine.UI;
using Valheim.SettingsGui;
using Valheim.UI;
using ValheimOnline.Combat;
using ValheimOnline.Compat;
using ValheimOnline.Guilds;
using ValheimOnline.Social;
using ValheimOnline.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimOnline
{
	public static class ScalePlugin
	{
		public const int VanillaPlayerLimit = 10;

		public const int VanillaSteamSendRate = 153600;

		public const int VanillaZdoQueueLimit = 10240;

		public const float VanillaSyncInterval = 0.05f;

		public const int SteamLobbyHardLimit = 250;

		internal static ConfigEntry<int> MaxPlayers;

		internal static ConfigEntry<int> SteamSendRate;

		internal static ConfigEntry<int> ZdoQueueLimit;

		internal static ConfigEntry<float> SyncInterval;

		internal static ConfigEntry<int> MaxPeersPerFrame;

		internal static ConfigEntry<bool> EnableSendLoopRewrite;

		private static Harmony _harmony;

		internal static ManualLogSource Log => Plugin.Log;

		public static void Init(ConfigFile Config, Harmony harmony)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			_harmony = harmony;
			MaxPlayers = Config.Bind<int>("1. Players", "MaxPlayers", 100, new ConfigDescription("Maximum players allowed on this server. Vanilla is 10.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			SteamSendRate = Config.Bind<int>("2. Bandwidth", "SteamSendRateBytesPerSecond", 1048576, new ConfigDescription("Steam per-connection send rate in bytes/sec (used for both min and max). Vanilla is 153600 (150 KB/s). The server's total upload can reach this x player count, so lower it if your upload bandwidth is limited.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(65536, 16777216), Array.Empty<object>()));
			ZdoQueueLimit = Config.Bind<int>("2. Bandwidth", "ZdoSendQueueLimitBytes", 32768, new ConfigDescription("How many bytes of world updates may be queued per player before the server waits. Vanilla is 10240. Higher = fewer delayed updates in busy areas.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10240, 1048576), Array.Empty<object>()));
			SyncInterval = Config.Bind<float>("3. Sync loop", "SyncIntervalSeconds", 0.05f, new ConfigDescription("Target time for one full world-update pass over all players. Vanilla is 0.05.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 1f), Array.Empty<object>()));
			MaxPeersPerFrame = Config.Bind<int>("3. Sync loop", "MaxPeersPerFrame", 0, new ConfigDescription("Cap on how many players get world updates in a single frame. 0 = automatic (spread all players evenly across SyncIntervalSeconds).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
			EnableSendLoopRewrite = Config.Bind<bool>("3. Sync loop", "EnableSendLoopRewrite", true, "Replace vanilla's one-player-per-frame update loop. Vanilla only updates ONE player per frame, so with 100 players each one waits ~2 seconds between updates. Requires restart.");
			Apply(typeof(PlayerCapPatch));
			Apply(typeof(SteamLobbySizePatch));
			Apply(typeof(SteamSendRatePatch));
			Apply(typeof(ZdoQueueLimitPatch));
			if (EnableSendLoopRewrite.Value)
			{
				if (SendLoopPatch.Init())
				{
					if (Apply(typeof(SendLoopPatch)))
					{
						Log.LogInfo((object)("Patched ZDOMan.SendZDOToPeers2 send loop (interval " + SyncInterval.Value + " s)."));
					}
				}
				else
				{
					Log.LogError((object)"Send loop rewrite disabled: game internals did not match. Vanilla loop is in use.");
				}
			}
			Log.LogInfo((object)$"Scale: max players {MaxPlayers.Value}, Steam send rate {SteamSendRate.Value} B/s, ZDO queue {ZdoQueueLimit.Value} B.");
		}

		private static bool Apply(Type patchClass)
		{
			try
			{
				_harmony.CreateClassProcessor(patchClass).Patch();
				return true;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to apply " + patchClass.Name + ": " + ex));
				return false;
			}
		}

		public static int GetMaxPlayers()
		{
			return MaxPlayers.Value;
		}

		public static int GetSteamLobbySize()
		{
			return Math.Min(MaxPlayers.Value, 250);
		}

		public static int GetSteamSendRate()
		{
			return SteamSendRate.Value;
		}

		public static int GetZdoQueueLimit()
		{
			return ZdoQueueLimit.Value;
		}

		internal static bool IsLdcI4(CodeInstruction ci, int value)
		{
			if (ci.opcode == OpCodes.Ldc_I4 || ci.opcode == OpCodes.Ldc_I4_S)
			{
				if (ci.operand != null)
				{
					return Convert.ToInt32(ci.operand) == value;
				}
				return false;
			}
			return false;
		}

		internal static bool IsCallTo(CodeInstruction ci, string declaringType, string methodName)
		{
			if (ci.opcode != OpCodes.Call && ci.opcode != OpCodes.Callvirt)
			{
				return false;
			}
			MethodBase methodBase = ci.operand as MethodBase;
			if (methodBase != null && methodBase.Name == methodName && methodBase.DeclaringType != null)
			{
				return methodBase.DeclaringType.Name == declaringType;
			}
			return false;
		}

		internal static void ReplaceWithCall(CodeInstruction ci, string getterName)
		{
			ci.opcode = OpCodes.Call;
			ci.operand = AccessTools.Method(typeof(ScalePlugin), getterName, (Type[])null, (Type[])null);
		}

		internal static void ReportCount(string where, int found, int expected)
		{
			if (found == expected)
			{
				Log.LogInfo((object)("Patched " + where + " (" + found + " site(s))."));
			}
			else
			{
				Log.LogError((object)("Patch mismatch in " + where + ": expected " + expected + " site(s), found " + found + ". The game may have updated; this patch was NOT applied."));
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	internal static class PlayerCapPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<int> list2 = new List<int>();
			for (int i = 0; i + 1 < list.Count; i++)
			{
				if (ScalePlugin.IsCallTo(list[i], "ZNet", "GetNrOfPlayers") && ScalePlugin.IsLdcI4(list[i + 1], 10))
				{
					list2.Add(i + 1);
				}
			}
			ScalePlugin.ReportCount("ZNet.RPC_PeerInfo player cap", list2.Count, 1);
			if (list2.Count == 1)
			{
				ScalePlugin.ReplaceWithCall(list[list2[0]], "GetMaxPlayers");
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(ZSteamMatchmaking), "RegisterServer")]
	internal static class SteamLobbySizePatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<int> list2 = new List<int>();
			for (int i = 0; i + 1 < list.Count; i++)
			{
				if (ScalePlugin.IsLdcI4(list[i], 10) && ScalePlugin.IsCallTo(list[i + 1], "SteamMatchmaking", "CreateLobby"))
				{
					list2.Add(i);
				}
			}
			ScalePlugin.ReportCount("ZSteamMatchmaking.RegisterServer lobby size", list2.Count, 1);
			if (list2.Count == 1)
			{
				ScalePlugin.ReplaceWithCall(list[list2[0]], "GetSteamLobbySize");
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
	internal static class SteamSendRatePatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<int> list2 = new List<int>();
			for (int i = 0; i < list.Count; i++)
			{
				if (ScalePlugin.IsLdcI4(list[i], 153600))
				{
					list2.Add(i);
				}
			}
			ScalePlugin.ReportCount("ZSteamSocket send rate", list2.Count, 1);
			if (list2.Count == 1)
			{
				ScalePlugin.ReplaceWithCall(list[list2[0]], "GetSteamSendRate");
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "SendZDOs")]
	internal static class ZdoQueueLimitPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<int> list2 = new List<int>();
			for (int i = 0; i < list.Count; i++)
			{
				if (ScalePlugin.IsLdcI4(list[i], 10240))
				{
					list2.Add(i);
				}
			}
			ScalePlugin.ReportCount("ZDOMan.SendZDOs queue limit", list2.Count, 2);
			if (list2.Count == 2)
			{
				foreach (int item in list2)
				{
					ScalePlugin.ReplaceWithCall(list[item], "GetZdoQueueLimit");
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")]
	internal static class SendLoopPatch
	{
		private static FieldInfo _peersField;

		private static MethodInfo _sendZdos;

		private static readonly object[] _args = new object[2];

		private static int _cursor = -1;

		private static float _timer;

		private static float _owed;

		internal static bool Init()
		{
			_peersField = AccessTools.Field(typeof(ZDOMan), "m_peers");
			_sendZdos = AccessTools.Method(typeof(ZDOMan), "SendZDOs", (Type[])null, (Type[])null);
			if (_peersField == null || _sendZdos == null)
			{
				return false;
			}
			ParameterInfo[] parameters = _sendZdos.GetParameters();
			if (parameters.Length != 2 || parameters[1].ParameterType != typeof(bool) || _sendZdos.ReturnType != typeof(bool))
			{
				return false;
			}
			if (!typeof(IList).IsAssignableFrom(_peersField.FieldType))
			{
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		private static bool Prefix(ZDOMan __instance, float dt)
		{
			IList list = (IList)_peersField.GetValue(__instance);
			int num = list?.Count ?? 0;
			if (num == 0)
			{
				_cursor = -1;
				return false;
			}
			float value = ScalePlugin.SyncInterval.Value;
			_timer += dt;
			if (_cursor < 0)
			{
				if (_timer < value)
				{
					return false;
				}
				_cursor = 0;
				_timer = 0f;
				_owed = 0f;
			}
			_owed += (float)num * dt / value;
			int num2 = (int)_owed;
			if (num2 < 1)
			{
				num2 = 1;
			}
			_owed -= num2;
			if (_owed < 0f)
			{
				_owed = 0f;
			}
			int value2 = ScalePlugin.MaxPeersPerFrame.Value;
			if (value2 > 0 && num2 > value2)
			{
				num2 = value2;
			}
			try
			{
				int num3 = 0;
				while (num3 < num2 && _cursor < list.Count)
				{
					_args[0] = list[_cursor];
					_args[1] = false;
					_sendZdos.Invoke(__instance, _args);
					num3++;
					_cursor++;
				}
			}
			catch (TargetInvocationException ex)
			{
				_cursor++;
				ScalePlugin.Log.LogError((object)("SendZDOs failed: " + (ex.InnerException ?? ex)));
			}
			if (_cursor >= list.Count)
			{
				_cursor = -1;
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class Tweaks
	{
		public static ConfigEntry<bool> SkipIntro;

		public static ConfigEntry<bool> DevConsole;

		public static ConfigEntry<bool> AnnounceArrival;

		public static void Bind(ConfigFile c)
		{
			SkipIntro = c.Bind<bool>("0. Client", "SkipIntroCinematic", true, "Skip the intro cinematic when the game starts.");
			DevConsole = c.Bind<bool>("0. Client", "EnableDevConsole", false, "Turn on the F5 console for this session (like launching with -console). Takes effect at the next game start.");
			AnnounceArrival = c.Bind<bool>("0. Client", "AnnounceArrival", false, "Shout \"I have arrived!\" in world chat when you load into a world (the game's default).");
		}

		[HarmonyPatch(typeof(Chat), "SendText")]
		[HarmonyPrefix]
		private static bool NoArrival(string __1)
		{
			if (AnnounceArrival == null || AnnounceArrival.Value || string.IsNullOrEmpty(__1) || Localization.instance == null)
			{
				return true;
			}
			return __1 != Localization.instance.Localize("$text_player_arrived");
		}

		[HarmonyPatch(typeof(FejdStartup), "TryPlayIntroCinematic")]
		[HarmonyPrefix]
		private static bool IntroCo(FejdStartup __instance, ref IEnumerator __result)
		{
			if (SkipIntro == null || !SkipIntro.Value)
			{
				return true;
			}
			__result = Skip(__instance);
			return false;
		}

		[HarmonyPatch(typeof(Console), "Awake")]
		[HarmonyPostfix]
		private static void ConsoleOn()
		{
			if (DevConsole == null || !DevConsole.Value)
			{
				return;
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Console), "SetConsoleEnabledForThisSession", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(methodInfo.IsStatic ? null : Console.instance, null);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("EnableDevConsole: " + ex.Message));
			}
		}

		private static IEnumerator Skip(FejdStartup f)
		{
			try
			{
				Animator value = Traverse.Create((object)f).Field("m_menuAnimator").GetValue<Animator>();
				if ((Object)(object)value != (Object)null)
				{
					value.SetTrigger("FadeIn");
				}
				GameObject value2 = Traverse.Create((object)f).Field("m_mainMenu").GetValue<GameObject>();
				if ((Object)(object)value2 != (Object)null && !value2.activeSelf)
				{
					value2.SetActive(true);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("SkipIntro: " + ex.Message));
			}
			yield break;
		}
	}
	[BepInPlugin("com.valheimonline", "Ravenview", "1.5.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.valheimonline";

		public const string Name = "Ravenview";

		public const string Version = "1.5.1";

		public static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Logger.Listeners.Add((ILogListener)(object)new ErrorCounter());
			_harmony = new Harmony("com.valheimonline");
			ScalePlugin.Init(((BaseUnityPlugin)this).Config, _harmony);
			Tweaks.Bind(((BaseUnityPlugin)this).Config);
			try
			{
				_harmony.CreateClassProcessor(typeof(Tweaks)).Patch();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Tweaks failed: " + ex));
			}
			GuildConfig.Bind(((BaseUnityPlugin)this).Config);
			UiConfig.Bind(((BaseUnityPlugin)this).Config);
			PadDebug.Bind(((BaseUnityPlugin)this).Config);
			if (GuildConfig.Enabled)
			{
				int num = 0;
				int num2 = 0;
				foreach (Type item in from t in typeof(Plugin).Assembly.GetTypes()
					where t.Namespace == "ValheimOnline.Guilds" && t.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
					select t)
				{
					try
					{
						_harmony.CreateClassProcessor(item).Patch();
						num++;
					}
					catch (Exception ex2)
					{
						num2++;
						Log.LogError((object)("Guild patch " + item.Name + " failed: " + ex2));
					}
				}
				((Component)this).gameObject.AddComponent<GuildRuntime>();
				ConfigReload.Watch(((BaseUnityPlugin)this).Config);
				Log.LogInfo((object)("Guilds: " + num + " patch group(s) applied" + ((num2 > 0) ? (", " + num2 + " FAILED") : "") + "."));
			}
			else
			{
				Log.LogInfo((object)"Guilds are turned off in the config.");
			}
			((Component)this).gameObject.AddComponent<ProgressionRuntime>();
			foreach (Type item2 in from t in typeof(Plugin).Assembly.GetTypes()
				where t.Namespace == "ValheimOnline.UI" && t.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
				select t)
			{
				try
				{
					_harmony.CreateClassProcessor(item2).Patch();
				}
				catch (Exception ex3)
				{
					Log.LogError((object)("UI patch " + item2.Name + " failed: " + ex3));
				}
			}
			ModCompat.Bind(((BaseUnityPlugin)this).Config);
			foreach (Type item3 in from t in typeof(Plugin).Assembly.GetTypes()
				where t.Namespace == "ValheimOnline.Compat" && t.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
				select t)
			{
				try
				{
					_harmony.CreateClassProcessor(item3).Patch();
				}
				catch (Exception ex4)
				{
					Log.LogError((object)("Mod compat patch " + item3.Name + " failed: " + ex4));
				}
			}
			SocialRuntime.Bind(((BaseUnityPlugin)this).Config);
			((Component)this).gameObject.AddComponent<SocialRuntime>();
			foreach (Type item4 in from t in typeof(Plugin).Assembly.GetTypes()
				where t.Namespace == "ValheimOnline.Social" && t.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
				select t)
			{
				try
				{
					_harmony.CreateClassProcessor(item4).Patch();
				}
				catch (Exception ex5)
				{
					Log.LogError((object)("Social patch " + item4.Name + " failed: " + ex5));
				}
			}
			ValheimOnline.Combat.Combat.Bind(((BaseUnityPlugin)this).Config);
			if (ValheimOnline.Combat.Combat.GcoPresent)
			{
				Log.LogWarning((object)"Combat: Goo's Combat Overhaul is installed, so Ravenview's combat stays off (both change the same things).");
			}
			else
			{
				int num3 = 0;
				int num4 = 0;
				foreach (Type item5 in from t in typeof(Plugin).Assembly.GetTypes()
					where t.Namespace == "ValheimOnline.Combat" && t.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
					select t)
				{
					try
					{
						_harmony.CreateClassProcessor(item5).Patch();
						num3++;
					}
					catch (Exception ex6)
					{
						num4++;
						Log.LogError((object)("Combat patch " + item5.Name + " failed: " + ex6));
					}
				}
				((Component)this).gameObject.AddComponent<CombatRuntime>();
				Log.LogInfo((object)("Combat: " + num3 + " patch group(s) applied" + ((num4 > 0) ? (", " + num4 + " FAILED") : "") + "."));
			}
			Log.LogInfo((object)"Ravenview 1.5.1 loaded.");
		}
	}
}
namespace ValheimOnline.Guilds
{
	public static class Util
	{
		private static string _coinToken;

		private static string CoinToken
		{
			get
			{
				if (_coinToken == null)
				{
					SharedData val = Shared("Coins");
					if (val != null)
					{
						_coinToken = val.m_name;
					}
				}
				return _coinToken;
			}
		}

		public static GameObject ItemPrefab(string prefab)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(prefab))
			{
				return null;
			}
			return ObjectDB.instance.GetItemPrefab(prefab);
		}

		public static SharedData Shared(string prefab)
		{
			GameObject val = ItemPrefab(prefab);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if (!((Object)(object)component != (Object)null))
			{
				return null;
			}
			return component.m_itemData.m_shared;
		}

		public static bool ItemExists(string prefab)
		{
			return Shared(prefab) != null;
		}

		public static int MaxStack(string prefab)
		{
			SharedData val = Shared(prefab);
			if (val == null)
			{
				return 1;
			}
			return Math.Max(1, val.m_maxStackSize);
		}

		public static string ItemDisplayName(string prefab)
		{
			SharedData val = Shared(prefab);
			if (val == null)
			{
				return prefab;
			}
			if (Localization.instance == null)
			{
				return val.m_name;
			}
			return Localization.instance.Localize(val.m_name);
		}

		public static Sprite Icon(string prefab)
		{
			SharedData val = Shared(prefab);
			if (val == null || val.m_icons == null || val.m_icons.Length == 0)
			{
				return null;
			}
			return val.m_icons[0];
		}

		public static Sprite Icon(ItemRecord r)
		{
			SharedData val = Shared(r.Prefab);
			if (val == null || val.m_icons == null || val.m_icons.Length == 0)
			{
				return null;
			}
			return val.m_icons[Mathf.Clamp(r.Variant, 0, val.m_icons.Length - 1)];
		}

		public static string CreatureName(string token)
		{
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}

		public static bool IsGear(string prefab)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected I4, but got Unknown
			SharedData val = Shared(prefab);
			if (val == null)
			{
				return false;
			}
			ItemType itemType = val.m_itemType;
			switch (itemType - 3)
			{
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 6:
			case 8:
			case 9:
			case 11:
			case 12:
			case 14:
			case 15:
			case 16:
			case 17:
			case 19:
			case 20:
			case 21:
				return true;
			default:
				return false;
			}
		}

		public static ItemRecord ToRecord(ItemData item, int amount)
		{
			ItemRecord itemRecord = new ItemRecord
			{
				Prefab = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : ""),
				Stack = amount,
				Quality = item.m_quality,
				Variant = item.m_variant,
				Durability = item.m_durability,
				CrafterId = item.m_crafterID,
				CrafterName = (item.m_crafterName ?? ""),
				WorldLevel = item.m_worldLevel
			};
			if (item.m_customData != null)
			{
				foreach (KeyValuePair<string, string> customDatum in item.m_customData)
				{
					itemRecord.Custom[customDatum.Key] = customDatum.Value;
				}
			}
			return itemRecord;
		}

		public static ItemData FromRecord(ItemRecord r)
		{
			GameObject val = ItemPrefab(r.Prefab);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ItemData obj = val.GetComponent<ItemDrop>().m_itemData.Clone();
			obj.m_dropPrefab = val;
			obj.m_stack = r.Stack;
			obj.m_quality = r.Quality;
			obj.m_variant = r.Variant;
			obj.m_durability = r.Durability;
			obj.m_crafterID = r.CrafterId;
			obj.m_crafterName = r.CrafterName;
			obj.m_worldLevel = r.WorldLevel;
			obj.m_customData = new Dictionary<string, string>(r.Custom);
			obj.m_equipped = false;
			return obj;
		}

		public static ItemRecord TakeItemForVault(ItemData item, int amount)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || item == null)
			{
				return null;
			}
			if (item.m_equipped)
			{
				Notify.Show(MsgKind.Error, "Unequip the item first.");
				return null;
			}
			if ((Object)(object)item.m_dropPrefab == (Object)null)
			{
				Notify.Show(MsgKind.Error, "This item cannot be stored.");
				return null;
			}
			if (GuildClient.Rules.Blocked.Contains(((Object)item.m_dropPrefab).name))
			{
				Notify.Show(MsgKind.Error, "That item cannot be stored in the guild vault.");
				return null;
			}
			amount = Mathf.Clamp(amount, 1, item.m_stack);
			ItemRecord result = ToRecord(item, amount);
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (!inventory.ContainsItem(item))
			{
				return null;
			}
			if (!inventory.RemoveItem(item, amount))
			{
				return null;
			}
			return result;
		}

		public static int CountCoins()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || CoinToken == null)
			{
				return 0;
			}
			return ((Humanoid)localPlayer).GetInventory().CountItems(CoinToken, -1, false);
		}

		public static bool TakeCoins(long amount)
		{
			if (amount <= 0)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || CoinToken == null)
			{
				return false;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (inventory.CountItems(CoinToken, -1, false) < amount)
			{
				return false;
			}
			inventory.RemoveItem(CoinToken, (int)amount, -1, false);
			return true;
		}

		public static void GiveToLocalPlayer(List<ItemRecord> items, long coins)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Received guild items with no local player; " + items.Count + " stacks and " + coins + " coins lost."));
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			bool flag = false;
			foreach (ItemRecord item in items)
			{
				ItemData val = FromRecord(item);
				if (val == null)
				{
					Plugin.Log.LogWarning((object)("Unknown item " + item.Prefab + " from the guild vault."));
				}
				else if (!inventory.AddItem(val))
				{
					Drop(localPlayer, val);
					flag = true;
				}
			}
			if (coins > 0)
			{
				int num = MaxStack("Coins");
				long num2 = coins;
				while (num2 > 0)
				{
					int num3 = (int)Math.Min(num2, num);
					ItemData val2 = FromRecord(new ItemRecord
					{
						Prefab = "Coins",
						Stack = num3
					});
					if (val2 == null)
					{
						break;
					}
					if (!inventory.AddItem(val2))
					{
						Drop(localPlayer, val2);
						flag = true;
					}
					num2 -= num3;
				}
			}
			if (flag)
			{
				Notify.Show(MsgKind.Center, "Your inventory is full; some items were dropped at your feet.");
			}
		}

		private static void Drop(Player p, ItemData it)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)p).transform.position + ((Component)p).transform.forward * 0.8f + Vector3.up;
			ItemDrop.DropItem(it, it.m_stack, val, Quaternion.identity);
		}

		public static bool PeerIsAdmin(ZNetPeer peer)
		{
			try
			{
				return peer != null && peer.m_socket != null && ZNet.instance.IsAdmin(peer.m_socket.GetHostName());
			}
			catch
			{
				return false;
			}
		}

		public static string Ago(long ticks)
		{
			if (ticks <= 0)
			{
				return "never";
			}
			TimeSpan timeSpan = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - ticks);
			if (timeSpan.TotalMinutes < 1.0)
			{
				return "just now";
			}
			if (timeSpan.TotalHours < 1.0)
			{
				return (int)timeSpan.TotalMinutes + " min ago";
			}
			if (timeSpan.TotalDays < 1.0)
			{
				return (int)timeSpan.TotalHours + " h ago";
			}
			return (int)timeSpan.TotalDays + " d ago";
		}

		public static string Hex(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGB(c);
		}

		public static int ColorToRgb(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			return (Mathf.RoundToInt(c.r * 255f) << 16) | (Mathf.RoundToInt(c.g * 255f) << 8) | Mathf.RoundToInt(c.b * 255f);
		}

		public static string Esc(string s)
		{
			return (s ?? "").Replace("<", "").Replace(">", "");
		}
	}
	public static class Notify
	{
		public static void Show(MsgKind kind, string text)
		{
			switch (kind)
			{
			case MsgKind.GuildChat:
			{
				Guild mine = GuildClient.Mine;
				string text2 = ((mine != null) ? mine.ColorHex : "88CCFF");
				ChatLine("<color=#" + text2 + ">[Guild] " + Util.Esc(text) + "</color>");
				break;
			}
			case MsgKind.Notice:
				ChatLine("<color=#C8B78A>[Guild] " + Util.Esc(text) + "</color>");
				Hud((MessageType)1, text);
				break;
			case MsgKind.Motd:
				ChatLine("<color=#E8C95A>[Message of the day] " + Util.Esc(text) + "</color>");
				Hud((MessageType)2, text);
				break;
			case MsgKind.Center:
				ChatLine("<color=#E8C95A>[Guild] " + Util.Esc(text) + "</color>");
				Hud((MessageType)2, text);
				break;
			case MsgKind.Error:
				Hud((MessageType)2, "<color=#FF7060>" + Util.Esc(text) + "</color>");
				GuildWindow.LastError = text;
				break;
			default:
				Hud((MessageType)1, text);
				GuildWindow.LastInfo = text;
				break;
			}
		}

		public static void ChatLine(string rich)
		{
			if ((Object)(object)Chat.instance != (Object)null)
			{
				((Terminal)Chat.instance).AddString(rich);
			}
		}

		private static void Hud(MessageType t, string text)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage(t, text, 0, (Sprite)null, false, true);
			}
		}
	}
	public static class Keys
	{
		public static readonly int Guild = StringExtensionMethods.GetStableHashCode("vo_guild");

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

		public static readonly int Levelled = StringExtensionMethods.GetStableHashCode("vo_lvl");
	}
	public class GuildBanner : MonoBehaviour, Hoverable, Interactable
	{
		private ZNetView _nview;

		private Piece _piece;

		private float _tintTimer;

		private Color _lastTint = Color.clear;

		public GuildSummary Owner
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: 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_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				Vector3 position = ((Component)this).transform.position;
				foreach (GuildSummary value in GuildClient.Summaries.Values)
				{
					if (value.HasBanner)
					{
						Vector2 val = new Vector2(value.BannerPos.x - position.x, value.BannerPos.z - position.z);
						if (((Vector2)(ref val)).sqrMagnitude < 2.5f)
						{
							return value;
						}
					}
				}
				return null;
			}
		}

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
		}

		private void Start()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return;
			}
			ZDO zDO = _nview.GetZDO();
			if (_nview.IsOwner() && (Object)(object)_piece != (Object)null && _piece.IsCreator() && !zDO.GetBool(Keys.Reg, false))
			{
				zDO.Set(Keys.Reg, true);
				if (GuildClient.Mine != null)
				{
					zDO.Set(Keys.Guild, GuildClient.Mine.Id, false);
				}
				Vector3 pos = ((Component)this).transform.position;
				GuildClient.Send(Op.BannerPlaced, delegate(ZPackage p)
				{
					//IL_0002: Unknown result type (might be due to invalid IL or missing references)
					p.Write(pos);
				});
			}
		}

		private void Update()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return;
			}
			_tintTimer -= Time.deltaTime;
			if (!(_tintTimer > 0f))
			{
				_tintTimer = 2f;
				GuildSummary owner = Owner;
				Color val = (Color)(((??)owner?.Color) ?? new Color(0.5f, 0.5f, 0.5f));
				if (val != _lastTint)
				{
					Tint(val);
					_lastTint = val;
				}
				if (owner != null)
				{
					Territory.CheckLevelling(this, _nview, owner);
				}
			}
		}

		private void Tint(Color c)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			List<Renderer> list = (from r in ((Component)this).GetComponentsInChildren<Renderer>()
				where r is SkinnedMeshRenderer || (Object)(object)((Component)r).GetComponent<Cloth>() != (Object)null
				select r).ToList();
			if (list.Count == 0)
			{
				list = ((Component)this).GetComponentsInChildren<Renderer>().ToList();
			}
			MaterialPropertyBlock val = new MaterialPropertyBlock();
			foreach (Renderer item in list)
			{
				item.GetPropertyBlock(val);
				val.SetColor("_Color", Color.Lerp(Color.white, c, 0.85f));
				item.SetPropertyBlock(val);
			}
		}

		public string GetHoverText()
		{
			GuildSummary owner = Owner;
			if (owner == null)
			{
				return "Guild banner\n<color=#999999>(inactive — not registered to a guild)</color>";
			}
			string text = "<color=#" + owner.ColorHex + ">" + Util.Esc(owner.Name) + " [" + owner.Tag + "]</color>\nGuild banner · territory " + owner.TerritorySize + " m";
			if (GuildClient.Mine != null && GuildClient.Mine.Id == owner.Id)
			{
				text += "\n[<color=yellow><b>$KEY_Use</b></color>] Guild banner (upgrades)";
				if (owner.UpgradeLevel("Respawn") > 0)
				{
					text += "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Toggle respawn here";
				}
			}
			if (Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}

		public string GetHoverName()
		{
			return "Guild banner";
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (hold || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			GuildSummary owner = Owner;
			if (owner == null || GuildClient.Mine == null || GuildClient.Mine.Id != owner.Id)
			{
				Notify.Show(MsgKind.Info, (owner == null) ? "This banner belongs to no guild." : ("The banner of " + owner.Name + " [" + owner.Tag + "]."));
				return true;
			}
			if (alt)
			{
				GuildClient.Send(Op.ToggleBannerRespawn);
			}
			else
			{
				GuildWindow.OpenAtBanner(((Component)this).transform.position);
			}
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	public static class Territory
	{
		private static int _currentTerritory;

		private static float _checkTimer;

		private static float _lastDenyMsg;

		private static readonly FieldRef<Character, Rigidbody> BodyRef = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");

		private static readonly FieldRef<Player, GameObject> GhostRef = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly HashSet<ZDOID> _levelling = new HashSet<ZDOID>();

		private static readonly FieldRef<TerrainComp, float[]> F_level = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_levelDelta");

		private static readonly FieldRef<TerrainComp, float[]> F_smooth = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_smoothDelta");

		private static readonly FieldRef<TerrainComp, bool[]> F_mod = AccessTools.FieldRefAccess<TerrainComp, bool[]>("m_modifiedHeight");

		private static readonly FieldRef<TerrainComp, bool> F_init = AccessTools.FieldRefAccess<TerrainComp, bool>("m_initialized");

		private static readonly FieldRef<TerrainComp, ZNetView> F_nview = AccessTools.FieldRefAccess<TerrainComp, ZNetView>("m_nview");

		private static readonly MethodInfo M_save = AccessTools.Method(typeof(TerrainComp), "Save", new Type[1] { typeof(bool) }, (Type[])null);

		public static void RegisterRpcs(ZRoutedRpc rpc)
		{
		}

		public static void DenyMessage(string text)
		{
			if (!(Time.time - _lastDenyMsg < 1.5f))
			{
				_lastDenyMsg = Time.time;
				Notify.Show(MsgKind.Error, text);
			}
		}

		public static bool LocalDenied(Vector3 pos, bool message)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!GuildConfig.Enabled || !GuildClient.Rules.TerritoryClaim || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			GuildSummary guildSummary = GuildClient.TerritoryAt(pos);
			if (guildSummary == null || GuildClient.HasTerritoryAccess(guildSummary, GuildClient.LocalPid))
			{
				return false;
			}
			if (message)
			{
				DenyMessage("This land belongs to " + guildSummary.Name + " [" + guildSummary.Tag + "].");
			}
			return true;
		}

		public static void ClientUpdate(Player lp, float dt)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			_checkTimer -= dt;
			if (_checkTimer <= 0f)
			{
				_checkTimer = 0.5f;
				Vector3 position = ((Component)lp).transform.position;
				GuildSummary t = GuildClient.TerritoryAt(position);
				int num = ((t != null) ? t.Id : 0);
				if (num != _currentTerritory)
				{
					GuildClient.Summaries.TryGetValue(_currentTerritory, out var value);
					_currentTerritory = num;
					if (t != null)
					{
						bool flag = t.IsMember(GuildClient.LocalPid);
						GuildSummary guildSummary = GuildClient.GuildOfPlayer(GuildClient.LocalPid);
						bool flag2 = guildSummary != null && GuildClient.RelationBetween(guildSummary.Id, t.Id) == Relation.War;
						if ((Object)(object)MessageHud.instance != (Object)null)
						{
							MessageHud.instance.ShowMessage((MessageType)2, "<color=#" + t.ColorHex + ">" + Util.Esc(t.Name) + " [" + t.Tag + "]</color>" + (flag2 ? "\n<color=#FF5544>ENEMY TERRITORY</color>" : ""), 0, Util.Icon(t.Emblem), false, false);
						}
						if (!flag)
						{
							GuildClient.Send(Op.Intruder, delegate(ZPackage p)
							{
								p.Write(t.Id);
							});
						}
					}
					else if (value != null && (Object)(object)MessageHud.instance != (Object)null)
					{
						MessageHud.instance.ShowMessage((MessageType)1, "Leaving the territory of " + value.Name, 0, (Sprite)null, false, false);
					}
				}
			}
			TerritoryVisuals.Update(lp);
		}

		public static void Barrier(Player p)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if (!GuildConfig.Enabled || !GuildClient.HasState || !GuildClient.Rules.TerritoryBarrier || ((Character)p).IsDead() || ((Character)p).IsTeleporting() || ((Character)p).IsAttachedToShip())
			{
				return;
			}
			Vector3 position = ((Component)p).transform.position;
			GuildSummary guildSummary = GuildClient.TerritoryAt(position);
			if (guildSummary != null && !GuildClient.CanEnterTerritory(guildSummary, GuildClient.LocalPid))
			{
				float num = guildSummary.TerritorySize * 0.5f + 0.6f;
				float num2 = position.x - guildSummary.BannerPos.x;
				float num3 = position.z - guildSummary.BannerPos.z;
				Vector3 val = position;
				if (num - Mathf.Abs(num2) < num - Mathf.Abs(num3))
				{
					val.x = guildSummary.BannerPos.x + ((num2 >= 0f) ? num : (0f - num));
				}
				else
				{
					val.z = guildSummary.BannerPos.z + ((num3 >= 0f) ? num : (0f - num));
				}
				float num4 = default(float);
				if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val, ref num4, 1000))
				{
					val.y = Mathf.Max(val.y, num4);
				}
				((Component)p).transform.position = val;
				Rigidbody val2 = BodyRef.Invoke((Character)(object)p);
				if ((Object)(object)val2 != (Object)null)
				{
					val2.position = val;
				}
				((Character)p).SetVelocity(Vector3.zero);
				DenyMessage("You cannot enter the territory of " + guildSummary.Name + " [" + guildSummary.Tag + "].");
			}
		}

		public static string PlacementError(Player player, Piece piece)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)((Component)piece).GetComponent<GuildBanner>() != (Object)null))
			{
				return null;
			}
			GameObject val = GhostRef.Invoke(player);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? val.transform.position : ((Component)player).transform.position);
			Guild mine = GuildClient.Mine;
			GuildSummary mySummary = GuildClient.MySummary;
			if (mine == null || mySummary == null)
			{
				return "Found or join a guild first.";
			}
			Rules rules = GuildClient.Rules;
			if (!GuildClient.Has(Perm.Banner))
			{
				return "Your rank cannot place the guild banner.";
			}
			if (mine.HasBanner)
			{
				return "Your guild already has a banner.";
			}
			float num = rules.TerritorySize(mine.UpgradeLevel("Territory")) * 0.5f;
			foreach (GuildSummary value in GuildClient.Summaries.Values)
			{
				if (value.Id != mine.Id && value.HasBanner)
				{
					float num2 = num + value.TerritorySize * 0.5f + rules.TerritoryGap;
					if (Mathf.Abs(value.BannerPos.x - val2.x) < num2 && Mathf.Abs(value.BannerPos.z - val2.z) < num2)
					{
						return "Too close to the territory of " + value.Name + " [" + value.Tag + "].";
					}
				}
			}
			return null;
		}

		public static void CheckLevelling(GuildBanner banner, ZNetView nview, GuildSummary owner)
		{
			//IL_0032: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (!GuildClient.Rules.TerritoryLevelling || (Object)(object)Player.m_localPlayer == (Object)null || !owner.IsMember(GuildClient.LocalPid) || Vector3.Distance(((Component)Player.m_localPlayer).transform.position, ((Component)banner).transform.position) > owner.TerritorySize * 0.75f + 10f)
			{
				return;
			}
			ZDO zDO = nview.GetZDO();
			if (!(zDO.GetFloat(Keys.Levelled, 0f) >= owner.TerritorySize - 0.01f) && !_levelling.Contains(zDO.m_uid))
			{
				if (!nview.IsOwner())
				{
					nview.ClaimOwnership();
				}
				_levelling.Add(zDO.m_uid);
				((MonoBehaviour)GuildRuntime.Instance).StartCoroutine(Level(((Component)banner).transform.position, owner.TerritorySize, zDO));
			}
		}

		private static IEnumerator Level(Vector3 center, float size, ZDO zdo)
		{
			//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)
			Notify.Show(MsgKind.Info, "Levelling the guild territory…");
			float target = center.y;
			float half = size * 0.5f + 1f;
			float outer = half + 6f;
			RemoveVegetation(center, outer, target);
			yield return null;
			List<Bounds> blocked = new List<Bounds>();
			List<Piece> list = new List<Piece>();
			Piece.GetAllPiecesInRadius(center, outer * 1.5f, list);
			foreach (Piece item in list)
			{
				if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).GetComponent<GuildBanner>() != (Object)null)
				{
					continue;
				}
				Collider[] componentsInChildren = ((Component)item).GetComponentsInChildren<Collider>();
				foreach (Collider val in componentsInChildren)
				{
					if (!val.isTrigger)
					{
						Bounds bounds = val.bounds;
						((Bounds)(ref bounds)).Expand(new Vector3(1f, 0f, 1f));
						blocked.Add(bounds);
					}
				}
			}
			List<Heightmap> list2 = new List<Heightmap>();
			Heightmap.FindHeightmap(center, outer * 1.42f, list2);
			int done = 0;
			Vector3 val3 = default(Vector3);
			foreach (Heightmap hm in list2)
			{
				if ((Object)(object)hm == (Object)null)
				{
					continue;
				}
				TerrainComp tc = null;
				try
				{
					tc = hm.GetAndCreateTerrainCompiler();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Levelling: " + ex.Message));
				}
				if ((Object)(object)tc == (Object)null)
				{
					continue;
				}
				float wait = 0f;
				while ((Object)(object)tc != (Object)null && !F_init.Invoke(tc) && wait < 5f)
				{
					wait += 0.1f;
					yield return (object)new WaitForSeconds(0.1f);
				}
				if ((Object)(object)tc == (Object)null || !F_init.Invoke(tc))
				{
					continue;
				}
				ZNetView val2 = F_nview.Invoke(tc);
				if ((Object)(object)val2 != (Object)null && val2.IsValid() && !val2.IsOwner())
				{
					val2.ClaimOwnership();
				}
				float[] array = F_level.Invoke(tc);
				float[] array2 = F_smooth.Invoke(tc);
				bool[] array3 = F_mod.Invoke(tc);
				int num = hm.m_width + 1;
				float scale = hm.m_scale;
				int num2 = hm.m_width / 2;
				Vector3 position = ((Component)hm).transform.position;
				bool flag = false;
				for (int j = 0; j < num; j++)
				{
					for (int k = 0; k < num; k++)
					{
						((Vector3)(ref val3))..ctor(position.x + (float)(k - num2) * scale, 0f, position.z + (float)(j - num2) * scale);
						float num3 = Mathf.Abs(val3.x - center.x);
						float num4 = Mathf.Abs(val3.z - center.z);
						float num5 = Mathf.Max(num3, num4);
						if (num5 > outer)
						{
							continue;
						}
						bool flag2 = false;
						foreach (Bounds item2 in blocked)
						{
							Bounds current2 = item2;
							if (val3.x >= ((Bounds)(ref current2)).min.x && val3.x <= ((Bounds)(ref current2)).max.x && val3.z >= ((Bounds)(ref current2)).min.z && val3.z <= ((Bounds)(ref current2)).max.z)
							{
								flag2 = true;
								break;
							}
						}
						if (!flag2)
						{
							int num6 = j * num + k;
							float num7 = hm.GetHeight(k, j) - array[num6] - array2[num6];
							float num8;
							if (num5 <= half)
							{
								num8 = target;
							}
							else
							{
								float num9 = Mathf.Clamp01((num5 - half) / 6f);
								num9 = num9 * num9 * (3f - 2f * num9);
								num8 = Mathf.Lerp(target, num7, num9);
							}
							array[num6] = Mathf.Clamp(num8 - num7, -8f, 8f);
							array2[num6] = 0f;
							array3[num6] = true;
							flag = true;
						}
					}
				}
				if (flag)
				{
					try
					{
						M_save.Invoke(tc, new object[1] { false });
						hm.Poke(1, false);
						done++;
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogWarning((object)("Levelling save failed: " + ex2));
					}
				}
				yield return null;
			}
			try
			{
				if ((Object)(object)ClutterSystem.instance != (Object)null)
				{
					ClutterSystem.instance.ResetGrass(center, outer * 1.42f);
				}
			}
			catch
			{
			}
			Plugin.Log.LogInfo((object)("Territory levelled (" + done + " terrain chunk(s))."));
			if (zdo != null && zdo.IsValid())
			{
				zdo.Set(Keys.Levelled, size);
			}
			_levelling.Remove(zdo.m_uid);
			Notify.Show(MsgKind.Info, "The guild territory has been levelled.");
		}

		private static void RemoveVegetation(Vector3 center, float half, float target)
		{
			//IL_0000: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapBox(center, new Vector3(half, 60f, half), Quaternion.identity);
			HashSet<ZNetView> hashSet = new HashSet<ZNetView>();
			Collider[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				ZNetView componentInParent = ((Component)array2[i]).GetComponentInParent<ZNetView>();
				if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid() || hashSet.Contains(componentInParent))
				{
					continue;
				}
				GameObject gameObject = ((Component)componentInParent).gameObject;
				if (!((Object)(object)gameObject.GetComponent<Piece>() != (Object)null) && !((Object)(object)gameObject.GetComponent<Character>() != (Object)null) && !((Object)(object)gameObject.GetComponent<ItemDrop>() != (Object)null) && ((Object)(object)gameObject.GetComponent<TreeBase>() != (Object)null || (Object)(object)gameObject.GetComponent<TreeLog>() != (Object)null || (Object)(object)gameObject.GetComponent<Destructible>() != (Object)null || (Object)(object)gameObject.GetComponent<MineRock>() != (Object)null || (Object)(object)gameObject.GetComponent<MineRock5>() != (Object)null || (Object)(object)gameObject.GetComponent<Pickable>() != (Object)null))
				{
					Vector3 position = gameObject.transform.position;
					if (!(Mathf.Abs(ZoneSystem.instance.GetGroundHeight(position) - target) < 0.3f))
					{
						hashSet.Add(componentInParent);
						componentInParent.ClaimOwnership();
						ZNetScene.instance.Destroy(gameObject);
					}
				}
			}
		}
	}
	internal static class TerritoryVisuals
	{
		private class Vis
		{
			public LineRenderer Ground;

			public LineRenderer Curtain1;

			public LineRenderer Curtain2;

			public List<GameObject> Posts = new List<GameObject>();

			public Vector3 Center;

			public float Size;

			public Color Color;
		}

		private static readonly Dictionary<int, Vis> _vis = new Dictionary<int, Vis>();

		private static Material _mat;

		private static float _timer;

		private static Material Mat
		{
			get
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Expected O, but got Unknown
				if ((Object)(object)_mat == (Object)null)
				{
					_mat = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Standard"));
				}
				return _mat;
			}
		}

		public static void Update(Player lp)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			_timer -= Time.deltaTime;
			if (_timer > 0f)
			{
				return;
			}
			_timer = 0.25f;
			Vector3 position = ((Component)lp).transform.position;
			bool flag = ((Character)lp).InPlaceMode();
			GameObject hoverObject = ((Humanoid)lp).GetHoverObject();
			bool flag2 = (Object)(object)hoverObject != (Object)null && (Object)(object)hoverObject.GetComponentInParent<GuildBanner>() != (Object)null;
			HashSet<int> keep = new HashSet<int>();
			foreach (GuildSummary value2 in GuildClient.Summaries.Values)
			{
				if (!value2.HasBanner)
				{
					continue;
				}
				float num = value2.TerritorySize * 0.5f;
				float num2 = Mathf.Max(Mathf.Abs(position.x - value2.BannerPos.x), Mathf.Abs(position.z - value2.BannerPos.z)) - num;
				if (!(num2 > 150f))
				{
					bool flag3 = !GuildClient.CanEnterTerritory(value2, GuildClient.LocalPid);
					bool flag4 = Mathf.Abs(num2) < 12f;
					bool enabled = flag || flag2 || (flag3 && flag4);
					bool enabled2 = flag3 && flag4 && GuildClient.Rules.TerritoryBarrier;
					keep.Add(value2.Id);
					if (!_vis.TryGetValue(value2.Id, out var value))
					{
						value = Create();
						_vis[value2.Id] = value;
					}
					if (value.Center != value2.BannerPos || value.Size != value2.TerritorySize || value.Color != value2.Color)
					{
						Rebuild(value, value2);
					}
					((Renderer)value.Ground).enabled = enabled;
					((Renderer)value.Curtain1).enabled = enabled2;
					((Renderer)value.Curtain2).enabled = enabled2;
				}
			}
			foreach (int item in _vis.Keys.Where((int k) => !keep.Contains(k)).ToList())
			{
				Destroy(_vis[item]);
				_vis.Remove(item);
			}
		}

		private static Vis Create()
		{
			return new Vis
			{
				Ground = Line("vo_border", 0.15f),
				Curtain1 = Line("vo_curtain1", 0.6f),
				Curtain2 = Line("vo_curtain2", 0.35f)
			};
		}

		private static LineRenderer Line(string name, float width)
		{
			//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)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			Object.DontDestroyOnLoad((Object)val);
			LineRenderer obj = val.AddComponent<LineRenderer>();
			((Renderer)obj).material = Mat;
			obj.loop = true;
			obj.widthMultiplier = width;
			obj.useWorldSpace = true;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			((Renderer)obj).enabled = false;
			return obj;
		}

		private static void Rebuild(Vis v, GuildSummary s)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Expected O, but got Unknown
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			v.Center = s.BannerPos;
			v.Size = s.TerritorySize;
			v.Color = s.Color;
			float num = s.TerritorySize * 0.5f;
			List<Vector3> list = new List<Vector3>();
			Vector2[] array = (Vector2[])(object)new Vector2[4]
			{
				new Vector2(0f - num, 0f - num),
				new Vector2(num, 0f - num),
				new Vector2(num, num),
				new Vector2(0f - num, num)
			};
			Vector3 val4 = default(Vector3);
			for (int i = 0; i < 4; i++)
			{
				Vector2 val = array[i];
				Vector2 val2 = array[(i + 1) % 4];
				int num2 = Mathf.Max(1, Mathf.CeilToInt(Vector2.Distance(val, val2) / 2f));
				for (int j = 0; j < num2; j++)
				{
					Vector2 val3 = Vector2.Lerp(val, val2, (float)j / (float)num2);
					((Vector3)(ref val4))..ctor(s.BannerPos.x + val3.x, 0f, s.BannerPos.z + val3.y);
					val4.y = (((Object)(object)ZoneSystem.instance != (Object)null) ? (ZoneSystem.instance.GetGroundHeight(val4) + 0.15f) : s.BannerPos.y);
					list.Add(val4);
				}
			}
			Vector3[] pts = list.ToArray();
			Set(v.Ground, pts, 0f, new Color(s.Color.r, s.Color.g, s.Color.b, 0.95f));
			Set(v.Curtain1, pts, 1.2f, new Color(s.Color.r, s.Color.g, s.Color.b, 0.45f));
			Set(v.Curtain2, pts, 2.6f, new Color(s.Color.r, s.Color.g, s.Color.b, 0.25f));
			foreach (GameObject post in v.Posts)
			{
				if ((Object)(object)post != (Object)null)
				{
					Object.Destroy((Object)(object)post);
				}
			}
			v.Posts.Clear();
			Vector2[] array2 = array;
			Vector3 val6 = default(Vector3);
			foreach (Vector2 val5 in array2)
			{
				((Vector3)(ref val6))..ctor(s.BannerPos.x + val5.x, 0f, s.BannerPos.z + val5.y);
				val6.y = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.GetGroundHeight(val6) : s.BannerPos.y);
				GameObject val7 = Prefabs.VisualOf("wood_pole2") ?? Prefabs.VisualOf("wood_pole");
				if ((Object)(object)val7 != (Object)null)
				{
					val7.transform.position = val6;
					v.Posts.Add(val7);
				}
				GameObject val8 = GameObject.CreatePrimitive((PrimitiveType)0);
				Object.Destroy((Object)(object)val8.GetComponent<Collider>());
				val8.transform.position = val6 + Vector3.up * 2.1f;
				val8.transform.localScale = Vector3.one * 0.35f;
				val8.GetComponent<Renderer>().material = new Material(Mat)
				{
					color = s.Color
				};
				v.Posts.Add(val8);
			}
		}

		private static void Set(LineRenderer lr, Vector3[] pts, float lift, Color c)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			lr.positionCount = pts.Length;
			for (int i = 0; i < pts.Length; i++)
			{
				lr.SetPosition(i, pts[i] + Vector3.up * lift);
			}
			Color startColor = (lr.endColor = c);
			lr.startColor = startColor;
		}

		private static void Destroy(Vis v)
		{
			LineRenderer[] array = (LineRenderer[])(object)new LineRenderer[3] { v.Ground, v.Curtain1, v.Curtain2 };
			foreach (LineRenderer val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			foreach (GameObject post in v.Posts)
			{
				if ((Object)(object)post != (Object)null)
				{
					Object.Destroy((Object)(object)post);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class TerritoryPatches
	{
		private static readonly FieldRef<WearNTear, ZNetView> WntView = AccessTools.FieldRefAccess<WearNTear, ZNetView>("m_nview");

		private static readonly FieldRef<Piece, ZNetView> PieceView = AccessTools.FieldRefAccess<Piece, ZNetView>("m_nview");

		private static ZDO Zdo(ZNetView nv)
		{
			if (!((Object)(object)nv != (Object)null) || !nv.IsValid())
			{
				return null;
			}
			return nv.GetZDO();
		}

		[HarmonyPatch(typeof(PrivateArea), "CheckAccess")]
		[HarmonyPostfix]
		private static void CheckAccess(Vector3 point, bool flash, ref bool __result)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (__result && Territory.LocalDenied(point, flash))
			{
				__result = false;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "Interact")]
		[HarmonyPrefix]
		private static bool Station(CraftingStation __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result);
		}

		[HarmonyPatch(typeof(Bed), "Interact")]
		[HarmonyPrefix]
		private static bool BedUse(Bed __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result);
		}

		[HarmonyPatch(typeof(Fireplace), "Interact")]
		[HarmonyPrefix]
		private static bool Fire(Fireplace __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result);
		}

		[HarmonyPatch(typeof(Fireplace), "UseItem")]
		[HarmonyPrefix]
		private static bool FireItem(Fireplace __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result);
		}

		[HarmonyPatch(typeof(Smelter), "OnAddOre")]
		[HarmonyPrefix]
		private static bool SmeltOre(Smelter __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result, handled: false);
		}

		[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
		[HarmonyPrefix]
		private static bool SmeltFuel(Smelter __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result, handled: false);
		}

		[HarmonyPatch(typeof(Smelter), "OnEmpty")]
		[HarmonyPrefix]
		private static bool SmeltEmpty(Smelter __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result, handled: false);
		}

		[HarmonyPatch(typeof(CookingStation), "OnAddFoodSwitch")]
		[HarmonyPrefix]
		private static bool CookFood(CookingStation __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result, handled: false);
		}

		[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
		[HarmonyPrefix]
		private static bool CookFuel(CookingStation __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result, handled: false);
		}

		[HarmonyPatch(typeof(CookingStation), "OnInteract")]
		[HarmonyPrefix]
		private static bool CookTake(CookingStation __instance, ref bool __result)
		{
			return Gate((Component)(object)__instance, ref __result, handled: false);
		}

		private static bool Gate(Component c, ref bool result, bool handled = true)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!Territory.LocalDenied(c.transform.position, message: true))
			{
				return true;
			}
			result = handled;
			return false;
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		[HarmonyPrefix]
		private static bool TryPlace(Player __instance, Piece piece, ref bool __result)
		{
			if (!GuildConfig.Enabled || (Object)(object)piece == (Object)null)
			{
				return true;
			}
			string text = Territory.PlacementError(__instance, piece);
			if (text == null)
			{
				return true;
			}
			Territory.DenyMessage(text);
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		[HarmonyPostfix]
		private static void CanRemove(Piece piece, ref bool __result)
		{
			if (__result && GuildConfig.Enabled && !((Object)(object)piece == (Object)null) && (Object)(object)((Component)piece).GetComponent<GuildBanner>() != (Object)null)
			{
				GuildSummary owner = ((Component)piece).GetComponent<GuildBanner>().Owner;
				if (owner != null && (GuildClient.Mine == null || GuildClient.Mine.Id != owner.Id || !GuildClient.Has(Perm.Banner)))
				{
					Territory.DenyMessage("Only members with the Banner permission can take down the banner.");
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
		[HarmonyPrefix]
		private static bool Damage(WearNTear __instance, HitData hit)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!GuildConfig.Enabled)
			{
				return true;
			}
			if ((Object)(object)((Component)__instance).GetComponent<GuildBanner>() != (Object)null)
			{
				return false;
			}
			GuildView guildView = GuildData.TerritoryAt(((Component)__instance).transform.position);
			if (guildView != null && guildView.HasBanner && hit != null)
			{
				float num = Defs.Tier(Defs.SturdyReduction, guildView.UpgradeLevel("SturdyWalls"));
				if (num > 0f)
				{
					hit.ApplyModifier(1f - num);
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(WearNTear), "Destroy", new Type[]
		{
			typeof(HitData),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static void Destroyed(WearNTear __instance)
		{
			//IL_0037: 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)
			if (GuildConfig.Enabled && !((Object)(object)((Component)__instance).GetComponent<GuildBanner>() == (Object)null) && Zdo(WntView.Invoke(__instance)) != null)
			{
				Vector3 pos = ((Component)__instance).transform.position;
				GuildClient.Send(Op.BannerRemoved, delegate(ZPackage p)
				{
					//IL_0002: Unknown result type (might be due to invalid IL or missing references)
					p.Write(pos);
				});
			}
		}

		[HarmonyPatch(typeof(Player), "FixedUpdate")]
		[HarmonyPostfix]
		private static void Barrier(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Territory.Barrier(__instance);
			}
		}

		[HarmonyPatch(typeof(PrivateArea), "Interact")]
		[HarmonyPrefix]
		private static bool WardInteract(PrivateArea __instance, Humanoid human, bool hold, bool alt, ref bool __result)
		{
			if (!GuildConfig.Enabled || !alt || hold || !GuildClient.Rules.GuildWards || (Object)(object)human != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			Piece component = ((Component)__instance).GetComponent<Piece>();
			if ((Object)(object)component == (Object)null || !component.IsCreator())
			{
				return true;
			}
			__result = true;
			Guild mine = GuildClient.Mine;
			if (mine == null)
			{
				Notify.Show(MsgKind.Error, "You are not in a guild.");
				return false;
			}
			if (!GuildClient.Has(Perm.BindWards))
			{
				Notify.Show(MsgKind.Error, "Your rank cannot bind wards.");
				return false;
			}
			ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component2 == (Object)null || !component2.IsValid())
			{
				return false;
			}
			component2.ClaimOwnership();
			int num = ((component2.GetZDO().GetInt(Keys.Guild, 0) != mine.Id) ? mine.Id : 0);
			component2.GetZDO().Set(Keys.Guild, num, false);
			Notify.Show(MsgKind.Info, (num != 0) ? ("Ward bound to " + mine.Name + ".") : "Ward unbound from the guild.");
			return false;
		}

		[HarmonyPatch(typeof(PrivateArea), "IsPermitted")]
		[HarmonyPostfix]
		private static void WardPermitted(PrivateArea __instance, long playerID, ref bool __result)
		{
			if (__result || !GuildConfig.Enabled || !GuildClient.Rules.GuildWards)
			{
				return;
			}
			ZDO val = Zdo(((Component)__instance).GetComponent<ZNetView>());
			if (val == null)
			{
				return;
			}
			int num = val.GetInt(Keys.Guild, 0);
			if (num != 0 && GuildClient.Summaries.TryGetValue(num, out var value))
			{
				Piece component = ((Component)__instance).GetComponent<Piece>();
				if (!((Object)(object)component == (Object)null) && value.IsMember(component.GetCreator()) && value.WardMemberIds.Contains(playerID))
				{
					__result = true;
				}
			}
		}

		[HarmonyPatch(typeof(PrivateArea), "GetHoverText")]
		[HarmonyPostfix]
		private static void WardHover(PrivateArea __instance, ref string __result)
		{
			if (!GuildConfig.Enabled || !GuildClient.Rules.GuildWards)
			{
				return;
			}
			ZDO val = Zdo(((Component)__instance).GetComponent<ZNetView>());
			if (val != null)
			{
				int num = val.GetInt(Keys.Guild, 0);
				if (num != 0 && GuildClient.Summaries.TryGetValue(num, out var value))
				{
					__result = __result + "\n<color=#" + value.ColorHex + ">Guild ward: " + Util.Esc(value.Name) + " [" + value.Tag + "]</color>";
				}
				Piece component = ((Component)__instance).GetComponent<Piece>();
				if ((Object)(object)component != (Object)null && component.IsCreator() && GuildClient.Mine != null)
				{
					__result = __result + "\n[<color=yellow><b>Shift + E</b></color>] " + ((num == GuildClient.Mine.Id) ? "Unbind from guild" : "Bind to guild");
				}
			}
		}
	}
	public enum Op
	{
		Create = 1,
		Apply,
		WithdrawApplication,
		Invite,
		AcceptInvite,
		DeclineInvite,
		AcceptApplication,
		DeclineApplication,
		Leave,
		Disband,
		Kick,
		Promote,
		Demote,
		TransferLeader,
		SetInfo,
		Rename,
		RankAdd,
		RankEdit,
		RankMove,
		RankRemove,
		VaultDeposit,
		VaultWithdraw,
		CoinDeposit,
		CoinWithdraw,
		Donate,
		Diplomacy,
		BuyUpgrade,
		ToggleBannerRespawn,
		Chat,
		PinAdd,
		PinRemove,
		BannerPlaced,
		BannerRemoved,
		BuildingPlaced,
		BuildingRemoved,
		SetBarracksSpawn,
		StatReport,
		BossKill,
		Intruder,
		Admin,
		RequestSync
	}
	public enum DiploAction
	{
		ProposeAlliance = 1,
		BreakAlliance,
		DeclareWar,
		OfferPeace,
		AcceptOffer,
		DeclineOffer,
		WithdrawOffer
	}
	public enum MsgKind
	{
		Info,
		Error,
		Center,
		GuildChat,
		Notice,
		Motd
	}
	public static class Rpc
	{
		public const string Op = "VO_G_Op";

		public const string Sync = "VO_G_Sync";

		public const string Pos = "VO_G_Pos";

		public const string Msg = "VO_G_Msg";

		public const string Give = "VO_G_Give";
	}
	public class UpgradeDef
	{
		public string Id;

		public string Label;

		public string Effect;

		public bool PointsOnly;

		public string DefaultCost;

		public ConfigEntry<string> CostEntry;

		public UpgradeDef(string id, string label, string effect, bool pointsOnly, string cost)
		{
			Id = id;
			Label = label;
			Effect = effect;
			PointsOnly = pointsOnly;
			DefaultCost = cost;
		}
	}
	public class LevelCost
	{
		public int Points;

		public int MinLevel;

		public long Coins;

		public List<KeyValuePair<string, int>> Items = new List<KeyValuePair<string, int>>();

		public static List<LevelCost> ParseLevels(string s)
		{
			List<LevelCost> list = new List<LevelCost>();
			if (string.IsNullOrEmpty(s))
			{
				return list;
			}
			string[] array = s.Split(';');
			foreach (string obj in array)
			{
				LevelCost levelCost = new LevelCost();
				string[] array2 = obj.Split(',');
				for (int j = 0; j < array2.Length; j++)
				{
					string text = array2[j].Trim();
					if (text.Length == 0)
					{
						continue;
					}
					int num = text.IndexOf(':');
					if (num > 0)
					{
						if (int.TryParse(text.Substring(num + 1), out var result) && result > 0)
						{
							levelCost.Items.Add(new KeyValuePair<string, int>(text.Substring(0, num).Trim(), result));
						}
						continue;
					}
					char c = char.ToUpperInvariant(text[0]);
					if (long.TryParse(text.Substring(1), out var result2))
					{
						switch (c)
						{
						case 'P':
							levelCost.Points = (int)result2;
							break;
						case 'C':
							levelCost.Coins = result2;
							break;
						case 'L':
							levelCost.MinLevel = (int)result2;
							break;
						}
					}
				}
				list.Add(levelCost);
			}
			return list;
		}

		public string Describe()
		{
			List<string> list = new List<string>();
			if (Points > 0)
			{
				list.Add(Points + " point" + ((Points == 1) ? "" : "s"));
			}
			if (Coins > 0)
			{
				list.Add(Coins + " coins");
			}
			foreach (KeyValuePair<string, int> item in Items)
			{
				list.Add(item.Value + " " + Util.ItemDisplayName(item.Key));
			}
			if (MinLevel > 0)
			{
				list.Add("guild level " + MinLevel);
			}
			if (list.Count != 0)
			{
				return string.Join(", ", list.ToArray());
			}
			return "free";
		}
	}
	public class AchievementDef
	{
		public string Id;

		public string Label;

		public string Category;

		public string[] Stats;

		public long[] Tiers;

		public AchievementDef(string id, string label, string cat, string[] stats, long b, long s, long g)
		{
			Id = id;
			Label = label;
			Category = cat;
			Stats = stats;
			Tiers = new long[3] { b, s, g };
		}
	}
	public static class Defs
	{
		public static readonly UpgradeDef[] Upgrades = new UpgradeDef[10]
		{
			new UpgradeDef("Territory", "Territory", "+{0} m territory side per level", pointsOnly: true, "P1;P1;P2;P2;P3;P3;P4;P4"),
			new UpgradeDef("Vault", "Vault", "+{0} vault stacks per level (equipment and materials)", pointsOnly: true, "P1;P1;P1;P2;P2;P2;P3;P3;P3;P4"),
			new UpgradeDef("Members", "Members", "+{0} member slots per level", pointsOnly: true, "P1;P1;P2;P2;P3;P3;P4;P4;P5;P5"),
			new UpgradeDef("Regeneration", "Regeneration", "+5 / 10 / 15 % health, stamina and eitr regeneration for all members", pointsOnly: false, "C500,Wood:100,Stone:100,Resin:20;C1500,L5,Bronze:20,Guck:10,Chain:5;C4000,L10,BlackMetal:20,Needle:20,Eitr:10"),
			new UpgradeDef("Comfort", "Comfort", "+1 / +2 comfort while resting for all members", pointsOnly: false, "C800,FineWood:40,DeerHide:10,Resin:20;C3000,L8,Silver:20,WolfPelt:10,Crystal:5"),
			new UpgradeDef("MonsterWard", "Monster ward", "No monster spawns or raids inside the territory", pointsOnly: false, "C2000,L3,SurtlingCore:10,Iron:20,Stone:100"),
			new UpgradeDef("SturdyWalls", "Sturdy walls", "-20 / 35 / 50 % damage to structures inside the territory", pointsOnly: false, "C500,Stone:150,Wood:100;C1500,L5,Iron:30,Stone:300;C4000,L10,BlackMetal:30,BlackMarble:100"),
			new UpgradeDef("Workshops", "Workshops", "Smelters, kilns, fermenters and cooking built by members +5 / 10 / 15 % faster", pointsOnly: false, "C600,Copper:20,Tin:20;C2000,L6,Iron:30,Coal:50;C5000,L12,BlackMetal:20,Coal:100"),
			new UpgradeDef("FertileSoil", "Fertile soil", "Crops planted by members grow +10 / 20 / 30 % faster", pointsOnly: false, "C400,Wood:50,Dandelion:10;C1500,L5,Turnip:20,Guck:10;C4000,L10,Barley:40,Flax:40"),
			new UpgradeDef("Respawn", "Respawn at the banner", "Members can choose to respawn at the guild banner", pointsOnly: false, "C1500,L4,SurtlingCore:4,FineWood:20")
		};

		public static readonly float[] RegenBonus = new float[4] { 0f, 0.05f, 0.1f, 0.15f };

		public static readonly int[] ComfortBonus = new int[3] { 0, 1, 2 };

		public static readonly float[] SturdyReduction = new float[4] { 0f, 0.2f, 0.35f, 0.5f };

		public static readonly float[] WorkshopBonus = new float[4] { 0f, 0.05f, 0.1f, 0.15f };

		public static readonly float[] FertileBonus = new float[4] { 0f, 0.1f, 0.2f, 0.3f };

		public static readonly AchievementDef[] Achievements = new AchievementDef[17]
		{
			new AchievementDef("slayer", "Monster slayers", "Combat", new string[1] { "EnemyKills" }, 250L, 2500L, 15000L),
			new AchievementDef("bosses", "Boss hunters", "Combat", new string[1] { "BossKills" }, 3L, 15L, 50L),
			new AchievementDef("archers", "Volley masters", "Combat", new string[1] { "ArrowsShot" }, 500L, 5000L, 30000L),
			new AchievementDef("crafters", "Master crafters", "Crafting", new string[1] { "Crafts" }, 100L, 1000L, 5000L),
			new AchievementDef("upgraders", "Fine tuning", "Crafting", new string[1] { "Upgrades" }, 25L, 250L, 1000L),
			new AchievementDef("cooks", "Hearth keepers", "Crafting", new string[2] { "CraftFood", "CraftGrill" }, 100L, 1000L, 5000L),
			new AchievementDef("lumber", "Lumberjacks", "Gathering", new string[1] { "Tree" }, 300L, 3000L, 15000L),
			new AchievementDef("miners", "Deep miners", "Gathering", new string[1] { "Mines" }, 200L, 2000L, 10000L),
			new AchievementDef("farmers", "Farmers", "Gathering", new string[4] { "HarvestCrop", "HarvestBerry", "HarvestMushroom", "HarvestVine" }, 300L, 3000L, 15000L),
			new AchievementDef("fishers", "Fishers", "Gathering", new string[1] { "FishCaught" }, 25L, 250L, 1000L),
			new AchievementDef("builders", "Builders", "Building", new string[1] { "Builds" }, 500L, 5000L, 25000L),
			new AchievementDef("tamers", "Beast tamers", "Building", new string[1] { "CreatureTamed" }, 5L, 50L, 200L),
			new AchievementDef("travelers", "Wanderers", "Exploration", new string[1] { "DistanceTraveled" }, 50000L, 500000L, 2500000L),
			new AchievementDef("sailors", "Seafarers", "Exploration", new string[1] { "DistanceSail" }, 10000L, 100000L, 500000L),
			new AchievementDef("portals", "Gatewalkers", "Exploration", new string[1] { "PortalsUsed" }, 50L, 500L, 2500L),
			new AchievementDef("sleepers", "Well rested", "Other", new string[1] { "Sleep" }, 25L, 250L, 1000L),
			new AchievementDef("keepers", "Beekeepers and tappers", "Other", new string[2] { "BeesHarvested", "SapHarvested" }, 25L, 250L, 1000L)
		};

		public static readonly Dictionary<string, float> StatXp = new Dictionary<string, float>
		{
			{ "EnemyKills", 2f },
			{ "Crafts", 1f },
			{ "Upgrades", 2f },
			{ "CraftFood", 0.5f },
			{ "CraftGrill", 0.5f },
			{ "Tree", 1f },
			{ "Mines", 1f },
			{ "HarvestCrop", 0.3f },
			{ "HarvestBerry", 0.1f },
			{ "HarvestMushroom", 0.2f },
			{ "HarvestVine", 0.3f },
			{ "FishCaught", 3f },
			{ "Builds", 0.2f },
			{ "CreatureTamed", 10f },
			{ "DistanceTraveled", 0.002f },
			{ "DistanceSail", 0.002f },
			{ "BeesHarvested", 1f },
			{ "SapHarvested", 1f }
		};

		public static readonly Dictionary<string, long> StatCap = new Dictionary<string, long>
		{
			{ "EnemyKills", 60L },
			{ "ArrowsShot", 200L },
			{ "Crafts", 120L },
			{ "Upgrades", 60L },
			{ "CraftFood", 60L },
			{ "CraftGrill", 60L },
			{ "Tree", 40L },
			{ "Mines", 60L },
			{ "HarvestCrop", 200L },
			{ "HarvestBerry", 200L },
			{ "HarvestMushroom", 100L },
			{ "HarvestVine", 100L },
			{ "FishCaught", 15L },
			{ "Builds", 200L },
			{ "CreatureTamed", 5L },
			{ "DistanceTraveled", 3000L },
			{ "DistanceSail", 3000L },
			{ "PortalsUsed", 20L },
			{ "Sleep", 2L },
			{ "BeesHarvested", 20L },
			{ "SapHarvested", 20L }
		};

		public const string DefaultEmblems = "TrophyEikthyr,TrophyTheElder,TrophyBonemass,TrophyDragonQueen,TrophyGoblinKing,TrophySeekerQueen,TrophyFader,TrophyDeer,TrophyBoar,TrophyNeck,TrophyGreydwarf,TrophyGreydwarfBrute,TrophyGreydwarfShaman,TrophyTroll,TrophySkeleton,TrophyDraugr,TrophyDraugrElite,TrophyBlob,TrophyWraith,TrophyLeech,TrophyWolf,TrophyFenring,TrophyHatchling,TrophySGolem,TrophyGoblin,TrophyGoblinBrute,TrophyGoblinShaman,TrophyLox,TrophyDeathsquito,TrophyGrowth,TrophySeeker,TrophySeekerBrute,TrophyTick,TrophyGjall,TrophyDvergr,TrophyHare,TrophySerpent,TrophyAbomination,TrophyCultist,TrophyUlv,TrophyBjorn,TrophyAsksvin,TrophyCharredMelee,TrophyMorgen,TrophyFallenValkyrie";

		public const string DefaultBosses = "Eikthyr,gd_king,Bonemass,Dragon,GoblinKing,SeekerQueen,Fader";

		public static UpgradeDef Upgrade(string id)
		{
			UpgradeDef[] upgrades = Upgrades;
			foreach (UpgradeDef upgradeDef in upgrades)
			{
				if (upgradeDef.Id == id)
				{
					return upgradeDef;
				}
			}
			return null;
		}

		public static float Tier(float[] table, int level)
		{
			return table[Math.Max(0, Math.Min(level, table.Length - 1))];
		}

		public static int Tier(int[] table, int level)
		{
			return table[Math.Max(0, Math.Min(level, table.Length - 1))];
		}
	}
	public class Rules
	{
		public long CreateCost = 1000L;

		public int MaxMembers = 15;

		public int MaxRanks = 8;

		public int VaultSlots = 40;

		public int GearSlots = 40;

		public int InviteExpireHours = 48;

		public int RejoinCooldownHours = 12;

		public bool AllowApplications = true;

		public bool GuildWards = true;

		public bool GuildChat = true;

		public string BlockedVaultItems = "";

		public string Emblems = "TrophyEikthyr,TrophyTheElder,TrophyBonemass,TrophyDragonQueen,TrophyGoblinKing,TrophySeekerQueen,TrophyFader,TrophyDeer,TrophyBoar,TrophyNeck,TrophyGreydwarf,TrophyGreydwarfBrute,TrophyGreydwarfShaman,TrophyTroll,TrophySkeleton,TrophyDraugr,TrophyDraugrElite,TrophyBlob,TrophyWraith,TrophyLeech,TrophyWolf,TrophyFenring,TrophyHatchling,TrophySGolem,TrophyGoblin,TrophyGoblinBrute,TrophyGoblinShaman,TrophyLox,TrophyDeathsquito,TrophyGrowth,TrophySeeker,TrophySeekerBrute,TrophyTick,TrophyGjall,TrophyDvergr,TrophyHare,TrophySerpent,TrophyAbomination,TrophyCultist,TrophyUlv,TrophyBjorn,TrophyAsksvin,TrophyCharredMelee,TrophyMorgen,TrophyFallenValkyrie";

		public int LevelXpBase = 1000;

		public float LevelXpGrowth = 1.25f;

		public int MaxLevel = 30;

		public int PointsPerLevel = 1;

		public int StartingPoints = 1;

		public float ActivityXpMultiplier = 1f;

		public int XpBossFirstKill = 1500;

		public int XpBossKill = 150;

		public int XpBronze = 300;

		public int XpSilver = 1000;

		public int XpGold = 3000;

		public int DonationCoinsPerXp = 10;

		public string BossNames = "Eikthyr,gd_king,Bonemass,Dragon,GoblinKing,SeekerQueen,Fader";

		public bool TerritoryClaim = true;

		public bool TerritoryBarrier = true;

		public bool AlliesCanEnter = true;

		public bool TerritoryLevelling = true;

		public bool UpgradeOnlyAtBanner = true;

		public float TerritoryBaseSize = 70f;

		public float TerritorySizePerUpgrade = 10f;

		public float TerritoryGap = 20f;

		public int VaultSlotsPerUpgrade = 10;

		public int MembersPerUpgrade = 5;

		public string BannerRecipe = "Wood:20,LeatherScraps:8,DeerHide:4,Resin:4";

		public bool ShareMemberPositions = true;

		public int MaxGuildPins = 100;

		public bool IntruderAlerts = true;

		public bool WarEnablesPvP = true;

		public bool NoFriendlyFire = true;

		public Dictionary<string, string> UpgradeCosts = new Dictionary<string, string>();

		[NonSerialized]
		private HashSet<string> _blocked;

		[NonSerialized]
		private List<string> _emblems;

		[NonSerialized]
		private HashSet<string> _bosses;

		[NonSerialized]
		private Dictionary<string, List<LevelCost>> _costs;

		public HashSet<string> Blocked
		{
			get
			{
				if (_blocked == null)
				{
					_blocked = new HashSet<string>(Split(BlockedVaultItems));
				}
				return _blocked;
			}
		}

		public List<string> EmblemList
		{
			get
			{
				if (_emblems == null)
				{
					_emblems = new List<string>(Split(Emblems));
				}
				return _emblems;
			}
		}

		public HashSet<string> Bosses
		{
			get
			{
				if (_bosses == null)
				{
					_bosses = new HashSet<string>(Split(BossNames));
				}
				return _bosses;
			}
		}

		public List<LevelCost> CostsFor(string upgradeId)
		{
			if (_costs == null)
			{
				_costs = new Dictionary<string, List<LevelCost>>();
			}
			if (!_costs.TryGetValue(upgradeId, out var value))
			{
				if (!UpgradeCosts.TryGetValue(upgradeId, out var value2))
				{
					UpgradeDef upgradeDef = Defs.Upgrade(upgradeId);
					value2 = ((upgradeDef == null) ? "" : upgradeDef.DefaultCost);
				}
				value = LevelCost.ParseLevels(value2);
				_costs[upgradeId] = value;
			}
			return value;
		}

		public int MaxUpgradeLevel(string id)
		{
			return CostsFor(id).Count;
		}

		public long XpForLevel(int level)
		{
			return (long)Math.Round((double)LevelXpBase * Math.Pow(LevelXpGrowth, Math.Max(0, level - 1)));
		}

		public float TerritorySize(int territoryUpgrade)
		{
			return TerritoryBaseSize + TerritorySizePerUpgrade * (float)territoryUpgrade;
		}

		public int MembersMax(int membersUpgrade)
		{
			return MaxMembers + MembersPerUpgrade * membersUpgrade;
		}

		public int ArmoryCapacity(Guild g)
		{
			return GearSlots + VaultSlotsPerUpgrade * g.UpgradeLevel("Vault");
		}

		public int WarehouseCapacity(Guild g)
		{
			return VaultSlots + VaultSlotsPerUpgrade * g.UpgradeLevel("Vault");
		}

		private static IEnumerable<string> Split(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				yield break;
			}
			string[] array = s.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					yield return text;
				}
			}
		}

		public void Write(ZPackage p)
		{
			p.Write(CreateCost);
			p.Write(MaxMembers);
			p.Write(MaxRanks);
			p.Write(VaultSlots);
			p.Write(GearSlots);
			p.Write(InviteExpireHours);
			p.Write(RejoinCooldownHours);
			p.Write(AllowApplications);
			p.Write(GuildWards);
			p.Write(GuildChat);
			p.Write(BlockedVaultItems);
			p.Write(Emblems);
			p.Write(LevelXpBase);
			p.Write(LevelXpGrowth);
			p.Write(MaxLevel);
			p.Write(PointsPerLevel);
			p.Write(StartingPoints);
			p.Write(ActivityXpMultiplier);
			p.Write(XpBossFirstKill);
			p.Write(XpBossKill);
			p.Write(XpBronze);
			p.Write(XpSilver);
			p.Write(XpGold);
			p.Write(DonationCoinsPerXp);
			p.Write(BossNames);
			p.Write(TerritoryClaim);
			p.Write(TerritoryBarrier);
			p.Write(AlliesCanEnter);
			p.Write(TerritoryLevelling);
			p.Write(UpgradeOnlyAtBanner);
			p.Write(TerritoryBaseSize);
			p.Write(TerritorySizePerUpgrade);
			p.Write(TerritoryGap);
			p.Write(VaultSlotsPerUpgrade);
			p.Write(MembersPerUpgrade);
			p.Write(BannerRecipe);
			p.Write(ShareMemberPositions);
			p.Write(MaxGuildPins);
			p.Write(IntruderAlerts);
			p.Write(WarEnablesPvP);
			p.Write(NoFriendlyFire);
			WriteMap(p, UpgradeCosts);
		}

		public static Rules Read(ZPackage p)
		{
			return new Rules
			{
				CreateCost = p.ReadLong(),
				MaxMembers = p.ReadInt(),
				MaxRanks = p.ReadInt(),
				VaultSlots = p.ReadInt(),
				GearSlots = p.ReadInt(),
				InviteExpireHours = p.ReadInt(),
				RejoinCooldownHours = p.ReadInt(),
				AllowApplications = p.ReadBool(),
				GuildWards = p.ReadBool(),
				GuildChat = p.ReadBool(),
				BlockedVaultItems = p.ReadString(),
				Emblems = p.ReadString(),
				LevelXpBase = p.ReadInt(),
				LevelXpGrowth = p.ReadSingle(),
				MaxLevel = p.ReadInt(),
				PointsPerLevel = p.ReadInt(),
				StartingPoints = p.ReadInt(),
				ActivityXpMultiplier = p.ReadSingle(),
				XpBossFirstKill = p.ReadInt(),
				XpBossKill = p.ReadInt(),
				XpBronze = p.ReadInt(),
				XpSilver = p.ReadInt(),
				XpGold = p.ReadInt(),
				DonationCoinsPerXp = p.ReadInt(),
				BossNames = p.ReadString(),
				TerritoryClaim = p.ReadBool(),
				TerritoryBarrier = p.ReadBool(),
				AlliesCanEnter = p.ReadBool(),
				TerritoryLevelling = p.ReadBool(),
				UpgradeOnlyAtBanner = p.ReadBool(),
				TerritoryBaseSize = p.ReadSingle(),
				TerritorySizePerUpgrade = p.ReadSingle(),
				TerritoryGap = p.ReadSingle(),
				VaultSlotsPerUpgrade = p.ReadInt(),
				MembersPerUpgrade = p.ReadInt(),
				BannerRecipe = p.ReadString(),
				ShareMemberPositions = p.ReadBool(),
				MaxGuildPins = p.ReadInt(),
				IntruderAlerts = p.ReadBool(),
				WarEnablesPvP = p.ReadBool(),
				NoFriendlyFire = p.ReadBool(),
				UpgradeCosts = ReadMap(p)
			};
		}

		private static void WriteMap(ZPackage p, Dictionary<string, string> m)
		{
			p.Write(m.Count);
			foreach (KeyValuePair<string, string> item in m)
			{
				p.Write(item.Key);
				p.Write(item.Value);
			}
		}

		private static Dictionary<string, string> ReadMap(ZPackage p)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			int num = p.ReadInt();
			for (int i = 0; i < num; i++)
			{
				dictionary[p.ReadString()] = p.ReadString();
			}
			return dictionary;
		}
	}
	[HarmonyPatch]
	internal static class EffectPatches
	{
		private static readonly FieldRef<SEMan, Character> SemanChar = AccessTools.FieldRefAccess<SEMan, Character>("m_character");

		private static GuildView LocalGuild
		{
			get
			{
				if (!GuildConfig.Enabled || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					return null;
				}
				GuildView guildView = GuildData.OfPlayer(Player.m_localPlayer.GetPlayerID());
				if (guildView == null || !guildView.HasBanner)
				{
					return null;
				}
				return guildView;
			}
		}

		private static GuildView CreatorGuild(Component c)
		{
			if (!GuildConfig.Enabled)
			{
				return null;
			}
			Piece component = c.GetComponent<Piece>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			GuildView guildView = GuildData.OfPlayer(component.GetCreator());
			if (guildView == null || !guildView.HasBanner)
			{
				return null;
			}
			return guildView;
		}

		private static float RegenBonus(SEMan seman)
		{
			if ((Object)(object)SemanChar.Invoke(seman) != (Object)(object)Player.m_localPlayer)
			{
				return 0f;
			}
			GuildView localGuild = LocalGuild;
			if (localGuild != null)
			{
				return Defs.Tier(Defs.RegenBonus, localGuild.UpgradeLevel("Regeneration"));
			}
			return 0f;
		}

		[HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")]
		[HarmonyPostfix]
		private static void HealthRegen(SEMan __instance, ref float regenMultiplier)
		{
			regenMultiplier += RegenBonus(__instance);
		}

		[HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")]
		[HarmonyPostfix]
		private static void StaminaRegen(SEMan __instance, ref float staminaMultiplier)
		{
			staminaMultiplier += RegenBonus(__instance);
		}

		[HarmonyPatch(typeof(SEMan), "ModifyEitrRegen")]
		[HarmonyPostfix]
		private static void EitrRegen(SEMan __instance, ref float eitrMultiplier)
		{
			eitrMultiplier += RegenBonus(__instance);
		}

		[HarmonyPatch(typeof(SE_Rested), "CalculateComfortLevel", new Type[]
		{
			typeof(bool),
			typeof(Vector3)
		})]
		[HarmonyPostfix]
		private static void Comfort(bool inShelter, Vector3 position, ref int __result)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (inShelter && !((Object)(object)localPlayer == (Object)null) && !(Vector3.Distance(((Component)localPlayer).transform.position, position) > 1f))
			{
				GuildView localGuild = LocalGuild;
				if (localGuild != null)
				{
					__result += Defs.Tier(Defs.ComfortBonus, localGuild.UpgradeLevel("Comfort"));
				}
			}
		}

		[HarmonyPatch(typeof(SpawnSystem), "IsSpawnPointGood")]
		[HarmonyPostfix]
		private static void NoSpawn(ref Vector3 spawnPoint, ref bool __result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (__result && GuildConfig.Enabled)
			{
				GuildView guildView = GuildData.TerritoryAt(spawnPoint);
				if (guildView != null && guildView.UpgradeLevel("MonsterWard") > 0)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(RandEventSystem), "GetValidEventPoints")]
		[HarmonyPostfix]
		private static void NoRaids(List<Vector3> __result)
		{
			if (GuildConfig.Enabled)
			{
				__result?.RemoveAll(delegate(Vector3 p)
				{
					//IL_0000: Unknown result type (might be due to invalid IL or missing references)
					GuildView guildView = GuildData.TerritoryAt(p);
					return guildView != null && guildView.UpgradeLevel("MonsterWard") > 0;
				});
			}
		}

		private static double WorkshopFactor(Component c)
		{
			GuildView guildView = CreatorGuild(c);
			if (guildView != null)
			{
				return 1.0 + (double)Defs.Tier(Defs.WorkshopBonus, guildView.UpgradeLevel("Workshops"));
			}
			return 1.0;
		}

		[HarmonyPatch(typeof(Smelter), "GetDeltaTime")]
		[HarmonyPostfix]
		private static void SmelterTime(Smelter __instance, ref double __result)
		{
			if (__result > 0.0)
			{
				__result *= WorkshopFactor((Component)(object)__instance);
			}
		}

		[HarmonyPatch(typeof(CookingStation), "GetDeltaTime")]
		[HarmonyPostfix]
		private static void CookTime(CookingStation __instance, ref float __result)
		{
			if (__result > 0f)
			{
				__result *= (float)WorkshopFactor((Component)(object)__instance);
			}
		}

		[HarmonyPatch(typeof(Fermenter), "GetFermentationTime")]
		[HarmonyPostfix]
		private static void FermentTime(Fermenter __instance, ref double __result)
		{
			if (__result > 0.0)
			{
				__result *= WorkshopFactor((Component)(object)__instance);
			}
		}

		[HarmonyPatch(typeof(Plant), "GetGrowTime")]
		[HarmonyPostfix]
		private static void GrowTime(Plant __instance, ref float __result)
		{
			GuildView guildView = CreatorGuild((Component)(object)__instance);
			if (guildView != null)
			{
				float num = Defs.Tier(Defs.FertileBonus, guildView.UpgradeLevel("FertileSoil"));
				if (num > 0f)
				{
					__result /= 1f + num;
				}
			}
		}

		[HarmonyPatch(typeof(Game), "FindSpawnPoint")]
		[HarmonyPrefix]
		private static bool Respawn(Game __instance, ref Vector3 point, ref bool usedLogoutPoint, ref bool __result)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (!GuildConfig.Enabled || !Traverse.Create((object)__instance).Field("m_respawnAfterDeath").GetValue<bool>())
			{
				return true;
			}
			Guild mine = GuildClient.Mine;
			if (mine == null)
			{
				return true;
			}
			Member member = mine.GetMember(GuildClient.MyPid);
			if (member == null)
			{
				return true;
			}
			if (member.BannerRespawn && mine.HasBanner && mine.UpgradeLevel("Respawn") > 0)
			{
				Vector3 bannerPos = mine.BannerPos;
				ZNet.instance.SetReferencePosition(bannerPos);
				usedLogoutPoint = false;
				if (!ZNetScene.instance.IsAreaReady(bannerPos))
				{
					point = Vector3.zero;
					__result = false;
					return false;
				}
				Vector3 val = bannerPos + new Vector3(2f, 0f, 2f);
				float y = default(float);
				if (ZoneSystem.instance.GetSolidHeight(val, ref y, 1000))
				{
					val.y = y;
				}
				point = val + Vector3.up * 0.5f;
				__result = true;
				return false;
			}
			return true;
		}

		private static int WarState(Character a, Character b)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!GuildConfig.Enabled || (Object)(object)a == (Object)null || (Object)(object)b == (Object)null || (Object)(object)a == (Object)(object)b || !a.IsPlayer() || !b.IsPlayer())
			{
				return 0;
			}
			GuildSummary guildSummary = GuildClient.GuildOfPlayer(((Player)a).GetPlayerID());
			GuildSummary guildSummary2 = GuildClient.GuildOfPlayer(((Player)b).GetPlayerID());
			if (guildSummary == null || guildSummary2 == null)
			{
				return 0;
			}
			Relation relation = GuildClient.RelationBetween(guildSummary.Id, guildSummary2.Id);
			if (relation == Relation.War && GuildClient.Rules.WarEnablesPvP)
			{
				return 1;
			}
			if (relation == Relation.Alliance && GuildClient.Rules.NoFriendlyFire)
			{
				return -1;
			}
			return 0;
		}

		[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
		{
			typeof(Character),
			typeof(Character)
		})]
		[HarmonyPostfix]
		private static void IsEnemy(Character a, Character b, ref bool __result)
		{
			if (WarState(a, b) == 1)
			{
				__result = true;
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		[HarmonyPrefix]
		private static bool Damage(Character __instance, HitData hit)
		{
			if (hit == null)
			{
				return true;
			}
			switch (WarState(hit.GetAttacker(), __instance))
			{
			case 1:
				hit.m_ignorePVP = true;
				break;
			case -1:
				return false;
			}
			return true;
		}
	}
	public static class ConfigReload
	{
		private static ConfigFile _config;

		private static FileSystemWatcher _watcher;

		private static volatile bool _pending;

		private static DateTime _lastApply;

		public static bool Pending => _pending;

		public static void Watch(ConfigFile config)
		{
			_config = config;
			try
			{
				string configFilePath = config.ConfigFilePath;
				_watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath));
				_watcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite;
				_watcher.Changed += delegate
				{
					_pending = true;
				};
				_watcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Config file watcher unavailable: " + ex.Message));
			}
		}

		public static voi