Decompiled source of Blyssheim v0.4.5

plugins/Blyssheim/Blyssheim.dll

Decompiled 43 minutes 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.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Blyssheim.Dev;
using Blyssheim.Pets;
using Blyssheim.Warden;
using Blyssheim.Watch;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Blyssheim")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.5.0")]
[assembly: AssemblyInformationalVersion("0.4.5+8639bc0efdf90803a1a603d3111c7ca3251e90b0")]
[assembly: AssemblyProduct("Blyssheim")]
[assembly: AssemblyTitle("Blyssheim")]
[assembly: AssemblyVersion("0.4.5.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 Blyssheim
{
	[BepInPlugin("overzealyss.blyssheim", "Blyssheim", "0.4.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "overzealyss.blyssheim";

		public const string Name = "Blyssheim";

		public const string Version = "0.4.5";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private void Awake()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Settings.Bind(((BaseUnityPlugin)this).Config);
			Diagnostics.Bind(((BaseUnityPlugin)this).Config);
			BodyExport.Bind(((BaseUnityPlugin)this).Config);
			WardenItems.Init(((BaseUnityPlugin)this).Config);
			WardenNet.Init(((BaseUnityPlugin)this).Config);
			PetFetch.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("overzealyss.blyssheim").PatchAll();
			Log.LogInfo((object)"Blyssheim 0.4.5 loaded.");
		}

		private void Update()
		{
			WardenNet.Tick();
			WardenSearch.Tick();
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class Rpc
	{
		public const string Snapshot = "Blyssheim_Snapshot";

		public const string Alert = "Blyssheim_Alert";

		private static void Postfix()
		{
			ZRoutedRpc.instance.Register<ZPackage>("Blyssheim_Snapshot", (Action<long, ZPackage>)ServerWatch.OnSnapshot);
			ZRoutedRpc.instance.Register<string>("Blyssheim_Alert", (Action<long, string>)ClientWatch.OnAlert);
			WardenNet.Register();
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated())
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(ReportContrabandSoon());
			}
		}

		private static IEnumerator ReportContrabandSoon()
		{
			yield return (object)new WaitForSeconds(15f);
			Contraband.LogSummary();
		}

		public static long ServerPeerId()
		{
			return (long)AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null).Invoke(ZRoutedRpc.instance, null);
		}
	}
}
namespace Blyssheim.Watch
{
	internal static class ClientWatch
	{
		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class SpawnPatch
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && _loop == null)
				{
					_loop = ((MonoBehaviour)Plugin.Instance).StartCoroutine(Loop());
				}
			}
		}

		[HarmonyPatch(typeof(Game), "Logout")]
		private static class LogoutPatch
		{
			private static void Prefix()
			{
				Send("leave");
			}
		}

		private static readonly PlayerStatType[] TrackedStats;

		private static Coroutine _loop;

		private static string _lastSent;

		private static bool OnDedicatedServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
				{
					return (Object)(object)Player.m_localPlayer != (Object)null;
				}
				return false;
			}
		}

		public unsafe static Snapshot Take(string kind)
		{
			//IL_0120: 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)
			Player localPlayer = Player.m_localPlayer;
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if ((Object)(object)localPlayer == (Object)null || val == null)
			{
				return null;
			}
			Snapshot snapshot = new Snapshot
			{
				Kind = kind,
				PlayerId = val.GetPlayerID(),
				Character = val.GetName(),
				UsedCheats = val.m_usedCheats
			};
			PlayerStats[] array = val.m_playerStats ?? Array.Empty<PlayerStats>();
			foreach (PlayerStats val2 in array)
			{
				if (val2 != null)
				{
					if (val2.m_knownWorlds != null)
					{
						snapshot.KnownWorlds.AddRange(val2.m_knownWorlds.Keys);
					}
					if (val2.m_knownCommands != null)
					{
						snapshot.KnownCommands.AddRange(val2.m_knownCommands.Keys);
					}
				}
			}
			snapshot.KnownWorlds = snapshot.KnownWorlds.Distinct().ToList();
			snapshot.KnownCommands = snapshot.KnownCommands.Distinct().Where(IsCheatCommand).ToList();
			PlayerStatType[] trackedStats = TrackedStats;
			for (int i = 0; i < trackedStats.Length; i++)
			{
				PlayerStatType val3 = trackedStats[i];
				snapshot.Stats[((object)(*(PlayerStatType*)(&val3))/*cast due to .constrained prefix*/).ToString()] = val.GetStat(val3);
			}
			foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
			{
				snapshot.Items.Add(new ItemEntry
				{
					Name = (Object.op_Implicit((Object)(object)allItem.m_dropPrefab) ? ((Object)allItem.m_dropPrefab).name : allItem.m_shared.m_name),
					Stack = allItem.m_stack,
					Quality = allItem.m_quality,
					Cheated = allItem.m_cheated,
					Crafter = allItem.m_crafterName
				});
			}
			return snapshot;
		}

		private static bool IsCheatCommand(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			string text = name.Split(' ')[0].ToLowerInvariant();
			if (text == "devcommands")
			{
				return true;
			}
			if (!(AccessTools.Field(typeof(Terminal), "commands")?.GetValue(null) is IDictionary dictionary) || !dictionary.Contains(text))
			{
				return false;
			}
			object? obj = dictionary[text];
			return ((ConsoleCommand)(((obj is ConsoleCommand) ? obj : null)?)).IsCheat ?? false;
		}

		public static void Send(string kind, bool onlyIfChanged = false)
		{
			if (!OnDedicatedServer)
			{
				return;
			}
			Snapshot snapshot = Take(kind);
			if (snapshot != null)
			{
				string text = string.Join(";", from kv in snapshot.Totals()
					orderby kv.Key
					select kv.Key + "=" + kv.Value);
				if (!onlyIfChanged || !(text == _lastSent))
				{
					_lastSent = text;
					ZRoutedRpc.instance.InvokeRoutedRPC(Rpc.ServerPeerId(), "Blyssheim_Snapshot", new object[1] { snapshot.ToPackage() });
				}
			}
		}

		private static IEnumerator Loop()
		{
			yield return (object)new WaitForSeconds(3f);
			_lastSent = null;
			Send("arrive");
			while ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				yield return (object)new WaitForSeconds((float)Mathf.Max(5, Settings.CheckpointSeconds.Value));
				Send("checkpoint", onlyIfChanged: true);
			}
			_loop = null;
		}

		public static void OnAlert(long sender, string text)
		{
			if (Object.op_Implicit((Object)(object)MessageHud.instance))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "<color=#ff4040>CONTRABAND</color>\n" + text, 0, (Sprite)null, false, true);
			}
			if (Object.op_Implicit((Object)(object)Chat.instance))
			{
				((Terminal)Chat.instance).AddString("<color=#ff4040>Blyssheim</color>", text, (Type)0, true);
			}
			Plugin.Log.LogWarning((object)("Contraband alert: " + text));
			Alerts.Raise(text);
		}

		static ClientWatch()
		{
			PlayerStatType[] array = new PlayerStatType[16];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			TrackedStats = (PlayerStatType[])(object)array;
		}
	}
	public static class Alerts
	{
		public static event Action<string> OnContraband;

		internal static void Raise(string text)
		{
			Alerts.OnContraband?.Invoke(text);
		}
	}
	internal static class Contraband
	{
		public static readonly (string Key, string Boss)[] Bosses = new(string, string)[7]
		{
			("defeated_eikthyr", "Eikthyr"),
			("defeated_gdking", "The Elder"),
			("defeated_bonemass", "Bonemass"),
			("defeated_dragon", "Moder"),
			("defeated_goblinking", "Yagluth"),
			("defeated_queen", "The Queen"),
			("defeated_fader", "Fader")
		};

		private static readonly Dictionary<string, string[]> Defaults = new Dictionary<string, string[]>
		{
			["defeated_eikthyr"] = new string[1] { "HardAntler" },
			["defeated_gdking"] = new string[4] { "Iron", "IronScrap", "IronOre", "CryptKey" },
			["defeated_bonemass"] = new string[3] { "Silver", "SilverOre", "Wishbone" },
			["defeated_dragon"] = new string[3] { "DragonTear", "BlackMetal", "LinenThread" },
			["defeated_goblinking"] = new string[4] { "YagluthDrop", "Wisp", "Eitr", "BlackCore" },
			["defeated_queen"] = new string[5] { "QueenDrop", "FlametalNew", "FlametalOreNew", "Flametal", "FlametalOre" },
			["defeated_fader"] = new string[1] { "FaderDrop" }
		};

		private static Dictionary<string, int> _tier;

		private static string FilePath => Path.Combine(ServerWatch.DataDir, "contraband.json");

		private static Dictionary<string, string[]> LoadTable()
		{
			if (!File.Exists(FilePath))
			{
				File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)Defaults, (Formatting)1));
			}
			try
			{
				return JsonConvert.DeserializeObject<Dictionary<string, string[]>>(File.ReadAllText(FilePath)) ?? Defaults;
			}
			catch
			{
				return Defaults;
			}
		}

		private static void Build()
		{
			_tier = new Dictionary<string, int>();
			Dictionary<string, string[]> dictionary = LoadTable();
			for (int i = 0; i < Bosses.Length; i++)
			{
				if (dictionary.TryGetValue(Bosses[i].Key, out var value))
				{
					string[] array = value;
					foreach (string key in array)
					{
						_tier[key] = i;
					}
				}
			}
			List<Recipe> list = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.m_recipes.Where((Recipe r) => Object.op_Implicit((Object)(object)r) && Object.op_Implicit((Object)(object)r.m_item)).ToList() : new List<Recipe>());
			bool flag = true;
			int num = 0;
			while (flag && num < 20)
			{
				flag = false;
				foreach (Recipe item in list)
				{
					int num2 = -1;
					Requirement[] array2 = (Requirement[])(((object)item.m_resources) ?? ((object)new Requirement[0]));
					foreach (Requirement val in array2)
					{
						if (Object.op_Implicit((Object)(object)val?.m_resItem) && _tier.TryGetValue(((Object)((Component)val.m_resItem).gameObject).name, out var value2) && value2 > num2)
						{
							num2 = value2;
						}
					}
					if (num2 >= 0)
					{
						string name = ((Object)((Component)item.m_item).gameObject).name;
						if (!_tier.TryGetValue(name, out var value3) || num2 > value3)
						{
							_tier[name] = num2;
							flag = true;
						}
					}
				}
				num++;
			}
			Plugin.Log.LogInfo((object)$"Contraband table: {_tier.Count} gated items.");
		}

		public static string BossNeeded(string item)
		{
			if (_tier == null)
			{
				Build();
			}
			if (!_tier.TryGetValue(item, out var value))
			{
				return null;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance != (Object)null && instance.GetGlobalKey(Bosses[value].Key))
			{
				return null;
			}
			return Bosses[value].Boss;
		}

		public static void Reset()
		{
			_tier = null;
		}

		public static void LogSummary()
		{
			if (_tier == null)
			{
				Build();
			}
			List<IGrouping<string, (string, string)>> list = (from i in _tier.Keys
				select (Item: i, Boss: BossNeeded(i)) into x
				where x.Boss != null
				group x by x.Boss).ToList();
			IEnumerable<string> values = from b in Bosses
				where Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey(b.Key)
				select b.Boss;
			Plugin.Log.LogInfo((object)("Contraband: bosses beaten: " + string.Join(", ", values) + ". " + $"{list.Sum((IGrouping<string, (string Item, string Boss)> g) => g.Count())} items are contraband right now."));
			foreach (IGrouping<string, (string, string)> item in list)
			{
				Plugin.Log.LogInfo((object)string.Format("  waits on {0} ({1}): {2}{3}", item.Key, item.Count(), string.Join(", ", (from x in item
					select x.Item into x
					orderby x
					select x).Take(25)), (item.Count() > 25) ? ", ..." : ""));
			}
		}
	}
	public class PlayerRecord
	{
		public string Host;

		public string Character;

		public long PlayerId;

		public DateTime LastSeen;

		public bool UsedCheats;

		public List<string> KnownWorlds = new List<string>();

		public List<string> KnownCommands = new List<string>();

		public Dictionary<string, float> Stats = new Dictionary<string, float>();

		public Snapshot Last;

		public DateTime? OnlineSince;

		public double SecondsOnServer;

		public int Sessions;

		public DateTime? FirstSeen;
	}
	public class Incident
	{
		public DateTime When;

		public string Character;

		public string Host;

		public List<string> Charges = new List<string>();
	}
	internal static class ServerWatch
	{
		private static readonly Dictionary<long, string> OpenByPeer = new Dictionary<long, string>();

		private static readonly JsonSerializerSettings Json = new JsonSerializerSettings
		{
			Formatting = (Formatting)1
		};

		public static string DataDir
		{
			get
			{
				string text = Path.Combine(Paths.ConfigPath, "Blyssheim");
				Directory.CreateDirectory(text);
				return text;
			}
		}

		private static string PlayersDir
		{
			get
			{
				string text = Path.Combine(DataDir, "players");
				Directory.CreateDirectory(text);
				return text;
			}
		}

		private static string IncidentsPath => Path.Combine(DataDir, "incidents.json");

		private static string LogPath => Path.Combine(DataDir, "watch.log");

		private static string SessionsPath => Path.Combine(DataDir, "sessions.csv");

		public static void OnSnapshot(long sender, ZPackage pkg)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				Snapshot snapshot = Snapshot.FromPackage(pkg);
				ZNetPeer peer = ZNet.instance.GetPeer(sender);
				if (snapshot != null && peer != null)
				{
					Handle(peer, snapshot);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Watch: " + ex));
			}
		}

		private static string FileFor(string host, long id)
		{
			return Path.Combine(PlayersDir, string.Concat(string.Concat((host + "_" + id).Select((char c) => (!Path.GetInvalidFileNameChars().Contains(c)) ? c : '_')), ".json"));
		}

		public static IEnumerable<PlayerRecord> AllRecords()
		{
			return from r in Directory.GetFiles(PlayersDir, "*.json").Select(delegate(string f)
				{
					try
					{
						return JsonConvert.DeserializeObject<PlayerRecord>(File.ReadAllText(f));
					}
					catch
					{
						return (PlayerRecord)null;
					}
				})
				where r != null
				select r;
		}

		public static List<Incident> Incidents()
		{
			try
			{
				return File.Exists(IncidentsPath) ? (JsonConvert.DeserializeObject<List<Incident>>(File.ReadAllText(IncidentsPath)) ?? new List<Incident>()) : new List<Incident>();
			}
			catch
			{
				return new List<Incident>();
			}
		}

		private static void Handle(ZNetPeer peer, Snapshot snap)
		{
			string hostName = peer.m_socket.GetHostName();
			string text = FileFor(hostName, snap.PlayerId);
			PlayerRecord playerRecord = null;
			if (File.Exists(text))
			{
				try
				{
					playerRecord = JsonConvert.DeserializeObject<PlayerRecord>(File.ReadAllText(text));
				}
				catch
				{
				}
			}
			if (snap.Kind == "arrive")
			{
				List<string> list = Judge(playerRecord, snap);
				Note($"{snap.Character} ({hostName}) arrived carrying {snap.Items.Sum((ItemEntry i) => i.Stack)} items" + ((list.Count > 0) ? (" - CHARGES: " + string.Join("; ", list)) : " - clean"));
				if (list.Count > 0)
				{
					Report(new Incident
					{
						When = DateTime.Now,
						Character = snap.Character,
						Host = hostName,
						Charges = list
					});
				}
			}
			playerRecord = playerRecord ?? new PlayerRecord();
			if (snap.Kind == "arrive")
			{
				if (playerRecord.OnlineSince.HasValue)
				{
					CloseSession(playerRecord, playerRecord.LastSeen, "no leave recorded");
				}
				playerRecord.OnlineSince = DateTime.Now;
				playerRecord.Sessions++;
				playerRecord.FirstSeen = playerRecord.FirstSeen ?? DateTime.Now;
				OpenByPeer[peer.m_uid] = text;
			}
			else if (snap.Kind == "leave" && playerRecord.OnlineSince.HasValue)
			{
				CloseSession(playerRecord, DateTime.Now, "left");
				OpenByPeer.Remove(peer.m_uid);
			}
			playerRecord.Host = hostName;
			playerRecord.Character = snap.Character;
			playerRecord.PlayerId = snap.PlayerId;
			playerRecord.LastSeen = DateTime.Now;
			playerRecord.UsedCheats = snap.UsedCheats;
			playerRecord.KnownWorlds = snap.KnownWorlds;
			playerRecord.KnownCommands = snap.KnownCommands;
			playerRecord.Stats = snap.Stats;
			playerRecord.Last = snap;
			File.WriteAllText(text, JsonConvert.SerializeObject((object)playerRecord, Json));
		}

		private static void CloseSession(PlayerRecord rec, DateTime end, string how)
		{
			DateTime value = rec.OnlineSince.Value;
			double num = Math.Max(0.0, (end - value).TotalSeconds);
			rec.SecondsOnServer += num;
			rec.OnlineSince = null;
			try
			{
				if (!File.Exists(SessionsPath))
				{
					File.WriteAllText(SessionsPath, "character,account,start,end,minutes,how" + Environment.NewLine);
				}
				File.AppendAllText(SessionsPath, $"{rec.Character},{rec.Host},{value:yyyy-MM-dd HH:mm:ss},{end:yyyy-MM-dd HH:mm:ss},{num / 60.0:0.0},{how}{Environment.NewLine}");
			}
			catch
			{
			}
		}

		public static void OnDisconnect(ZNetPeer peer)
		{
			if (peer == null || !OpenByPeer.TryGetValue(peer.m_uid, out var value))
			{
				return;
			}
			OpenByPeer.Remove(peer.m_uid);
			try
			{
				PlayerRecord playerRecord = JsonConvert.DeserializeObject<PlayerRecord>(File.ReadAllText(value));
				if (playerRecord != null && playerRecord.OnlineSince.HasValue)
				{
					CloseSession(playerRecord, DateTime.Now, "disconnected");
					File.WriteAllText(value, JsonConvert.SerializeObject((object)playerRecord, Json));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Watch session: " + ex));
			}
		}

		public static string PlaytimeReport()
		{
			List<(string, double, int, bool, float, DateTime?)> list = (from x in AllRecords().Select(delegate(PlayerRecord r)
				{
					double item = r.SecondsOnServer + (r.OnlineSince.HasValue ? (DateTime.Now - r.OnlineSince.Value).TotalSeconds : 0.0);
					float item2 = 0f;
					if (r.Stats != null)
					{
						r.Stats.TryGetValue("TimeInBase", out var value);
						r.Stats.TryGetValue("TimeOutOfBase", out var value2);
						item2 = value + value2;
					}
					return (Character: r.Character, s: item, Sessions: r.Sessions, Online: r.OnlineSince.HasValue, Life: item2, FirstSeen: r.FirstSeen);
				})
				orderby x.s descending
				select x).ToList();
			if (list.Count == 0)
			{
				return "No time recorded yet.";
			}
			return "Time on Blyss (since Blyssheim 0.4.3):\n" + string.Join("\n", list.Select<(string, double, int, bool, float, DateTime?), string>(((string Character, double s, int Sessions, bool Online, float Life, DateTime? FirstSeen) x) => string.Format("{0}: {1} in {2} session{3}{4}", x.Character, Span(x.s), x.Sessions, (x.Sessions == 1) ? "" : "s", x.Online ? " (online now)" : "") + ((x.Life > 0f) ? ("; character total, all worlds: " + Span(x.Life)) : "")));
			static string Span(double s)
			{
				TimeSpan timeSpan = TimeSpan.FromSeconds(s);
				if (!(timeSpan.TotalHours >= 1.0))
				{
					return $"{timeSpan.Minutes}m";
				}
				return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes:00}m";
			}
		}

		private static List<string> Judge(PlayerRecord rec, Snapshot now)
		{
			List<string> list = new List<string>();
			bool flag = rec?.Last == null;
			Dictionary<string, int> before = (flag ? new Dictionary<string, int>() : rec.Last.Totals());
			Dictionary<string, int> source = now.Totals();
			int num = ((!flag) ? rec.Last.Items.Where((ItemEntry i) => i.Cheated).Sum((ItemEntry i) => i.Stack) : 0);
			List<string> list2 = (from i in now.Items
				where i.Cheated
				group i by i.Name into g
				select $"{g.Sum((ItemEntry i) => i.Stack)} {g.Key}").ToList();
			if (list2.Count > 0 && now.Items.Where((ItemEntry i) => i.Cheated).Sum((ItemEntry i) => i.Stack) > num)
			{
				list.Add("carrying items made with cheats: " + string.Join(", ", list2));
			}
			if (now.UsedCheats && (flag || !rec.UsedCheats))
			{
				list.Add("this character has used cheats");
			}
			List<string> list3 = now.KnownCommands.Except(flag ? new List<string>() : rec.KnownCommands).ToList();
			if (list3.Count > 0)
			{
				list.Add("console commands used: " + string.Join(", ", list3));
			}
			int value;
			List<string> list4 = (from kv in source
				select (Item: kv.Key, Gain: kv.Value - (before.TryGetValue(kv.Key, out value) ? value : 0), Boss: Contraband.BossNeeded(kv.Key)) into x
				where x.Gain > 0 && x.Boss != null
				select $"{x.Gain} {x.Item} (needs {x.Boss})").ToList();
			if (list4.Count > 0)
			{
				list.Add("contraband: " + string.Join(", ", list4));
			}
			if (!flag)
			{
				List<(string Item, int Gain)> list5 = (from kv in source
					select (Item: kv.Key, Gain: kv.Value - (before.TryGetValue(kv.Key, out value) ? value : 0)) into x
					where x.Gain > 0 && Contraband.BossNeeded(x.Item) == null
					select x).ToList();
				int big = Math.Max(1, Settings.BigGainStacks.Value);
				List<(string, int)> list6 = list5.Where(((string Item, int Gain) x) => x.Gain >= big * MaxStack(x.Item)).ToList();
				if (list6.Count > 0)
				{
					list.Add("came back with a big haul: " + string.Join(", ", list6.Select<(string, int), string>(((string Item, int Gain) x) => $"+{x.Gain} {x.Item}")));
				}
				List<(string, int)> list7 = list5.Except<(string, int)>(list6).ToList();
				if (list7.Count > 0 && (Settings.AlertOnAnyGain.Value || list.Count > 0))
				{
					list.Add("also gained while away: " + string.Join(", ", list7.Select<(string, int), string>(((string Item, int Gain) x) => $"+{x.Gain} {x.Item}")));
				}
				List<string> list8 = now.KnownWorlds.Except(rec.KnownWorlds).ToList();
				if (list8.Count > 0 && list.Count > 0)
				{
					list.Add("visited other worlds since last time: " + string.Join(", ", list8));
				}
			}
			return list;
		}

		private static int MaxStack(string item)
		{
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(item) : null);
			ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return 50;
			}
			return Math.Max(1, val2.m_itemData.m_shared.m_maxStackSize);
		}

		private static void Report(Incident inc)
		{
			List<Incident> list = Incidents();
			list.Add(inc);
			File.WriteAllText(IncidentsPath, JsonConvert.SerializeObject((object)list, Json));
			string text = inc.Character + ": " + string.Join("\n", inc.Charges);
			foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers())
			{
				if (ZNet.instance.IsAdmin(connectedPeer.m_socket.GetHostName()))
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(connectedPeer.m_uid, "Blyssheim_Alert", new object[1] { text });
				}
			}
		}

		public static void Log(string line)
		{
			Note(line);
		}

		private static void Note(string line)
		{
			Plugin.Log.LogInfo((object)("Watch: " + line));
			try
			{
				File.AppendAllText(LogPath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}  {line}{Environment.NewLine}");
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Disconnect", new Type[] { typeof(ZNetPeer) })]
	internal static class SessionPatches
	{
		private static void Prefix(ZNetPeer peer)
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				ServerWatch.OnDisconnect(peer);
			}
		}
	}
	internal static class Settings
	{
		public static ConfigEntry<int> CheckpointSeconds;

		public static ConfigEntry<int> BigGainStacks;

		public static ConfigEntry<bool> AlertOnAnyGain;

		public static void Bind(ConfigFile cfg)
		{
			CheckpointSeconds = cfg.Bind<int>("Watch", "CheckpointSeconds", 20, "How often a player's game reports what they carry while playing, so a crash still leaves a recent record.");
			BigGainStacks = cfg.Bind<int>("Watch", "BigGainStacks", 2, "Server: coming back with this many more full stacks of one item than you left with counts as a charge.");
			AlertOnAnyGain = cfg.Bind<bool>("Watch", "AlertOnAnyGain", true, "Server: if true, any item gained while away is listed with the charges; if false, only gated, cheated or big gains are.");
		}
	}
	public class ItemEntry
	{
		public string Name;

		public int Stack;

		public int Quality;

		public bool Cheated;

		public string Crafter;
	}
	public class Snapshot
	{
		public const int Format = 1;

		public string Kind;

		public long PlayerId;

		public string Character;

		public bool UsedCheats;

		public List<string> KnownWorlds = new List<string>();

		public List<string> KnownCommands = new List<string>();

		public Dictionary<string, float> Stats = new Dictionary<string, float>();

		public List<ItemEntry> Items = new List<ItemEntry>();

		public Dictionary<string, int> Totals()
		{
			return (from i in Items
				group i by i.Name).ToDictionary((IGrouping<string, ItemEntry> g) => g.Key, (IGrouping<string, ItemEntry> g) => g.Sum((ItemEntry i) => i.Stack));
		}

		public ZPackage ToPackage()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(Kind ?? "");
			val.Write(PlayerId);
			val.Write(Character ?? "");
			val.Write(UsedCheats);
			WriteList(val, KnownWorlds);
			WriteList(val, KnownCommands);
			val.Write(Stats.Count);
			foreach (KeyValuePair<string, float> stat in Stats)
			{
				val.Write(stat.Key);
				val.Write(stat.Value);
			}
			val.Write(Items.Count);
			foreach (ItemEntry item in Items)
			{
				val.Write(item.Name ?? "");
				val.Write(item.Stack);
				val.Write(item.Quality);
				val.Write(item.Cheated);
				val.Write(item.Crafter ?? "");
			}
			return val;
		}

		public static Snapshot FromPackage(ZPackage p)
		{
			if (p.ReadInt() != 1)
			{
				return null;
			}
			Snapshot snapshot = new Snapshot
			{
				Kind = p.ReadString(),
				PlayerId = p.ReadLong(),
				Character = p.ReadString(),
				UsedCheats = p.ReadBool(),
				KnownWorlds = ReadList(p),
				KnownCommands = ReadList(p)
			};
			int num = p.ReadInt();
			for (int i = 0; i < num; i++)
			{
				snapshot.Stats[p.ReadString()] = p.ReadSingle();
			}
			num = p.ReadInt();
			for (int j = 0; j < num; j++)
			{
				snapshot.Items.Add(new ItemEntry
				{
					Name = p.ReadString(),
					Stack = p.ReadInt(),
					Quality = p.ReadInt(),
					Cheated = p.ReadBool(),
					Crafter = p.ReadString()
				});
			}
			return snapshot;
		}

		private static void WriteList(ZPackage p, List<string> list)
		{
			p.Write(list.Count);
			foreach (string item in list)
			{
				p.Write(item ?? "");
			}
		}

		private static List<string> ReadList(ZPackage p)
		{
			List<string> list = new List<string>();
			int num = p.ReadInt();
			for (int i = 0; i < num; i++)
			{
				list.Add(p.ReadString());
			}
			return list;
		}
	}
}
namespace Blyssheim.Warden
{
	internal static class WardenAccess
	{
		[HarmonyPatch(typeof(PrivateArea), "CheckAccess")]
		private static class Wards
		{
			private static void Postfix(ref bool __result)
			{
				if (!__result && Active())
				{
					__result = true;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "CheckAccess")]
		private static class PrivateChests
		{
			private static void Postfix(ref bool __result)
			{
				if (!__result && Active())
				{
					__result = true;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class AskOnSpawn
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsServer())
				{
					AdminConfirmed = false;
					WardenNet.AskServer("whoami", 0f);
				}
			}
		}

		public static bool AdminConfirmed;

		public static bool Active()
		{
			Player localPlayer = Player.m_localPlayer;
			if (AdminConfirmed && Object.op_Implicit((Object)(object)localPlayer))
			{
				return WardenVisuals.IsWarden(((Component)localPlayer).GetComponent<VisEquipment>());
			}
			return false;
		}
	}
	internal class WardenFX : MonoBehaviour
	{
		[HarmonyPatch(typeof(Player), "Awake")]
		private static class AttachToPlayers
		{
			private static void Postfix(Player __instance)
			{
				if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<WardenFX>()))
				{
					((Component)__instance).gameObject.AddComponent<WardenFX>();
				}
			}
		}

		public static readonly Dictionary<ZDOID, float> SirenUntil = new Dictionary<ZDOID, float>();

		public static readonly Dictionary<ZDOID, (string Word, float Until)> Shamed = new Dictionary<ZDOID, (string, float)>();

		private static readonly Color RuneDim = new Color(0.45f, 0.02f, 0.02f);

		private static readonly Color RuneBright = new Color(1f, 0.12f, 0.08f);

		private Player _player;

		private VisEquipment _vis;

		private GameObject _rig;

		private Transform _hips;

		private Transform _spine2;

		private Transform _head;

		private Transform _lFore;

		private Transform _lHand;

		private Transform _rFore;

		private Transform _rHand;

		private Transform _lUp;

		private Transform _lLeg;

		private Transform _lFoot;

		private Transform _rUp;

		private Transform _rLeg;

		private Transform _rFoot;

		private readonly List<(Transform T, Func<Vector3> Pos, Func<Quaternion> Rot)> _pieces = new List<(Transform, Func<Vector3>, Func<Quaternion>)>();

		private readonly List<Material> _runeMats = new List<Material>();

		private Light _chestLight;

		private Light _beaconLight;

		private Light _beaconSpot;

		private Transform _beacon;

		private Transform _spinner;

		private Material _beaconMat;

		private float _nextBubble;

		private Transform _helmModel;

		private List<GameObject> _clothes;

		private float _nextHelmLook;

		private static Material _unlit;

		private ZDOID Id
		{
			get
			{
				//IL_0019: 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)
				if (!Object.op_Implicit((Object)(object)_player))
				{
					return ZDOID.None;
				}
				return ((Character)_player).GetZDOID();
			}
		}

		private void Awake()
		{
			_player = ((Component)this).GetComponent<Player>();
			_vis = ((Component)this).GetComponent<VisEquipment>();
		}

		private void LateUpdate()
		{
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: 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_00f9: Invalid comparison between Unknown and I4
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_player))
			{
				return;
			}
			bool flag = WardenVisuals.IsWarden(_vis);
			if (flag && !Object.op_Implicit((Object)(object)_rig))
			{
				Build();
			}
			if (!flag && Object.op_Implicit((Object)(object)_rig))
			{
				Object.Destroy((Object)(object)_rig);
				_rig = null;
				_pieces.Clear();
				_runeMats.Clear();
			}
			if (!flag && Object.op_Implicit((Object)(object)_helmModel))
			{
				Object.Destroy((Object)(object)((Component)_helmModel).gameObject);
				_helmModel = null;
			}
			if (!flag && _clothes != null)
			{
				foreach (GameObject clothe in _clothes)
				{
					if (Object.op_Implicit((Object)(object)clothe))
					{
						Object.Destroy((Object)(object)clothe);
					}
				}
				_clothes = null;
			}
			if (flag && _clothes == null && (int)SystemInfo.graphicsDeviceType != 4)
			{
				_clothes = new List<GameObject>();
				string[] array = new string[2] { "warden_coat", "warden_pants" };
				foreach (string asset in array)
				{
					GameObject val = WardenSkinned.Attach(_vis, asset);
					if (Object.op_Implicit((Object)(object)val))
					{
						_clothes.Add(val);
					}
				}
				if (Object.op_Implicit((Object)(object)_rig) && WardenSkinned.Has("warden_coat"))
				{
					Renderer[] componentsInChildren = _rig.GetComponentsInChildren<Renderer>(true);
					foreach (Renderer val2 in componentsInChildren)
					{
						if ((Object)(object)((Component)val2).transform != (Object)(object)_beacon)
						{
							val2.enabled = false;
						}
					}
				}
			}
			ZDOID id = Id;
			float value;
			bool siren = SirenUntil.TryGetValue(id, out value) && Time.time < value;
			if (Object.op_Implicit((Object)(object)_rig))
			{
				Animate(siren);
			}
			Bubbles(id, siren);
		}

		private Transform Bone(string name)
		{
			Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private void Build()
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Expected O, but got Unknown
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			_hips = Bone("Hips");
			_spine2 = Bone("Spine2");
			_head = Bone("Helmet_attach") ?? Bone("Head");
			_lFore = Bone("LeftForeArm");
			_lHand = Bone("LeftHand");
			_rFore = Bone("RightForeArm");
			_rHand = Bone("RightHand");
			_lUp = Bone("LeftUpLeg");
			_lLeg = Bone("LeftLeg");
			_lFoot = Bone("LeftFoot");
			_rUp = Bone("RightUpLeg");
			_rLeg = Bone("RightLeg");
			_rFoot = Bone("RightFoot");
			if (!Object.op_Implicit((Object)(object)_hips) || !Object.op_Implicit((Object)(object)_spine2) || !Object.op_Implicit((Object)(object)_head))
			{
				return;
			}
			_rig = new GameObject("BlyssheimWardenRig");
			_rig.transform.SetParent(((Component)this).transform, false);
			Transform root = ((Component)this).transform;
			AddRune(() => Vector3.Lerp(_lFore.position, _lHand.position, 0.45f) - root.right * 0.1f, () => Quaternion.LookRotation(-root.right), 1f);
			AddRune(() => Vector3.Lerp(_rFore.position, _rHand.position, 0.45f) + root.right * 0.1f, () => Quaternion.LookRotation(root.right), 1f);
			(Transform, Transform, Transform)[] array = new(Transform, Transform, Transform)[2]
			{
				(_lUp, _lLeg, _lFoot),
				(_rUp, _rLeg, _rFoot)
			};
			for (int num = 0; num < array.Length; num++)
			{
				(Transform, Transform, Transform) tuple = array[num];
				Transform item = tuple.Item1;
				Transform item2 = tuple.Item2;
				Transform item3 = tuple.Item3;
				Transform u = item;
				Transform k = item2;
				Transform f = item3;
				AddRune(() => Vector3.Lerp(u.position, k.position, 0.55f) + root.forward * 0.1f, () => root.rotation, 1f);
				AddRune(() => Vector3.Lerp(k.position, f.position, 0.4f) + root.forward * 0.09f, () => root.rotation, 0.9f);
			}
			Transform val = Primitive((PrimitiveType)2, new Vector3(0.11f, 0.004f, 0.11f), RuneDim);
			_pieces.Add((val, () => _spine2.position + root.forward * 0.26f + root.up * 0.03f, () => root.rotation * Quaternion.Euler(90f, 0f, 0f)));
			AddRune(() => _spine2.position + root.forward * 0.27f + root.up * 0.03f, () => root.rotation, 1.3f);
			_chestLight = AddLight(val, (LightType)2, 1.4f, 0.6f);
			Transform val2 = Primitive((PrimitiveType)3, new Vector3(0.05f, 0.08f, 0.05f), RuneDim);
			_pieces.Add((val2, () => _hips.position + root.right * 0.25f + root.forward * 0.1f - root.up * 0.05f, () => root.rotation));
			AddLight(val2, (LightType)2, 0.9f, 0.4f);
			_beacon = Primitive((PrimitiveType)2, new Vector3(0.09f, 0.045f, 0.09f), new Color(0.3f, 0.02f, 0.02f));
			_beaconMat = ((Component)_beacon).GetComponent<Renderer>().material;
			_pieces.Add((_beacon, () => (!Object.op_Implicit((Object)(object)_helmModel)) ? (_head.position + root.up * 0.1f) : _helmModel.TransformPoint(0f, 1.28f, 0f), () => root.rotation));
			_spinner = new GameObject("spinner").transform;
			_spinner.SetParent(_beacon, false);
			_beaconLight = AddLight(_beacon, (LightType)2, 4f, 0f);
			GameObject val3 = new GameObject("spot");
			val3.transform.SetParent(_spinner, false);
			val3.transform.localRotation = Quaternion.Euler(10f, 0f, 0f);
			_beaconSpot = val3.AddComponent<Light>();
			_beaconSpot.type = (LightType)0;
			_beaconSpot.color = RuneBright;
			_beaconSpot.range = 14f;
			_beaconSpot.spotAngle = 45f;
			_beaconSpot.intensity = 0f;
		}

		private static Material Unlit(Color c)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)_unlit))
			{
				Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
				Shader val = null;
				string[] array2 = new string[3] { "Standard", "Unlit/Color", "Sprites/Default" };
				foreach (string want in array2)
				{
					val = Array.Find(array, (Shader s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == want) ?? Shader.Find(want);
					if (Object.op_Implicit((Object)(object)val))
					{
						break;
					}
				}
				_unlit = new Material(val);
				Plugin.Log.LogInfo((object)("Warden glow shader: " + (Object.op_Implicit((Object)(object)val) ? ((Object)val).name : "none")));
			}
			Material val2 = new Material(_unlit);
			if (val2.HasProperty("_EmissionColor"))
			{
				val2.EnableKeyword("_EMISSION");
			}
			SetGlow(val2, c, 1.5f);
			return val2;
		}

		private static void SetGlow(Material m, Color c, float brightness)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (m.HasProperty("_EmissionColor"))
			{
				m.color = c * 0.35f;
				m.SetColor("_EmissionColor", c * brightness);
			}
			else
			{
				m.color = c;
			}
		}

		private Transform Primitive(PrimitiveType type, Vector3 scale, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive(type);
			Object.Destroy((Object)(object)obj.GetComponent<Collider>());
			obj.transform.SetParent(_rig.transform, false);
			obj.transform.localScale = scale;
			Material val = Unlit(color);
			obj.GetComponent<Renderer>().material = val;
			obj.GetComponent<Renderer>().shadowCastingMode = (ShadowCastingMode)0;
			_runeMats.Add(val);
			return obj.transform;
		}

		private void AddRune(Func<Vector3> pos, Func<Quaternion> rot, float size)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = new GameObject("rune").transform;
			transform.SetParent(_rig.transform, false);
			float[] array = new float[2] { 40f, -40f };
			foreach (float num in array)
			{
				Transform obj = Primitive((PrimitiveType)3, new Vector3(0.011f * size, 0.07f * size, 0.004f), RuneDim);
				obj.SetParent(transform, false);
				obj.localRotation = Quaternion.Euler(0f, 0f, num);
			}
			_pieces.Add((transform, pos, rot));
		}

		private Light AddLight(Transform at, LightType type, float range, float intensity)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("light");
			val.transform.SetParent(at, false);
			Light obj = val.AddComponent<Light>();
			obj.type = type;
			obj.color = RuneBright;
			obj.range = range;
			obj.intensity = intensity;
			obj.shadows = (LightShadows)0;
			return obj;
		}

		private void Animate(bool siren)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_helmModel) && Time.time > _nextHelmLook)
			{
				_nextHelmLook = Time.time + 1f;
				if (Object.op_Implicit((Object)(object)_head))
				{
					_helmModel = WardenModels.PinTo(_head, "helm");
				}
				if (Object.op_Implicit((Object)(object)_helmModel) && Object.op_Implicit((Object)(object)_beacon))
				{
					((Component)_beacon).GetComponent<Renderer>().enabled = false;
				}
			}
			foreach (var (val, func, func2) in _pieces)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					val.position = func();
					val.rotation = func2();
				}
			}
			float num = (siren ? 6f : 2f);
			float num2 = 0.5f + 0.5f * Mathf.Sin(Time.time * num);
			float brightness = (siren ? (3f + 5f * num2) : (1.2f + 2.8f * num2));
			foreach (Material runeMat in _runeMats)
			{
				if (Object.op_Implicit((Object)(object)runeMat) && (Object)(object)runeMat != (Object)(object)_beaconMat)
				{
					SetGlow(runeMat, RuneBright, brightness);
				}
			}
			if (Object.op_Implicit((Object)(object)_chestLight))
			{
				_chestLight.intensity = 0.3f + 0.7f * num2 * (siren ? 2f : 1f);
			}
			if (Object.op_Implicit((Object)(object)_beaconMat))
			{
				SetGlow(_beaconMat, RuneBright, siren ? (6f + 6f * num2) : 0.4f);
			}
			if (Object.op_Implicit((Object)(object)_spinner))
			{
				_spinner.localRotation = Quaternion.Euler(0f, siren ? (Time.time * 540f % 360f) : 0f, 0f);
			}
			if (Object.op_Implicit((Object)(object)_beaconSpot))
			{
				_beaconSpot.intensity = (siren ? 6f : 0f);
			}
			if (Object.op_Implicit((Object)(object)_beaconLight))
			{
				_beaconLight.intensity = (siren ? (1.5f + 2.5f * num2) : 0f);
			}
			Color val2 = Color.white * (siren ? (3f + 6f * num2) : (0.8f + 1.4f * num2));
			if (Object.op_Implicit((Object)(object)_helmModel) && Object.op_Implicit((Object)(object)WardenModels.Helm?.Material))
			{
				WardenModels.Helm.Material.SetColor("_EmissionColor", val2);
			}
			if (Object.op_Implicit((Object)(object)WardenModels.Club?.Material))
			{
				WardenModels.Club.Material.SetColor("_EmissionColor", val2);
			}
			foreach (Material value in WardenSkinned.Materials.Values)
			{
				if (Object.op_Implicit((Object)(object)value))
				{
					value.SetColor("_EmissionColor", val2);
				}
			}
		}

		private void Bubbles(ZDOID id, bool siren)
		{
			//IL_007f: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Chat.instance) || Time.time < _nextBubble)
			{
				return;
			}
			(string, float) value;
			if (siren)
			{
				if (Mathf.FloorToInt(Time.time * 2f) % 2 == 0)
				{
					Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 2.3f, 40f, 0.5f, "", "<color=#ff3030>WEE WOO</color>", true);
				}
				_nextBubble = Time.time + 0.5f;
			}
			else if (Shamed.TryGetValue(id, out value) && Time.time < value.Item2)
			{
				Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 2.3f, 40f, 2.2f, "", "<color=#ff3030>" + value.Item1 + "</color>", true);
				_nextBubble = Time.time + 2f;
			}
		}
	}
	internal static class WardenItems
	{
		public const string Regalia = "BH_WardenRegalia";

		public const string Helm = "BH_WardenHelm";

		public const string Legs = "BH_WardenLegs";

		public const string Club = "BH_WardenClub";

		public static ConfigEntry<string> Tint;

		private static readonly Dictionary<Material, Material> Cache = new Dictionary<Material, Material>();

		public static int RegaliaHash => StringExtensionMethods.GetStableHashCode("BH_WardenRegalia");

		public static int HelmHash => StringExtensionMethods.GetStableHashCode("BH_WardenHelm");

		public static int LegsHash => StringExtensionMethods.GetStableHashCode("BH_WardenLegs");

		public static void Init(ConfigFile cfg)
		{
			Tint = cfg.Bind<string>("Realm Warden", "Tint", "#6E4636", "Colour multiplied into the Warden's armour (hex). Darker = closer to the concept art's leather and iron.");
			WardenModels.Bind(cfg);
			PrefabManager.OnVanillaPrefabsAvailable += Add;
		}

		private static void Add()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00d5: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			PrefabManager.OnVanillaPrefabsAvailable -= Add;
			Color val2 = default(Color);
			Color val = (Color)(ColorUtility.TryParseHtmlString(Tint.Value, ref val2) ? val2 : new Color(0.43f, 0.27f, 0.21f));
			AddArmour("BH_WardenRegalia", "ArmorCarapaceChest", "Realm Warden Regalia", "The full uniform of the Realm Warden. Same laws, different shores: contraband is contraband.", val);
			AddArmour("BH_WardenHelm", "HelmetCarapace", "Realm Warden Beacon Hat", "Worn with the Regalia.", val);
			AddArmour("BH_WardenLegs", "ArmorCarapaceLegs", "Realm Warden Greaves", "Worn with the Regalia.", val);
			CustomItem val3 = new CustomItem("BH_WardenClub", "Club");
			SharedData shared = val3.ItemDrop.m_itemData.m_shared;
			shared.m_name = "Warden's Billy Club";
			shared.m_description = "Does no harm. Staggers the guilty and marks them OFFENDER for all to see.";
			shared.m_damages = default(DamageTypes);
			shared.m_attackForce = 120f;
			shared.m_useDurability = false;
			Recolour(val3.ItemPrefab, val * 0.8f);
			WardenModels.Apply(val3.ItemPrefab, "club");
			SetIcon(shared, "icon_club");
			ItemManager.Instance.AddItem(val3);
			WardenSearch.AddPrefab();
			Plugin.Log.LogInfo((object)"Realm Warden items added.");
		}

		private static void AddArmour(string name, string basePrefab, string display, string description, Color tint)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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_008c: Invalid comparison between Unknown and I4
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			CustomItem val = new CustomItem(name, basePrefab);
			SharedData shared = val.ItemDrop.m_itemData.m_shared;
			shared.m_name = display;
			shared.m_description = description;
			shared.m_setName = "";
			shared.m_setSize = 0;
			shared.m_equipStatusEffect = null;
			shared.m_useDurability = false;
			if (Object.op_Implicit((Object)(object)shared.m_armorMaterial))
			{
				shared.m_armorMaterial = Tinted(shared.m_armorMaterial, tint);
			}
			if (name == "BH_WardenRegalia" && WardenSkinned.Has("warden_coat") && (int)SystemInfo.graphicsDeviceType != 4)
			{
				shared.m_armorMaterial = null;
				Renderer[] componentsInChildren = val.ItemPrefab.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					if ((Object)(object)((Component)val2).transform != (Object)(object)val.ItemPrefab.transform && (Object)(object)((Component)val2).transform.parent != (Object)(object)val.ItemPrefab.transform)
					{
						val2.enabled = false;
					}
				}
				foreach (Transform item in val.ItemPrefab.transform)
				{
					Transform val3 = item;
					if (((Object)val3).name.StartsWith("attach"))
					{
						componentsInChildren = ((Component)val3).GetComponentsInChildren<Renderer>(true);
						for (int i = 0; i < componentsInChildren.Length; i++)
						{
							componentsInChildren[i].enabled = false;
						}
					}
				}
			}
			Recolour(val.ItemPrefab, tint);
			if (name == "BH_WardenRegalia")
			{
				SetIcon(shared, "icon_regalia");
			}
			ItemManager.Instance.AddItem(val);
		}

		private static void SetIcon(SharedData s, string asset)
		{
			Sprite val = WardenModels.LoadIcon(asset);
			if (Object.op_Implicit((Object)(object)val))
			{
				s.m_icons = (Sprite[])(object)new Sprite[1] { val };
			}
		}

		private static void Recolour(GameObject prefab, Color tint)
		{
			//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)
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!(val is ParticleSystemRenderer))
				{
					val.sharedMaterials = val.sharedMaterials.Select((Material m) => (!Object.op_Implicit((Object)(object)m)) ? m : Tinted(m, tint)).ToArray();
				}
			}
		}

		private static Material Tinted(Material m, Color tint)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (Cache.TryGetValue(m, out var value))
			{
				return value;
			}
			Material val = new Material(m)
			{
				name = ((Object)m).name + "_warden"
			};
			if (val.HasProperty("_Color"))
			{
				val.color *= tint;
			}
			Cache[m] = val;
			return val;
		}
	}
	internal class ModelPlacer : MonoBehaviour
	{
		public string Key;

		private void Start()
		{
			if (Key != null && WardenModels.Parts.TryGetValue(Key, out var value))
			{
				WardenModels.Place(((Component)this).transform, value);
			}
		}
	}
	internal static class WardenModels
	{
		public class Part
		{
			public string Asset;

			public string ChildName;

			public ConfigEntry<string> Offset;

			public ConfigEntry<string> Rotation;

			public ConfigEntry<float> Size;

			public ConfigEntry<string> Stretch;

			public Material Material;

			public GameObject TemplateObject;
		}

		public static readonly Dictionary<string, Part> Parts = new Dictionary<string, Part>();

		public static ConfigEntry<float> Brightness;

		public static ConfigEntry<float> Shine;

		public static ConfigEntry<float> Contrast;

		private static readonly Dictionary<Texture2D, Color32[]> Originals = new Dictionary<Texture2D, Color32[]>();

		private static float _appliedContrast = 1f;

		private static readonly List<Material> AllMaterials = new List<Material>();

		public static Part Helm
		{
			get
			{
				if (!Parts.TryGetValue("helm", out var value))
				{
					return null;
				}
				return value;
			}
		}

		public static Part Club
		{
			get
			{
				if (!Parts.TryGetValue("club", out var value))
				{
					return null;
				}
				return value;
			}
		}

		private static string AssetsDir => Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location), "assets");

		public static void Bind(ConfigFile cfg)
		{
			Add(cfg, "helm", "warden_helm", "0,-0.1525,-0.002", "0,0,0", 0.3352f, "Helmet model on the head (offset x,y,z metres; y is up)", "Helmet width in metres");
			Add(cfg, "club", "warden_club", "0.02,-0.04,-0.18", "90,0,0", 0.136f, "Billy club model in the hand (offset x,y,z metres)", "Club thickness in metres");
			Brightness = cfg.Bind<float>("Realm Warden Model", "Brightness", 0.5f, "Multiplies the colour of the Warden models (1 = as textured; lower = darker). The wardenlook command changes it live.");
			Shine = cfg.Bind<float>("Realm Warden Model", "Shine", 0.3f, "How shiny the Warden models are (0 = matte, 1 = polished).");
			Contrast = cfg.Bind<float>("Realm Warden Model", "Contrast", 1.5f, "Contrast of the Warden models' colours (1 = as textured; higher = punchier darks and lights; lower = flatter).");
		}

		public static void ApplyLook()
		{
			foreach (Material allMaterial in AllMaterials)
			{
				if (Object.op_Implicit((Object)(object)allMaterial))
				{
					Look(allMaterial);
				}
			}
			if (Mathf.Approximately(_appliedContrast, Contrast.Value))
			{
				return;
			}
			foreach (Texture2D key in Originals.Keys)
			{
				Recontrast(key);
			}
			_appliedContrast = Contrast.Value;
		}

		private static void Recontrast(Texture2D tex)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			if (Object.op_Implicit((Object)(object)tex) && Originals.TryGetValue(tex, out var value))
			{
				float value2 = Contrast.Value;
				byte[] array = new byte[256];
				for (int i = 0; i < 256; i++)
				{
					array[i] = (byte)Mathf.Clamp(Mathf.RoundToInt(((float)i - 128f) * value2 + 128f), 0, 255);
				}
				Color32[] array2 = (Color32[])(object)new Color32[value.Length];
				for (int j = 0; j < value.Length; j++)
				{
					Color32 val = value[j];
					array2[j] = new Color32(array[val.r], array[val.g], array[val.b], val.a);
				}
				tex.SetPixels32(array2);
				tex.Apply(true);
			}
		}

		private static void Look(Material m)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			m.color = new Color(Brightness.Value, Brightness.Value, Brightness.Value, 1f);
			m.SetFloat("_Glossiness", Shine.Value);
			m.SetFloat("_Metallic", 0f);
		}

		private static void Add(ConfigFile cfg, string key, string asset, string offset, string rotation, float size, string what, string sizeWhat)
		{
			string text = "Realm Warden Model";
			string text2 = char.ToUpper(key[0]) + key.Substring(1);
			Parts[key] = new Part
			{
				Asset = asset,
				ChildName = "Blyssheim_" + asset,
				Offset = cfg.Bind<string>(text, text2 + "Offset", offset, what + "."),
				Rotation = cfg.Bind<string>(text, text2 + "Rotation", rotation, text2 + " model rotation (degrees x,y,z)."),
				Size = cfg.Bind<float>(text, text2 + "Scale", size, sizeWhat + "."),
				Stretch = cfg.Bind<string>(text, text2 + "Stretch", "1,1,1", text2 + " model stretch: width, height, depth multipliers (1 = unchanged).")
			};
		}

		public static Vector3 ParseVec(string s)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			string[] p = s.Split(',');
			return new Vector3(F(0), F(1), F(2));
			float F(int i)
			{
				if (p.Length <= i || !float.TryParse(p[i].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					return 0f;
				}
				return result;
			}
		}

		public static void Apply(GameObject prefab, string key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				return;
			}
			Part part = Parts[key];
			Mesh val = LoadMesh(Path.Combine(AssetsDir, part.Asset + ".bhm"));
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Model " + part.Asset + " not found; keeping the vanilla look."));
				return;
			}
			Transform val2 = prefab.transform.Find("attach");
			if (!Object.op_Implicit((Object)(object)val2))
			{
				Plugin.Log.LogWarning((object)(((Object)prefab).name + " has no 'attach'; keeping the vanilla look."));
				return;
			}
			Renderer[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			foreach (Transform item in val2)
			{
				((Component)item).gameObject.SetActive(false);
			}
			part.Material = BuildMaterial(part.Asset);
			GameObject val3 = new GameObject(part.ChildName);
			val3.transform.SetParent(val2, false);
			val3.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterial = part.Material;
			val3.AddComponent<ModelPlacer>().Key = key;
			Place(val3.transform, part);
			Plugin.Log.LogInfo((object)$"Model {part.Asset} on {((Object)prefab).name} ({val.triangles.Length / 3} triangles; attach scale {val2.lossyScale}).");
		}

		public static GameObject Template(string key)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			Part part = Parts[key];
			if (Object.op_Implicit((Object)(object)part.TemplateObject))
			{
				return part.TemplateObject;
			}
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				return null;
			}
			Mesh val = LoadMesh(Path.Combine(AssetsDir, part.Asset + ".bhm"));
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Model " + part.Asset + " not found."));
				return null;
			}
			part.Material = (Object.op_Implicit((Object)(object)part.Material) ? part.Material : BuildMaterial(part.Asset));
			GameObject val2 = new GameObject(part.ChildName);
			val2.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val2);
			val2.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = part.Material;
			val2.AddComponent<ModelPlacer>().Key = key;
			part.TemplateObject = val2;
			Plugin.Log.LogInfo((object)$"Model {part.Asset} ready to pin ({val.triangles.Length / 3} triangles).");
			return val2;
		}

		public static Transform PinTo(Transform bone, string key)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Part part = Parts[key];
			foreach (Transform item in bone)
			{
				Transform val = item;
				if (((Object)val).name.StartsWith(part.ChildName))
				{
					return val;
				}
			}
			GameObject val2 = Template(key);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(val2, bone, false);
			((Object)obj).name = part.ChildName;
			obj.SetActive(true);
			Place(obj.transform, part);
			return obj.transform;
		}

		public static void Place(Transform t, Part part)
		{
			//IL_001a: 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_001f: 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_0037: 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_0058: 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_0073: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_009b: 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)
			Vector3 val = (Object.op_Implicit((Object)(object)t.parent) ? t.parent.lossyScale : Vector3.one);
			float num = (Mathf.Approximately(val.x, 0f) ? 1f : (1f / val.x));
			t.localPosition = ParseVec(part.Offset.Value) * num;
			t.localRotation = Quaternion.Euler(ParseVec(part.Rotation.Value));
			Vector3 val2 = ParseVec(part.Stretch.Value);
			if (val2 == Vector3.zero)
			{
				val2 = Vector3.one;
			}
			t.localScale = Vector3.Scale(val2, Vector3.one * part.Size.Value * num);
		}

		public static void PlaceAll(Part part)
		{
			Transform[] array = Resources.FindObjectsOfTypeAll<Transform>();
			foreach (Transform val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && ((Object)val).name.StartsWith(part.ChildName))
				{
					Place(val, part);
				}
			}
		}

		private static Mesh LoadMesh(string path)
		{
			//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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			if (!File.Exists(path))
			{
				return null;
			}
			BinaryReader r = new BinaryReader(File.OpenRead(path));
			try
			{
				if (new string(r.ReadChars(4)) != "BHM1")
				{
					return null;
				}
				int num = r.ReadInt32();
				int num2 = r.ReadInt32();
				Vector3[] vertices = V(num);
				Vector3[] normals = V(num);
				Vector2[] array = (Vector2[])(object)new Vector2[num];
				for (int i = 0; i < num; i++)
				{
					array[i] = new Vector2(r.ReadSingle(), r.ReadSingle());
				}
				int[] array2 = new int[num2];
				for (int j = 0; j < num2; j++)
				{
					array2[j] = r.ReadInt32();
				}
				Mesh val = new Mesh
				{
					name = Path.GetFileNameWithoutExtension(path)
				};
				if (num > 65000)
				{
					val.indexFormat = (IndexFormat)1;
				}
				val.vertices = vertices;
				val.normals = normals;
				val.uv = array;
				val.triangles = array2;
				val.RecalculateBounds();
				val.RecalculateTangents();
				return val;
			}
			finally
			{
				if (r != null)
				{
					((IDisposable)r).Dispose();
				}
			}
			Vector3[] V(int count)
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				Vector3[] array3 = (Vector3[])(object)new Vector3[count];
				for (int k = 0; k < count; k++)
				{
					array3[k] = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
				}
				return array3;
			}
		}

		private static Texture2D LoadTexture(string path, bool linear)
		{
			//IL_000f: 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_0020: Expected O, but got Unknown
			//IL_0022: Expected O, but got Unknown
			if (!File.Exists(path))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear);
			ImageConversion.LoadImage(val, File.ReadAllBytes(path));
			return val;
		}

		private static Texture2D ToNormalMap(Texture2D src)
		{
			//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_001a: 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_0026: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			Color32[] pixels = src.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				Color32 val = pixels[i];
				pixels[i] = new Color32(byte.MaxValue, val.g, val.g, val.r);
			}
			Texture2D val2 = new Texture2D(((Texture)src).width, ((Texture)src).height, (TextureFormat)4, true, true);
			val2.SetPixels32(pixels);
			val2.Apply(true);
			Object.Destroy((Object)(object)src);
			return val2;
		}

		public static Material BuildMaterialFor(string name)
		{
			return BuildMaterial(name);
		}

		public static Sprite LoadIcon(string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				return null;
			}
			Texture2D val = LoadTexture(Path.Combine(AssetsDir, name + ".png"), linear: false);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		private static Material BuildMaterial(string name)
		{
			//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)
			//IL_0044: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			Material val = new Material(Array.Find(Resources.FindObjectsOfTypeAll<Shader>(), (Shader s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == "Standard") ?? Shader.Find("Standard"))
			{
				name = name
			};
			Texture2D val2 = LoadTexture(Path.Combine(AssetsDir, name + "_color.png"), linear: false);
			if (Object.op_Implicit((Object)(object)val2))
			{
				Originals[val2] = val2.GetPixels32();
				if (!Mathf.Approximately(Contrast.Value, 1f))
				{
					Recontrast(val2);
				}
				_appliedContrast = Contrast.Value;
				val.SetTexture("_MainTex", (Texture)(object)val2);
			}
			Texture2D val3 = LoadTexture(Path.Combine(AssetsDir, name + "_normal.png"), linear: true);
			if (Object.op_Implicit((Object)(object)val3))
			{
				val.SetTexture("_BumpMap", (Texture)(object)ToNormalMap(val3));
				val.EnableKeyword("_NORMALMAP");
			}
			Texture2D val4 = LoadTexture(Path.Combine(AssetsDir, name + "_glow.png"), linear: false);
			if (Object.op_Implicit((Object)(object)val4))
			{
				val.SetTexture("_EmissionMap", (Texture)(object)val4);
				val.EnableKeyword("_EMISSION");
				val.SetColor("_EmissionColor", Color.white * 1.5f);
			}
			Look(val);
			AllMaterials.Add(val);
			return val;
		}
	}
	internal static class WardenNet
	{
		[HarmonyPatch(typeof(Humanoid), "StartAttack")]
		private static class ClubSwing
		{
			private static void Postfix(Humanoid __instance, bool __result)
			{
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Expected O, but got Unknown
				if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					ItemData currentWeapon = __instance.GetCurrentWeapon();
					if (!((Object)(object)currentWeapon?.m_dropPrefab == (Object)null) && !(((Object)currentWeapon.m_dropPrefab).name != "BH_WardenClub"))
					{
						((MonoBehaviour)Plugin.Instance).StartCoroutine(Bonk((Player)__instance));
					}
				}
			}
		}

		private class WardenCommand : ConsoleCommand
		{
			public override string Name => "warden";

			public override string Help => "Admins: receive the Realm Warden Regalia and billy club.";

			public override void Run(string[] args)
			{
				AskServer("warden", 0f);
			}
		}

		private class ModelCommand : ConsoleCommand
		{
			private readonly string _key;

			public override string Name => "warden" + _key;

			public override string Help => "Adjust the Warden " + _key + " model live: warden" + _key + " <x> <y> <z> [size] [rotX rotY rotZ]   (no arguments shows the current values)";

			public ModelCommand(string key)
			{
				_key = key;
			}

			public override void Run(string[] args)
			{
				WardenModels.Part part = WardenModels.Parts[_key];
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				if (args.Length >= 3)
				{
					part.Offset.Value = args[0] + "," + args[1] + "," + args[2];
				}
				if (args.Length >= 4 && float.TryParse(args[3], NumberStyles.Float, invariantCulture, out var result))
				{
					part.Size.Value = result;
				}
				if (args.Length >= 7)
				{
					part.Rotation.Value = args[4] + "," + args[5] + "," + args[6];
				}
				WardenModels.PlaceAll(part);
				Console.instance.Print("warden" + _key + " " + part.Offset.Value.Replace(",", " ") + " " + part.Size.Value.ToString("0.###", invariantCulture) + " " + part.Rotation.Value.Replace(",", " "));
			}
		}

		private class DebugCommand : ConsoleCommand
		{
			public override string Name => "wardendebug";

			public override string Help => "Writes what is attached to your head (and where) to the log, for fixing the Warden helmet.";

			public override void Run(string[] args)
			{
				//IL_0066: 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_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: 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_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_010c: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: Unknown result type (might be due to invalid IL or missing references)
				//IL_018e: 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_0197: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_01af: Unknown result type (might be due to invalid IL or missing references)
				Player localPlayer = Player.m_localPlayer;
				if (!Object.op_Implicit((Object)(object)localPlayer))
				{
					return;
				}
				Transform val = Array.Find(((Component)localPlayer).GetComponentsInChildren<Transform>(true), (Transform t) => ((Object)t).name == "Helmet_attach");
				if (!Object.op_Implicit((Object)(object)val))
				{
					Console.instance.Print("No Helmet_attach found.");
					return;
				}
				ManualLogSource log = Plugin.Log;
				object[] obj = new object[4] { val.position, val.lossyScale, null, null };
				Quaternion rotation = val.rotation;
				obj[2] = ((Quaternion)(ref rotation)).eulerAngles;
				obj[3] = ((Component)localPlayer).transform.position;
				log.LogInfo((object)string.Format("wardendebug: Helmet_attach world={0} lossyScale={1} rot={2} player={3}", obj));
				Transform[] componentsInChildren = ((Component)val).GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					Renderer component = ((Component)val2).GetComponent<Renderer>();
					MeshFilter component2 = ((Component)val2).GetComponent<MeshFilter>();
					ManualLogSource log2 = Plugin.Log;
					string text = $"  {((Object)val2).name} active={((Component)val2).gameObject.activeInHierarchy} local={val2.localPosition} scale={val2.localScale} lossy={val2.lossyScale} layer={((Component)val2).gameObject.layer}";
					object obj2;
					if (!Object.op_Implicit((Object)(object)component))
					{
						obj2 = "";
					}
					else
					{
						object[] obj3 = new object[5]
						{
							((object)component).GetType().Name,
							component.enabled,
							null,
							null,
							null
						};
						Bounds bounds = component.bounds;
						obj3[2] = ((Bounds)(ref bounds)).center;
						bounds = component.bounds;
						obj3[3] = ((Bounds)(ref bounds)).size;
						obj3[4] = (Object.op_Implicit((Object)(object)component.sharedMaterial) ? ((Object)component.sharedMaterial.shader).name : "none");
						obj2 = string.Format(" renderer={0} enabled={1} bounds={2}/{3} shader={4}", obj3);
					}
					log2.LogInfo((object)(text + (string?)obj2 + (Object.op_Implicit((Object)(object)component2) ? (" mesh=" + (Object.op_Implicit((Object)(object)component2.sharedMesh) ? (((Object)component2.sharedMesh).name + " v" + component2.sharedMesh.vertexCount) : "none")) : "")));
				}
				Console.instance.Print("Written to the log.");
			}
		}

		private class StretchCommand : ConsoleCommand
		{
			public override string Name => "wardenstretch";

			public override string Help => "Stretch a Warden model: wardenstretch <helm|club> <width> <height> <depth>   (1 = unchanged; e.g. wardenstretch helm 1 1.15 1)";

			public override void Run(string[] args)
			{
				if (args.Length < 1 || !WardenModels.Parts.TryGetValue(args[0], out var value))
				{
					Console.instance.Print(((ConsoleCommand)this).Help);
					return;
				}
				if (args.Length >= 4)
				{
					value.Stretch.Value = args[1] + "," + args[2] + "," + args[3];
				}
				WardenModels.PlaceAll(value);
				Console.instance.Print("wardenstretch " + args[0] + " " + value.Stretch.Value.Replace(",", " "));
			}
		}

		private class LookCommand : ConsoleCommand
		{
			public override string Name => "wardenlook";

			public override string Help => "Adjust how the Warden models look: wardenlook <brightness> [shine] [contrast]   (1 = as textured; no arguments shows the current values)";

			public override void Run(string[] args)
			{
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				if (args.Length >= 1 && float.TryParse(args[0], NumberStyles.Float, invariantCulture, out var result))
				{
					WardenModels.Brightness.Value = result;
				}
				if (args.Length >= 2 && float.TryParse(args[1], NumberStyles.Float, invariantCulture, out var result2))
				{
					WardenModels.Shine.Value = result2;
				}
				if (args.Length >= 3 && float.TryParse(args[2], NumberStyles.Float, invariantCulture, out var result3))
				{
					WardenModels.Contrast.Value = result3;
				}
				WardenModels.ApplyLook();
				Console.instance.Print("wardenlook " + WardenModels.Brightness.Value.ToString("0.##", invariantCulture) + " " + WardenModels.Shine.Value.ToString("0.##", invariantCulture) + " " + WardenModels.Contrast.Value.ToString("0.##", invariantCulture));
			}
		}

		private class PlaytimeCommand : ConsoleCommand
		{
			public override string Name => "playtime";

			public override string Help => "Admins: time each character has spent on this server.";

			public override void Run(string[] args)
			{
				AskServer("playtime", 0f);
			}
		}

		private class SirenCommand : ConsoleCommand
		{
			public override string Name => "siren";

			public override string Help => "Admins: set off the Realm Warden siren (test). Optional seconds.";

			public override void Run(string[] args)
			{
				AskServer("siren", (args.Length != 0 && float.TryParse(args[0], out var result)) ? result : SirenSeconds.Value);
			}
		}

		public const string SirenRpc = "Blyssheim_Siren";

		public const string ShameRpc = "Blyssheim_Shame";

		public static ConfigEntry<float> SirenSeconds;

		public static ConfigEntry<float> ShameSeconds;

		public static ConfigEntry<string> ShameWord;

		public static ConfigEntry<KeyboardShortcut> SirenKey;

		public const string AskRpc = "Blyssheim_AdminAsk";

		public const string GrantRpc = "Blyssheim_AdminGrant";

		public const string InfoRpc = "Blyssheim_Info";

		public static void Init(ConfigFile cfg)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			SirenSeconds = cfg.Bind<float>("Realm Warden", "SirenSeconds", 20f, "How long the siren (spinning beacon, WEE WOO) goes off after a catch.");
			ShameSeconds = cfg.Bind<float>("Realm Warden", "ShameSeconds", 60f, "How long OFFENDER stays over someone hit with the billy club.");
			ShameWord = cfg.Bind<string>("Realm Warden", "ShameWord", "OFFENDER", "The word over their head (try SHAME).");
			SirenKey = cfg.Bind<KeyboardShortcut>("Realm Warden", "SirenKey", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), "While wearing the Regalia: press to switch the siren (beacon and WEE WOO) on, again to switch it off.");
			Alerts.OnContraband += delegate
			{
				OnCatch();
			};
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new WardenCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SirenCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ModelCommand("helm"));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ModelCommand("club"));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DebugCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new LookCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new StretchCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new PlaytimeCommand());
		}

		public static void Register()
		{
			ZRoutedRpc.instance.Register<ZDOID, float>("Blyssheim_Siren", (Action<long, ZDOID, float>)delegate(long sender, ZDOID id, float secs)
			{
				//IL_001a: 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)
				if (secs <= 0f)
				{
					WardenFX.SirenUntil.Remove(id);
				}
				else
				{
					WardenFX.SirenUntil[id] = Time.time + secs;
				}
			});
			ZRoutedRpc.instance.Register<ZDOID, string, float>("Blyssheim_Shame", (Action<long, ZDOID, string, float>)OnShame);
			ZRoutedRpc.instance.Register<string, float>("Blyssheim_AdminAsk", (Action<long, string, float>)OnAsk);
			ZRoutedRpc.instance.Register<string, float, bool>("Blyssheim_AdminGrant", (Action<long, string, float, bool>)OnGrant);
			WardenSearch.Register();
			ZRoutedRpc.instance.Register<string>("Blyssheim_Info", (Action<long, string>)delegate(long sender, string text)
			{
				if (Object.op_Implicit((Object)(object)Console.instance))
				{
					string[] array = text.Split('\n');
					foreach (string text2 in array)
					{
						Console.instance.Print(text2);
					}
				}
				if (Object.op_Implicit((Object)(object)Chat.instance))
				{
					((Terminal)Chat.instance).AddString("<color=#ffcc66>Blyssheim</color>", text, (Type)0, true);
				}
			});
		}

		public static void AskServer(string action, float arg)
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				OnGrant(0L, action, arg, ok: true);
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(Rpc.ServerPeerId(), "Blyssheim_AdminAsk", new object[2] { action, arg });
		}

		private static void OnAsk(long sender, string action, float arg)
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				ZNetPeer peer = ZNet.instance.GetPeer(sender);
				bool flag = peer != null && ZNet.instance.IsAdmin(peer.m_socket.GetHostName());
				if (action == "playtime")
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Blyssheim_Info", new object[1] { flag ? ServerWatch.PlaytimeReport() : "Only admins can see playtime." });
					return;
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Blyssheim_AdminGrant", new object[3] { action, arg, flag });
			}
		}

		private static void OnGrant(long sender, string action, float arg, bool ok)
		{
			if (action == "whoami")
			{
				WardenAccess.AdminConfirmed = ok;
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			if (!ok)
			{
				Say("Only admins can be the Realm Warden.");
				return;
			}
			if (!(action == "warden"))
			{
				if (action == "siren")
				{
					Siren(arg);
				}
				return;
			}
			string[] array = new string[2] { "BH_WardenRegalia", "BH_WardenClub" };
			foreach (string text in array)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
				if (Object.op_Implicit((Object)(object)itemPrefab))
				{
					((Humanoid)localPlayer).GetInventory().AddItem(itemPrefab, 1);
				}
			}
			Say("The Realm Warden is on duty.");
			static void Say(string s)
			{
				if (Object.op_Implicit((Object)(object)Console.instance))
				{
					Console.instance.Print(s);
				}
				if (Object.op_Implicit((Object)(object)MessageHud.instance))
				{
					MessageHud.instance.ShowMessage((MessageType)1, s, 0, (Sprite)null, false, true);
				}
			}
		}

		private static void OnCatch()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			ItemData val = ((IEnumerable<ItemData>)((Humanoid)localPlayer).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => Object.op_Implicit((Object)(object)i.m_dropPrefab) && ((Object)i.m_dropPrefab).name == "BH_WardenRegalia"));
			if (val != null)
			{
				if (!((Humanoid)localPlayer).IsItemEquiped(val))
				{
					((Humanoid)localPlayer).EquipItem(val, true);
				}
				Siren(SirenSeconds.Value);
			}
		}

		public static void Siren(float seconds)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Blyssheim_Siren", new object[2]
				{
					((Character)localPlayer).GetZDOID(),
					seconds
				});
			}
		}

		public static void Tick()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				KeyboardShortcut value = SirenKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && WardenVisuals.IsWarden(((Component)localPlayer).GetComponent<VisEquipment>()))
				{
					Siren((WardenFX.SirenUntil.TryGetValue(((Character)localPlayer).GetZDOID(), out var value2) && Time.time < value2) ? 0f : 3600f);
				}
			}
		}

		private static void OnShame(long sender, ZDOID id, string word, float seconds)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			WardenFX.Shamed[id] = (word, Time.time + seconds);
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && ((Character)localPlayer).GetZDOID() == id && Object.op_Implicit((Object)(object)MessageHud.instance))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "<color=#ff3030>" + word + "</color>", 0, (Sprite)null, false, true);
			}
		}

		private static IEnumerator Bonk(Player warden)
		{
			yield return (object)new WaitForSeconds(0.35f);
			if (!Object.op_Implicit((Object)(object)warden))
			{
				yield break;
			}
			Vector3 val = ((Component)warden).transform.position + Vector3.up;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!Object.op_Implicit((Object)(object)allPlayer) || (Object)(object)allPlayer == (Object)(object)warden || ((Character)allPlayer).IsDead())
				{
					continue;
				}
				Vector3 val2 = ((Component)allPlayer).transform.position + Vector3.up - val;
				if (!(((Vector3)(ref val2)).magnitude > 2.8f) && !(Vector3.Angle(((Component)warden).transform.forward, new Vector3(val2.x, 0f, val2.z)) > 70f))
				{
					((Character)allPlayer).Stagger(((Vector3)(ref val2)).normalized);
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Blyssheim_Shame", new object[3]
					{
						((Character)allPlayer).GetZDOID(),
						ShameWord.Value,
						ShameSeconds.Value
					});
					if (WardenAccess.Active())
					{
						WardenSearch.Request(allPlayer);
						break;
					}
				}
			}
		}
	}
	internal static class WardenSearch
	{
		[HarmonyPatch(typeof(ItemDrop), "DropItem")]
		private static class NoCopiesOnTheGround
		{
			private static void Postfix(ItemData item, ItemDrop __result)
			{
				if (Object.op_Implicit((Object)(object)__result) && MarkOf(item) != null)
				{
					ZNetScene.instance.Destroy(((Component)__result).gameObject);
				}
			}
		}

		public const string Prefab = "BH_EvidenceView";

		private const string Marker = "blyssheim_evidence";

		private const string SearchReq = "Blyssheim_SearchReq";

		private const string Search = "Blyssheim_Search";

		private const string SearchResult = "Blyssheim_SearchResult";

		private const string SearchView = "Blyssheim_SearchView";

		private const string SeizeReq = "Blyssheim_SeizeReq";

		private const string Seize = "Blyssheim_Seize";

		private static Container _view;

		private static long _target;

		private static string _targetName;

		private static readonly Dictionary<string, (string Name, int X, int Y, int Stack)> Mirror = new Dictionary<string, (string, int, int, int)>();

		private static bool IsServer
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		private static long Server => Rpc.ServerPeerId();

		public static void AddPrefab()
		{
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("BH_EvidenceView", "piece_chest_wood");
			if (!Object.op_Implicit((Object)(object)val))
			{
				Plugin.Log.LogWarning((object)"Evidence window: could not clone a chest.");
				return;
			}
			WearNTear[] componentsInChildren = val.GetComponentsInChildren<WearNTear>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			Collider[] componentsInChildren3 = val.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				componentsInChildren3[i].enabled = false;
			}
			ZNetView component = val.GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.m_persistent = false;
			}
			Container component2 = val.GetComponent<Container>();
			component2.m_width = 8;
			component2.m_height = 5;
			component2.m_name = "Evidence";
			PrefabManager.Instance.AddPrefab(val);
		}

		public static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			instance.Register<ZPackage>("Blyssheim_SearchReq", (Action<long, ZPackage>)OnSearchReq);
			instance.Register<ZPackage>("Blyssheim_Search", (Action<long, ZPackage>)OnSearch);
			instance.Register<ZPackage>("Blyssheim_SearchResult", (Action<long, ZPackage>)OnSearchResult);
			instance.Register<ZPackage>("Blyssheim_SearchView", (Action<long, ZPackage>)OnSearchView);
			instance.Register<ZPackage>("Blyssheim_SeizeReq", (Action<long, ZPackage>)OnSeizeReq);
			instance.Register<ZPackage>("Blyssheim_Seize", (Action<long, ZPackage>)OnSeize);
		}

		private static bool SenderIsAdmin(long sender)
		{
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer != null)
			{
				return ZNet.instance.IsAdmin(peer.m_socket.GetHostName());
			}
			return false;
		}

		public static void Request(Player target)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)target) && !IsServer && !Object.op_Implicit((Object)(object)_view))
			{
				ZPackage val = new ZPackage();
				ZDOID zDOID = ((Character)target).GetZDOID();
				val.Write(((ZDOID)(ref zDOID)).UserID);
				ZRoutedRpc.instance.InvokeRoutedRPC(Server, "Blyssheim_SearchReq", new object[1] { val });
			}
		}

		private static void OnSearchReq(long sender, ZPackage p)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (IsServer && SenderIsAdmin(sender))
			{
				long num = p.ReadLong();
				ZPackage val = new ZPackage();
				val.Write(sender);
				ZRoutedRpc.instance.InvokeRoutedRPC(num, "Blyssheim_Search", new object[1] { val });
			}
		}

		private static void OnSearch(long sender, ZPackage p)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (!IsServer && sender == Server && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				long num = p.ReadLong();
				ZPackage val = new ZPackage();
				((Humanoid)Player.m_localPlayer).GetInventory().Save(val);
				ZPackage val2 = new ZPackage();
				val2.Write(num);
				val2.Write(Player.m_localPlayer.GetPlayerName());
				val2.Write(val);
				ZRoutedRpc.instance.InvokeRoutedRPC(Server, "Blyssheim_SearchResult", new object[1] { val2 });
				if (Object.op_Implicit((Object)(object)MessageHud.instance))
				{
					MessageHud.instance.ShowMessage((MessageType)2, "<color=#ff4040>The Realm Warden searched you.</color>", 0, (Sprite)null, false, true);
				}
			}
		}

		private static void OnSearchResult(long sender, ZPackage p)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if (IsServer)
			{
				long num = p.ReadLong();
				string text = p.ReadString();
				ZPackage val = p.ReadPackage();
				if (SenderIsAdmin(num))
				{
					ZPackage val2 = new ZPackage();
					val2.Write(sender);
					val2.Write(text);
					val2.Write(val);
					ZRoutedRpc.instance.InvokeRoutedRPC(num, "Blyssheim_SearchView", new object[1] { val2 });
					ServerWatch.Log(text + " was searched by the Realm Warden");
				}
			}
		}

		private static void OnSearchView(long sender, ZPackage p)
		{
			//IL_006b: 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)
			if (IsServer || sender != Server || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || Object.op_Implicit((Object)(object)_view))
			{
				return;
			}
			_target = p.ReadLong();
			_targetName = p.ReadString();
			ZPackage val = p.ReadPackage();
			Player localPlayer = Player.m_localPlayer;
			GameObject prefab = ZNetScene.instance.GetPrefab("BH_EvidenceView");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return;
			}
			_view = Object.Instantiate<GameObject>(prefab, ((Component)localPlayer).transform.position, Quaternion.identity).GetComponent<Container>();
			_view.m_name = "Evidence: " + _targetName;
			Inventory inventory = _view.GetInventory();
			inventory.Load(val);
			Mirror.Clear();
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				string text = "e" + num++;
				allItem.m_customData = allItem.m_customData ?? new Dictionary<string, string>();
				allItem.m_customData["blyssheim_evidence"] = text;
				Mirror[text] = (Object.op_Implicit((Object)(object)allItem.m_dropPrefab) ? ((Object)allItem.m_dropPrefab).name : allItem.m_shared.m_name, allItem.m_gridPos.x, allItem.m_gridPos.y, allItem.m_stack);
			}
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnViewChanged));
			InventoryGui.instance.Show(_view, 1);
		}

		private static string MarkOf(ItemData it)
		{
			if (it?.m_customData == null || !it.m_customData.TryGetValue("blyssheim_evidence", out var value))
			{
				return null;
			}
			return value;
		}

		private static void OnViewChanged()
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_view))
			{
				return;
			}
			Dictionary<string, int> dictionary = (from i in _view.GetInventory().GetAllItems()
				where MarkOf(i) != null
				select i).GroupBy(MarkOf).ToDictionary((IGrouping<string, ItemData> g) => g.Key, (IGrouping<string, ItemData> g) => g.Sum((ItemData i) => i.m_stack));
			foreach (string item in Mirror.Keys.ToList())
			{
				(string, int, int, int) tuple = Mirror[item];
				dictionary.TryGetValue(item, out var value);
				if (value < tuple.Item4)
				{
					int num = tuple.Item4 - value;
					Mirror[item] = (tuple.Item1, tuple.Item2, tuple.Item3, value);
					ZPackage val = new ZPackage();
					val.Write(_target);
					val.Write(tuple.Item1);
					val.Write(tuple.Item2);
					val.Write(tuple.Item3);
					val.Write(num);
					val.Write(((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 0.8f + Vector3.up * 0.5f);
					ZRoutedRpc.instance.InvokeRoutedRPC(Server, "Blyssheim_SeizeReq", new object[1] { val });
				}
			}
		}

		public static void Tick()
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			foreach (ItemData item in (from i in inventory.GetAllItems()
				where MarkOf(i) != null
				select i).ToList())
			{
				inventory.RemoveItem(item);
			}
			if (!Object.op_Implicit((Object)(object)_view) || (Object.op_Implicit((Object)(object)InventoryGui.instance) && InventoryGui.IsVisible() && (Object)/*isinst with value type is only supported in some contexts*/ == (Object)(object)_view))
			{
				return;
			}
			foreach (ItemData item2 in (from i in _view.GetInventory().GetAllItems()
				where MarkOf(i) == null
				select i).ToList())
			{
				_view.GetInventory().RemoveItem(item2);
				if (!inventory.AddItem(item2))
				{
					ItemDrop.DropItem(item2, item2.m_stack, ((Component)localPlayer).transform.position + Vector3.up, Quaternion.identity);
				}
			}
			Inventory inventory2 = _view.GetInventory();
			inventory2.m_onChanged = (Action)Delegate.Remove(inventory2.m_onChanged, new Action(OnViewChanged));
			ZNetScene.instance.Destroy(((Component)_view).gameObject);
			_view = null;
			Mirror.Clear();
		}

		private static void OnSeizeReq(long sender, ZPackage p)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown resu