Decompiled source of PraetorisClient v0.1.3

PraetorisClient.dll

Decompiled a day 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.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PraetorisClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PraetorisClient")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3A303D15-4E60-4110-8EDF-EDF38560FBE2")]
[assembly: AssemblyFileVersion("0.1.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.3.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace PraetorisClient
{
	internal static class BotApiClient
	{
		public static IEnumerator PostLinkRoutine(LinkRequest link, Action<long, string, bool, string> sendResult)
		{
			string linkApiUrl = PraetorisClientPlugin.GetLinkApiUrl();
			string botApiKey = PraetorisClientPlugin.GetBotApiKey();
			if (string.IsNullOrWhiteSpace(linkApiUrl))
			{
				sendResult(link.Sender, link.RequestId, arg3: false, "Link API URL is not configured on the server.");
				yield break;
			}
			if (string.IsNullOrWhiteSpace(botApiKey))
			{
				sendResult(link.Sender, link.RequestId, arg3: false, "Bot API key is not configured on the server.");
				yield break;
			}
			string s = JsonLinkRequest(link);
			byte[] bytes = Encoding.UTF8.GetBytes(s);
			UnityWebRequest request = new UnityWebRequest(linkApiUrl, "POST")
			{
				uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes),
				downloadHandler = (DownloadHandler)new DownloadHandlerBuffer()
			};
			try
			{
				request.SetRequestHeader("Content-Type", "application/json");
				request.SetRequestHeader("X-API-Key", botApiKey);
				request.SetRequestHeader("User-Agent", "PraetorisClient/0.1");
				yield return request.SendWebRequest();
				string text = ((request.downloadHandler != null) ? request.downloadHandler.text : "");
				if ((int)request.result != 1 || request.responseCode < 200 || request.responseCode >= 300)
				{
					string text2 = ((!string.IsNullOrWhiteSpace(text)) ? text : (string.IsNullOrWhiteSpace(request.error) ? ("HTTP " + request.responseCode) : (request.error + " (HTTP " + request.responseCode + ")")));
					PraetorisClientPlugin.Log.LogWarning((object)("Discord link API failed for " + link.PlayerId + ": " + text2));
					sendResult(link.Sender, link.RequestId, arg3: false, text2);
				}
				else
				{
					string arg = (string.IsNullOrWhiteSpace(text) ? "Discord link complete." : text);
					PraetorisClientPlugin.Log.LogInfo((object)("Discord link API accepted " + link.PlayerId + "."));
					sendResult(link.Sender, link.RequestId, arg3: true, arg);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static string JsonLinkRequest(LinkRequest link)
		{
			return "{\"requestId\":\"" + EscapeJson(link.RequestId) + "\",\"code\":\"" + EscapeJson(link.Code) + "\",\"playerId\":\"" + EscapeJson(link.PlayerId) + "\",\"playerName\":\"" + EscapeJson(link.PlayerName) + "\",\"endpoint\":\"" + EscapeJson(link.Endpoint) + "\",\"platformDisplayName\":\"" + EscapeJson(link.PlatformDisplayName) + "\",\"receivedAtUtc\":\"" + EscapeJson(link.ReceivedAtUtc.ToString("O", CultureInfo.InvariantCulture)) + "\"}";
		}

		private static string EscapeJson(string value)
		{
			return (value ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r")
				.Replace("\n", "\\n");
		}
	}
	internal static class CreativeBiomeOverride
	{
		private sealed class OverrideZone
		{
			public Vector3 Center { get; }

			public float Radius { get; }

			public float RadiusSquared { get; }

			public Biome Biome { get; }

			public bool SuppressSpawns { get; }

			public OverrideZone(Vector3 center, float radius, Biome biome, bool suppressSpawns)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: 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)
				Center = center;
				Radius = radius;
				RadiusSquared = radius * radius;
				Biome = biome;
				SuppressSpawns = suppressSpawns;
			}

			public bool Contains(float x, float z)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				float num = x - Center.x;
				float num2 = z - Center.z;
				return num * num + num2 * num2 <= RadiusSquared;
			}
		}

		[HarmonyPatch(typeof(WorldGenerator), "GetBiome", new Type[]
		{
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(bool)
		})]
		private static class WorldGeneratorGetBiomePatch
		{
			private static bool Prefix(float wx, float wy, ref Biome __result)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Expected I4, but got Unknown
				if (!TryGetBiome(wx, wy, out var biome))
				{
					return true;
				}
				__result = (Biome)(int)biome;
				return false;
			}
		}

		[HarmonyPatch(typeof(Heightmap), "GetBiome", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(bool)
		})]
		private static class HeightmapGetBiomePatch
		{
			private static bool Prefix(Vector3 point, ref Biome __result)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Expected I4, but got Unknown
				if (!TryGetBiome(point.x, point.z, out var biome))
				{
					return true;
				}
				__result = (Biome)(int)biome;
				return false;
			}
		}

		[HarmonyPatch(typeof(Heightmap), "GetBiomeColor", new Type[]
		{
			typeof(float),
			typeof(float)
		})]
		private static class HeightmapGetBiomeColorPatch
		{
			private static bool Prefix(Heightmap __instance, float ix, float iy, ref Color __result)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				float num = (float)__instance.m_width * __instance.m_scale * 0.5f;
				Vector3 position = ((Component)__instance).transform.position;
				float x = position.x + (ix - 0.5f) * num * 2f;
				float z = position.z + (iy - 0.5f) * num * 2f;
				if (!TryGetBiome(x, z, out var biome))
				{
					return true;
				}
				__result = Color32.op_Implicit(Heightmap.GetBiomeColor(biome));
				return false;
			}
		}

		[HarmonyPatch(typeof(WorldGenerator), "IsAshlands")]
		private static class WorldGeneratorIsAshlandsPatch
		{
			private static bool Prefix(float x, float y, ref bool __result)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Invalid comparison between Unknown and I4
				if (!TryGetBiome(x, y, out var biome))
				{
					return true;
				}
				__result = (int)biome == 32;
				return false;
			}
		}

		[HarmonyPatch(typeof(WorldGenerator), "IsDeepnorth")]
		private static class WorldGeneratorIsDeepnorthPatch
		{
			private static bool Prefix(float x, float y, ref bool __result)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Invalid comparison between Unknown and I4
				if (!TryGetBiome(x, y, out var biome))
				{
					return true;
				}
				__result = (int)biome == 64;
				return false;
			}
		}

		[HarmonyPatch(typeof(SpawnSystem), "IsSpawnPointGood")]
		private static class SpawnSystemIsSpawnPointGoodPatch
		{
			private static bool Prefix(ref Vector3 spawnPoint, ref bool __result)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				if (!ContainsSpawnBlockedZone(spawnPoint))
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		private const int ProtocolVersion = 1;

		private static readonly Dictionary<string, OverrideZone> Zones = new Dictionary<string, OverrideZone>();

		private static readonly FieldInfo? HeightmapBuildDataField = AccessTools.Field(typeof(Heightmap), "m_buildData");

		public static void OnOverride(long sender, ZPackage pkg)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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)
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				int num = pkg.ReadInt();
				if (num != 1)
				{
					PraetorisClientPlugin.Log.LogWarning((object)$"Ignoring creative biome override version {num}; expected {1}.");
					return;
				}
				int num2 = pkg.ReadInt();
				if (num2 <= 0)
				{
					ClearAll();
					return;
				}
				for (int i = 0; i < num2; i++)
				{
					string text = pkg.ReadString();
					bool num3 = pkg.ReadBool();
					Vector3 center = pkg.ReadVector3();
					float num4 = pkg.ReadSingle();
					Biome val = (Biome)pkg.ReadInt();
					bool suppressSpawns = ((num2 == 1 && pkg.GetPos() < pkg.Size()) ? pkg.ReadBool() : (!text.StartsWith("siege_", StringComparison.OrdinalIgnoreCase)));
					if (!num3 || (int)val == 0 || num4 <= 0f)
					{
						Remove(text);
					}
					else
					{
						Set(text, center, num4, val, suppressSpawns);
					}
				}
			}
			catch (Exception arg)
			{
				PraetorisClientPlugin.Log.LogWarning((object)$"Failed to apply creative biome override: {arg}");
			}
		}

		public static bool TryGetBiome(float x, float z, out Biome biome)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			foreach (OverrideZone value in Zones.Values)
			{
				if (value.Contains(x, z))
				{
					biome = (Biome)(int)value.Biome;
					return true;
				}
			}
			biome = (Biome)0;
			return false;
		}

		public static bool ContainsSpawnBlockedZone(Vector3 point)
		{
			//IL_0023: 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)
			foreach (OverrideZone value in Zones.Values)
			{
				if (value.SuppressSpawns && value.Contains(point.x, point.z))
				{
					return true;
				}
			}
			return false;
		}

		private static void Set(string zoneId, Vector3 center, float radius, Biome biome, bool suppressSpawns)
		{
			//IL_0015: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			zoneId = NormalizeZoneId(zoneId);
			OverrideZone value;
			bool num = Zones.TryGetValue(zoneId, out value);
			OverrideZone overrideZone = new OverrideZone(center, radius, biome, suppressSpawns);
			Zones[zoneId] = overrideZone;
			if (num)
			{
				RefreshTerrain(value);
			}
			RefreshTerrain(overrideZone);
			PraetorisClientPlugin.Log.LogInfo((object)$"Creative biome override {zoneId}: {biome} at {center.x:0.##},{center.z:0.##} radius {radius:0.##}, suppressSpawns={suppressSpawns}.");
		}

		private static void Remove(string zoneId)
		{
			zoneId = NormalizeZoneId(zoneId);
			if (Zones.TryGetValue(zoneId, out OverrideZone value))
			{
				Zones.Remove(zoneId);
				RefreshTerrain(value);
				PraetorisClientPlugin.Log.LogInfo((object)("Removed creative biome override " + zoneId + "."));
			}
		}

		private static void ClearAll()
		{
			if (Zones.Count == 0)
			{
				return;
			}
			List<OverrideZone> list = new List<OverrideZone>(Zones.Values);
			Zones.Clear();
			foreach (OverrideZone item in list)
			{
				RefreshTerrain(item);
			}
			PraetorisClientPlugin.Log.LogInfo((object)"Cleared creative biome overrides.");
		}

		private static void RefreshTerrain(OverrideZone zone)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Heightmap allHeightmap in Heightmap.GetAllHeightmaps())
			{
				if (!((Object)(object)allHeightmap == (Object)null) && Intersects(allHeightmap, zone))
				{
					HeightmapBuildDataField?.SetValue(allHeightmap, null);
					allHeightmap.Poke(false);
				}
			}
			if ((Object)(object)ClutterSystem.instance != (Object)null)
			{
				ClutterSystem.instance.ResetGrass(zone.Center, zone.Radius);
			}
		}

		private static bool Intersects(Heightmap heightmap, OverrideZone zone)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			float num = (float)heightmap.m_width * heightmap.m_scale * 0.5f;
			Vector3 position = ((Component)heightmap).transform.position;
			float num2 = Math.Max(Math.Abs(position.x - zone.Center.x) - num, 0f);
			float num3 = Math.Max(Math.Abs(position.z - zone.Center.z) - num, 0f);
			return num2 * num2 + num3 * num3 <= zone.Radius * zone.Radius;
		}

		private static string NormalizeZoneId(string zoneId)
		{
			if (!string.IsNullOrWhiteSpace(zoneId))
			{
				return zoneId.Trim();
			}
			return "creative";
		}
	}
	internal static class CreativeInventoryRpc
	{
		private sealed class CreativeInventorySnapshot
		{
			public bool Available { get; set; }

			public string Error { get; set; } = string.Empty;


			public long PlayerId { get; set; }

			public string PlayerName { get; set; } = string.Empty;


			public int PlayerInventoryCount { get; set; }

			public bool ExtraSlotsLoaded { get; set; }

			public bool ExtraSlotsAvailable { get; set; }

			public int ExtraSlotsCount { get; set; }

			public int TotalUniqueCount { get; set; }

			public List<CreativeInventoryItem> Items { get; } = new List<CreativeInventoryItem>();


			public static CreativeInventorySnapshot Unavailable(string error)
			{
				return new CreativeInventorySnapshot
				{
					Available = false,
					Error = error
				};
			}
		}

		private sealed class CreativeInventoryItem
		{
			public string Source { get; set; } = string.Empty;


			public string PrefabName { get; set; } = string.Empty;


			public string SharedName { get; set; } = string.Empty;


			public int Stack { get; set; }

			public int Quality { get; set; }

			public bool Equipped { get; set; }

			public int GridX { get; set; }

			public int GridY { get; set; }

			public static CreativeInventoryItem FromItem(string source, ItemData item)
			{
				return new CreativeInventoryItem
				{
					Source = source,
					PrefabName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : string.Empty),
					SharedName = (item.m_shared?.m_name ?? string.Empty),
					Stack = item.m_stack,
					Quality = item.m_quality,
					Equipped = item.m_equipped,
					GridX = item.m_gridPos.x,
					GridY = item.m_gridPos.y
				};
			}
		}

		private sealed class ExtraSlotsReadResult
		{
			public bool ModLoaded { get; private set; }

			public bool Available { get; private set; }

			public string Error { get; private set; } = string.Empty;


			public List<ItemData> Items { get; } = new List<ItemData>();


			public static ExtraSlotsReadResult NotLoaded()
			{
				return new ExtraSlotsReadResult
				{
					ModLoaded = false,
					Available = true
				};
			}

			public static ExtraSlotsReadResult Loaded(IEnumerable<ItemData> items)
			{
				ExtraSlotsReadResult extraSlotsReadResult = new ExtraSlotsReadResult();
				extraSlotsReadResult.ModLoaded = true;
				extraSlotsReadResult.Available = true;
				extraSlotsReadResult.Items.AddRange(items);
				return extraSlotsReadResult;
			}

			public static ExtraSlotsReadResult Failed(string error)
			{
				return new ExtraSlotsReadResult
				{
					ModLoaded = true,
					Available = false,
					Error = error
				};
			}
		}

		private const int ProtocolVersion = 1;

		private const string ExtraSlotsApiTypeName = "ExtraSlots.API";

		public static void OnRequest(long sender, ZPackage pkg)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				return;
			}
			string text = string.Empty;
			ZDOID val = ZDOID.None;
			bool flag = true;
			try
			{
				int num = pkg.ReadInt();
				if (num != 1)
				{
					SendUnavailable(sender, text, val, $"Unsupported creative inventory protocol version {num}.");
					return;
				}
				text = pkg.ReadString();
				val = pkg.ReadZDOID();
				flag = pkg.ReadBool();
				CreativeInventorySnapshot snapshot = BuildSnapshot(val, flag);
				SendResponse(sender, text, val, snapshot);
			}
			catch (Exception arg)
			{
				PraetorisClientPlugin.Log.LogWarning((object)$"Failed to answer creative inventory request {text}: {arg}");
				SendUnavailable(sender, text, val, "Failed to read client inventory.");
			}
		}

		private static CreativeInventorySnapshot BuildSnapshot(ZDOID expectedCharacterId, bool includeItems)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Character)localPlayer).m_nview == (Object)null || !((Character)localPlayer).m_nview.IsValid())
			{
				return CreativeInventorySnapshot.Unavailable("Local player is not available.");
			}
			ZDO zDO = ((Character)localPlayer).m_nview.GetZDO();
			if (zDO == null)
			{
				return CreativeInventorySnapshot.Unavailable("Local player character is not available.");
			}
			if (!((ZDOID)(ref expectedCharacterId)).IsNone() && zDO.m_uid != expectedCharacterId)
			{
				return CreativeInventorySnapshot.Unavailable("Local player character did not match the requested character.");
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (inventory == null)
			{
				return CreativeInventorySnapshot.Unavailable("Local player inventory is not available.");
			}
			List<ItemData> list = (from item in inventory.GetAllItems()
				where item != null
				select item).ToList();
			ExtraSlotsReadResult extraSlotsReadResult = ReadExtraSlotsItems();
			if (!extraSlotsReadResult.Available && extraSlotsReadResult.ModLoaded)
			{
				return CreativeInventorySnapshot.Unavailable(extraSlotsReadResult.Error);
			}
			List<ItemData> list2 = new List<ItemData>();
			AddUnique(list2, list);
			AddUnique(list2, extraSlotsReadResult.Items);
			CreativeInventorySnapshot creativeInventorySnapshot = new CreativeInventorySnapshot
			{
				Available = true,
				Error = string.Empty,
				PlayerId = localPlayer.GetPlayerID(),
				PlayerName = localPlayer.GetPlayerName(),
				PlayerInventoryCount = list.Count,
				ExtraSlotsAvailable = extraSlotsReadResult.Available,
				ExtraSlotsLoaded = extraSlotsReadResult.ModLoaded,
				ExtraSlotsCount = extraSlotsReadResult.Items.Count,
				TotalUniqueCount = list2.Count
			};
			if (includeItems)
			{
				creativeInventorySnapshot.Items.AddRange(list.Select((ItemData item) => CreativeInventoryItem.FromItem("player", item)));
				creativeInventorySnapshot.Items.AddRange(extraSlotsReadResult.Items.Select((ItemData item) => CreativeInventoryItem.FromItem("extraSlots", item)));
			}
			return creativeInventorySnapshot;
		}

		private static ExtraSlotsReadResult ReadExtraSlotsItems()
		{
			Type type2 = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
				select assembly.GetType("ExtraSlots.API", throwOnError: false)).FirstOrDefault((Type type) => type != null);
			if (type2 == null)
			{
				return ExtraSlotsReadResult.NotLoaded();
			}
			MethodInfo method = type2.GetMethod("GetAllExtraSlotsItems", BindingFlags.Static | BindingFlags.Public);
			if (method == null)
			{
				return ExtraSlotsReadResult.Failed("ExtraSlots API did not expose GetAllExtraSlotsItems.");
			}
			try
			{
				if (!(method.Invoke(null, Array.Empty<object>()) is IEnumerable enumerable))
				{
					return ExtraSlotsReadResult.Failed("ExtraSlots API returned no item list.");
				}
				List<ItemData> list = new List<ItemData>();
				foreach (object item in enumerable)
				{
					ItemData val = (ItemData)((item is ItemData) ? item : null);
					if (val != null)
					{
						list.Add(val);
					}
				}
				return ExtraSlotsReadResult.Loaded(list);
			}
			catch (Exception ex)
			{
				return ExtraSlotsReadResult.Failed("ExtraSlots API read failed: " + ex.Message);
			}
		}

		private static void AddUnique(List<ItemData> target, IEnumerable<ItemData> items)
		{
			foreach (ItemData item in items)
			{
				if (!target.Contains(item))
				{
					target.Add(item);
				}
			}
		}

		private static void SendUnavailable(long target, string requestId, ZDOID characterId, string error)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			SendResponse(target, requestId, characterId, CreativeInventorySnapshot.Unavailable(error));
		}

		private static void SendResponse(long target, string requestId, ZDOID characterId, CreativeInventorySnapshot snapshot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(requestId);
			val.Write(characterId);
			val.Write(snapshot.Available);
			val.Write(snapshot.Error);
			val.Write(snapshot.PlayerId);
			val.Write(snapshot.PlayerName);
			val.Write(snapshot.PlayerInventoryCount);
			val.Write(snapshot.ExtraSlotsLoaded);
			val.Write(snapshot.ExtraSlotsAvailable);
			val.Write(snapshot.ExtraSlotsCount);
			val.Write(snapshot.TotalUniqueCount);
			val.Write(snapshot.Items.Count);
			foreach (CreativeInventoryItem item in snapshot.Items)
			{
				val.Write(item.Source);
				val.Write(item.PrefabName);
				val.Write(item.SharedName);
				val.Write(item.Stack);
				val.Write(item.Quality);
				val.Write(item.Equipped);
				val.Write(item.GridX);
				val.Write(item.GridY);
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(target, "DiscordTools_CreativeInventoryResponse", new object[1] { val });
		}
	}
	internal static class LinkCommandHandler
	{
		private static readonly Regex CodePattern = new Regex("^[A-Za-z0-9_-]{4,64}$", RegexOptions.Compiled);

		public static bool TryHandle(Chat chat)
		{
			string text = (((Object)(object)((Terminal)chat).m_input != (Object)null) ? ((TMP_InputField)((Terminal)chat).m_input).text : "");
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			string text2 = PraetorisClientPlugin.LinkCommand.Value.Trim();
			if (string.IsNullOrWhiteSpace(text2))
			{
				text2 = "!link";
			}
			string text3 = text.Trim();
			if (!text3.Equals(text2, StringComparison.OrdinalIgnoreCase) && !text3.StartsWith(text2 + " ", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string text4 = ((text3.Length > text2.Length) ? text3.Substring(text2.Length).Trim() : "");
			if (!CodePattern.IsMatch(text4))
			{
				((Terminal)chat).AddString("Usage: " + text2 + " CODE");
				ClearInput(chat);
				return true;
			}
			if (!LinkRpc.TrySendRequest(text4, out string message))
			{
				((Terminal)chat).AddString(message);
				ClearInput(chat);
				return true;
			}
			((Terminal)chat).AddString("Sending Discord link code to the server.");
			ClearInput(chat);
			return true;
		}

		private static void ClearInput(Chat chat)
		{
			if (!((Object)(object)((Terminal)chat).m_input == (Object)null))
			{
				((TMP_InputField)((Terminal)chat).m_input).text = "";
				((Component)((Terminal)chat).m_input).gameObject.SetActive(false);
			}
		}
	}
	internal static class LinkRpc
	{
		public static bool TrySendRequest(string code, out string message)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			message = "";
			if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null || ZNet.instance.IsServer() || (int)ZNet.GetConnectionStatus() != 2)
			{
				message = "You must be connected to a server before linking Discord.";
				return false;
			}
			string text = Guid.NewGuid().ToString("N");
			ZPackage val = new ZPackage();
			val.Write(text);
			val.Write(code);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "DiscordTools_LinkRequest", new object[1] { val });
			return true;
		}

		public static void OnRequest(long sender, ZPackage pkg)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			string requestId = pkg.ReadString();
			string code = pkg.ReadString();
			ZNetPeer val = PlayerResolver.FindPeerBySender(sender);
			if (val == null)
			{
				SendResult(sender, requestId, success: false, "The server could not identify your Valheim connection.");
				return;
			}
			PraetorisClientPlugin instance = PraetorisClientPlugin.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				SendResult(sender, requestId, success: false, "PraetorisClient is not ready on the server.");
				return;
			}
			LinkRequest link = new LinkRequest
			{
				Sender = sender,
				RequestId = requestId,
				Code = code,
				PlayerId = PlayerResolver.StablePlayerId(val),
				PlayerName = (val.m_playerName ?? ""),
				Endpoint = PlayerResolver.SafeEndPoint(val),
				PlatformDisplayName = PlayerResolver.PlatformDisplayName(val),
				ReceivedAtUtc = DateTime.UtcNow
			};
			PraetorisClientPlugin.Log.LogInfo((object)("Received Discord link code from " + PlayerResolver.DescribePeer(val) + "."));
			((MonoBehaviour)instance).StartCoroutine(BotApiClient.PostLinkRoutine(link, SendResult));
		}

		public static void OnResult(long sender, ZPackage pkg)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				string text = pkg.ReadString();
				bool flag = pkg.ReadBool();
				string text2 = pkg.ReadString();
				PraetorisClientPlugin.Log.LogInfo((object)("Discord link result " + text + ": " + text2));
				Chat instance = Chat.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString(flag ? text2 : ("Discord link failed: " + text2));
				}
			}
		}

		private static void SendResult(long target, string requestId, bool success, string message)
		{
			//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(requestId);
			val.Write(success);
			val.Write(message);
			ZRoutedRpc.instance.InvokeRoutedRPC(target, "DiscordTools_LinkResult", new object[1] { val });
		}
	}
	internal sealed class LinkRequest
	{
		public long Sender;

		public string RequestId = "";

		public string Code = "";

		public string PlayerId = "";

		public string PlayerName = "";

		public string Endpoint = "";

		public string PlatformDisplayName = "";

		public DateTime ReceivedAtUtc;
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNetAwakePatch
	{
		private static void Postfix()
		{
			PraetorisClientRpc.Register();
		}
	}
	[HarmonyPatch(typeof(Chat), "SendInput")]
	internal static class ChatSendInputPatch
	{
		private static bool Prefix(Chat __instance)
		{
			return !LinkCommandHandler.TryHandle(__instance);
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class CharacterApplyDamageTelemetryPatch
	{
		private static void Prefix(Character __instance, HitData hit, ref DamageObservationState __state)
		{
			__state = ValheimEventsTelemetry.CaptureDamageBefore(__instance, hit);
		}

		private static void Postfix(Character __instance, HitData hit, DamageModifier mod, DamageObservationState __state)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			ValheimEventsTelemetry.LogDamageApplied(__instance, hit, mod, __state);
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class PlayerDeathTelemetryPatch
	{
		private static void Prefix(Player __instance, ref DeathObservationState __state)
		{
			__state = ValheimEventsTelemetry.CaptureDeathBefore(__instance);
		}

		private static void Postfix(Player __instance, DeathObservationState __state)
		{
			ValheimEventsTelemetry.LogPlayerDied(__instance, __state);
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(int),
		typeof(int)
	})]
	internal static class MinimapExploreTelemetryPatch
	{
		private static void Postfix(Minimap __instance, int x, int y, bool __result)
		{
			if (__result)
			{
				ValheimEventsTelemetry.RecordExploredCell(__instance, x, y);
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Update")]
	internal static class GameUpdateTelemetryPatch
	{
		private static void Postfix()
		{
			ValheimEventsTelemetry.Update();
		}
	}
	internal static class PlayerResolver
	{
		public static List<ZNetPeer> FindPeers(string query)
		{
			List<ZNetPeer> list = new List<ZNetPeer>();
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return list;
			}
			string text = Normalize(query);
			foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers())
			{
				if (connectedPeer.IsReady())
				{
					string value = SafeHostName(connectedPeer);
					string value2 = StablePlayerId(connectedPeer);
					if (Normalize(connectedPeer.m_playerName) == text || Normalize(value) == text || Normalize(value2) == text || (DigitsOnly(value) == DigitsOnly(query) && DigitsOnly(query).Length > 0))
					{
						list.Add(connectedPeer);
					}
				}
			}
			if (list.Count > 0)
			{
				return list;
			}
			foreach (ZNetPeer connectedPeer2 in ZNet.instance.GetConnectedPeers())
			{
				if (connectedPeer2.IsReady() && Normalize(connectedPeer2.m_playerName).Contains(text))
				{
					list.Add(connectedPeer2);
				}
			}
			return list;
		}

		public static ZNetPeer? FindPeerBySender(long sender)
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return null;
			}
			return ((IEnumerable<ZNetPeer>)ZNet.instance.GetConnectedPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer peer) => peer.m_uid == sender));
		}

		public static string DescribePeer(ZNetPeer peer)
		{
			return peer.m_playerName + " (" + StablePlayerId(peer) + ")";
		}

		public static string StablePlayerId(ZNetPeer peer)
		{
			string text = SafeHostName(peer);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return text;
			}
			return peer.m_uid.ToString(CultureInfo.InvariantCulture);
		}

		public static string SafeHostName(ZNetPeer peer)
		{
			try
			{
				ISocket socket = peer.m_socket;
				return ((socket != null) ? socket.GetHostName() : null) ?? "";
			}
			catch
			{
				return "";
			}
		}

		public static string SafeEndPoint(ZNetPeer peer)
		{
			try
			{
				ISocket socket = peer.m_socket;
				return ((socket != null) ? socket.GetEndPointString() : null) ?? "";
			}
			catch
			{
				return "";
			}
		}

		public static string PlatformDisplayName(ZNetPeer peer)
		{
			try
			{
				string value;
				return (peer.m_serverSyncedPlayerData != null && peer.m_serverSyncedPlayerData.TryGetValue("platformDisplayName", out value)) ? value : "";
			}
			catch
			{
				return "";
			}
		}

		private static string Normalize(string value)
		{
			return (value ?? "").Trim().ToLowerInvariant();
		}

		private static string DigitsOnly(string value)
		{
			return new string((value ?? "").Where(char.IsDigit).ToArray());
		}
	}
	[BepInPlugin("warpalicious.PraetorisClient", "PraetorisClient", "0.1.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class PraetorisClientPlugin : BaseUnityPlugin
	{
		private const string ModName = "PraetorisClient";

		private const string ModVersion = "0.1.3";

		private const string Author = "warpalicious";

		private const string ModGUID = "warpalicious.PraetorisClient";

		private const string LinkApiUrlEnv = "PRAETORISCLIENT_LINK_API_URL";

		private const string BotApiKeyEnv = "PRAETORISCLIENT_BOT_API_KEY";

		private readonly Harmony _harmony = new Harmony("warpalicious.PraetorisClient");

		private DateTime _lastReloadTime;

		private FileSystemWatcher? _configWatcher;

		private const long ReloadDelayTicks = 10000000L;

		public static readonly ManualLogSource Log = Logger.CreateLogSource("PraetorisClient");

		internal static ConfigEntry<string> LinkApiUrl = null;

		internal static ConfigEntry<string> BotApiKey = null;

		internal static ConfigEntry<string> LinkCommand = null;

		internal static ConfigEntry<bool> ValheimEventsTelemetryEnabled = null;

		internal static ConfigEntry<bool> CombatTelemetryEnabled = null;

		internal static ConfigEntry<bool> ExplorationTelemetryEnabled = null;

		internal static ConfigEntry<float> ExplorationFlushSeconds = null;

		public static PraetorisClientPlugin? Instance { get; private set; }

		internal static string GetLinkApiUrl()
		{
			string environmentVariable = Environment.GetEnvironmentVariable("PRAETORISCLIENT_LINK_API_URL");
			if (!string.IsNullOrWhiteSpace(environmentVariable))
			{
				return environmentVariable.Trim();
			}
			return LinkApiUrl.Value;
		}

		internal static string GetBotApiKey()
		{
			string environmentVariable = Environment.GetEnvironmentVariable("PRAETORISCLIENT_BOT_API_KEY");
			if (!string.IsNullOrWhiteSpace(environmentVariable))
			{
				return environmentVariable.Trim();
			}
			return BotApiKey.Value;
		}

		public void Awake()
		{
			Instance = this;
			BindConfig();
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			SiegePortalTestCommand.Register();
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			SetupWatcher();
		}

		private void OnDestroy()
		{
			SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized;
			try
			{
				_configWatcher?.Dispose();
				_configWatcher = null;
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Failed to dispose configuration watcher: " + ex.Message));
			}
			try
			{
				((BaseUnityPlugin)this).Config.Save();
			}
			catch (Exception ex2)
			{
				Log.LogWarning((object)("Failed to save configuration during shutdown: " + ex2.Message));
			}
			try
			{
				_harmony.UnpatchSelf();
			}
			catch (Exception ex3)
			{
				Log.LogWarning((object)("Failed to unpatch PraetorisClient during shutdown: " + ex3.Message));
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void BindConfig()
		{
			LinkApiUrl = ((BaseUnityPlugin)this).Config.Bind<string>("BotApi", "LinkApiUrl", "", "Compatible bot Valheim link endpoint. Prefer the PRAETORISCLIENT_LINK_API_URL environment variable on dedicated servers.");
			BotApiKey = ((BaseUnityPlugin)this).Config.Bind<string>("BotApi", "ApiKey", "", "API key sent to the bot in the X-API-Key header. Prefer the PRAETORISCLIENT_BOT_API_KEY environment variable on dedicated servers.");
			LinkCommand = ((BaseUnityPlugin)this).Config.Bind<string>("Linking", "LinkCommand", "!link", "In-game chat command consumed before it is sent as chat.");
			ValheimEventsTelemetryEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ValheimEvents", "Enabled", true, SyncedDescription("Sends client-observed telemetry to the server-side ValheimEvents mod."));
			CombatTelemetryEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ValheimEvents", "CombatTelemetry", true, SyncedDescription("Sends client-observed combat and death telemetry."));
			ExplorationTelemetryEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ValheimEvents", "ExplorationTelemetry", true, SyncedDescription("Sends client-observed minimap exploration telemetry."));
			ExplorationFlushSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("ValheimEvents", "ExplorationFlushSeconds", 2f, SyncedDescription("How long newly explored minimap cells are batched before sending."));
		}

		private static ConfigDescription SyncedDescription(string description)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { val });
		}

		private static void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs args)
		{
			if (args.UpdatedPluginGUIDs != null && args.UpdatedPluginGUIDs.Contains("warpalicious.PraetorisClient"))
			{
				string text = (args.InitialSynchronization ? "initial" : "updated");
				Log.LogInfo((object)("Jotunn synchronized PraetorisClient configuration (" + text + ")."));
			}
		}

		private void SetupWatcher()
		{
			try
			{
				_lastReloadTime = DateTime.Now;
				_configWatcher?.Dispose();
				_configWatcher = new FileSystemWatcher(Paths.ConfigPath, "warpalicious.PraetorisClient.cfg");
				_configWatcher.Changed += ReadConfigValues;
				_configWatcher.Created += ReadConfigValues;
				_configWatcher.Renamed += ReadConfigValues;
				_configWatcher.IncludeSubdirectories = true;
				_configWatcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Failed to start configuration watcher: " + ex.Message));
			}
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			long num = now.Ticks - _lastReloadTime.Ticks;
			if (File.Exists(Path.Combine(Paths.ConfigPath, "warpalicious.PraetorisClient.cfg")) && num >= 10000000)
			{
				try
				{
					Log.LogInfo((object)"Reloading configuration.");
					((BaseUnityPlugin)this).Config.Reload();
				}
				catch (Exception ex)
				{
					Log.LogError((object)("Failed to reload configuration: " + ex.Message));
				}
				_lastReloadTime = now;
			}
		}
	}
	internal static class PraetorisClientRpc
	{
		private static ZRoutedRpc? _registeredRpc;

		public static void Register()
		{
			if (ZRoutedRpc.instance != null && _registeredRpc != ZRoutedRpc.instance)
			{
				_registeredRpc = ZRoutedRpc.instance;
				ZRoutedRpc.instance.Register<ZPackage>("DiscordTools_LinkRequest", (Action<long, ZPackage>)LinkRpc.OnRequest);
				ZRoutedRpc.instance.Register<ZPackage>("DiscordTools_LinkResult", (Action<long, ZPackage>)LinkRpc.OnResult);
				ZRoutedRpc.instance.Register<ZPackage>("DiscordTools_CreativeInventoryRequest", (Action<long, ZPackage>)CreativeInventoryRpc.OnRequest);
				ZRoutedRpc.instance.Register<ZPackage>("DiscordTools_CreativeBiomeOverride", (Action<long, ZPackage>)CreativeBiomeOverride.OnOverride);
				PraetorisClientPlugin.Log.LogInfo((object)"Registered PraetorisClient RPC handlers.");
			}
		}
	}
	internal static class RpcNames
	{
		public const string LinkRequest = "DiscordTools_LinkRequest";

		public const string LinkResult = "DiscordTools_LinkResult";

		public const string CreativeInventoryRequest = "DiscordTools_CreativeInventoryRequest";

		public const string CreativeInventoryResponse = "DiscordTools_CreativeInventoryResponse";

		public const string CreativeBiomeOverride = "DiscordTools_CreativeBiomeOverride";

		public const string SiegePortalEnter = "DiscordTools_SiegePortalEnter";

		public const string ValheimEventsTelemetry = "PraetorisClient_ValheimEventsTelemetry";
	}
	internal static class SiegePortalBridge
	{
		private const int ProtocolVersion = 1;

		internal const string SiegeIdZdoKey = "valheimCreativeSiegeId";

		internal const string SiegeTagPrefix = "siege:";

		internal static bool TryHandle(TeleportWorld portal, Player player)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || ZRoutedRpc.instance == null)
			{
				return false;
			}
			if ((Object)(object)player == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			ZNetView component = ((Component)portal).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			if (val == null || !TryGetSiegeId(val, out string siegeId))
			{
				return false;
			}
			if ((Object)(object)((Character)player).m_nview == (Object)null || !((Character)player).m_nview.IsValid())
			{
				((Character)player).Message((MessageType)2, "Siege portal failed: character was not ready.", 0, (Sprite)null);
				return true;
			}
			ZDO zDO = ((Character)player).m_nview.GetZDO();
			if (zDO == null)
			{
				((Character)player).Message((MessageType)2, "Siege portal failed: character was not ready.", 0, (Sprite)null);
				return true;
			}
			ZPackage val2 = new ZPackage();
			val2.Write(1);
			val2.Write(zDO.m_uid);
			val2.Write(siegeId);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "DiscordTools_SiegePortalEnter", new object[1] { val2 });
			((Character)player).Message((MessageType)2, "Entering siege: " + siegeId, 0, (Sprite)null);
			PraetorisClientPlugin.Log.LogInfo((object)("Requested siege portal enter for " + siegeId + "."));
			return true;
		}

		private static bool TryGetSiegeId(ZDO portalZdo, out string siegeId)
		{
			siegeId = portalZdo.GetString("valheimCreativeSiegeId", "").Trim();
			if (!string.IsNullOrWhiteSpace(siegeId))
			{
				return true;
			}
			string text = portalZdo.GetString(ZDOVars.s_tag, "").Trim();
			if (text.StartsWith("siege:", StringComparison.OrdinalIgnoreCase))
			{
				siegeId = text.Substring("siege:".Length).Trim();
				return !string.IsNullOrWhiteSpace(siegeId);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	internal static class TeleportWorldSiegePortalPatch
	{
		private static bool Prefix(TeleportWorld __instance, Player player)
		{
			return !SiegePortalBridge.TryHandle(__instance, player);
		}
	}
	internal static class SiegePortalTestCommand
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__1_0;

			public static ConsoleEvent <>9__1_1;

			internal void <Register>b__1_0(ConsoleEventArgs args)
			{
				//IL_008e: 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)
				if (args.Length < 2)
				{
					args.Context.AddString("Usage: dt_mark_siege_portal <siegeId> [radius]");
					return;
				}
				string text = args[1].Trim();
				if (string.IsNullOrWhiteSpace(text))
				{
					args.Context.AddString("siegeId is required.");
					return;
				}
				float result = 12f;
				if (args.Length >= 3)
				{
					float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result);
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					args.Context.AddString("No local player found.");
					return;
				}
				float distance;
				TeleportWorld val = FindNearestPortal(((Component)localPlayer).transform.position, Mathf.Clamp(result, 1f, 50f), out distance);
				if ((Object)(object)val == (Object)null)
				{
					args.Context.AddString($"No portal found within {result:0.#}m.");
					return;
				}
				ZNetView component = ((Component)val).GetComponent<ZNetView>();
				ZDO val2 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
				if (val2 == null)
				{
					args.Context.AddString("Nearest portal has no valid ZDO.");
					return;
				}
				val2.Set("valheimCreativeSiegeId", text);
				val2.Set(ZDOVars.s_tag, "siege:" + text);
				args.Context.AddString($"Marked nearest portal {val2.m_uid} as siege {text} at {distance:0.#}m.");
			}

			internal void <Register>b__1_1(ConsoleEventArgs args)
			{
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				float result = 12f;
				if (args.Length >= 2)
				{
					float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out result);
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					args.Context.AddString("No local player found.");
					return;
				}
				float distance;
				TeleportWorld val = FindNearestPortal(((Component)localPlayer).transform.position, Mathf.Clamp(result, 1f, 50f), out distance);
				if ((Object)(object)val == (Object)null)
				{
					args.Context.AddString($"No portal found within {result:0.#}m.");
					return;
				}
				bool flag = SiegePortalBridge.TryHandle(val, localPlayer);
				args.Context.AddString($"Nearest siege portal handled={flag} distance={distance:0.#}m.");
			}
		}

		private static bool _registered;

		internal static void Register()
		{
			//IL_0040: 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_0037: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			if (_registered)
			{
				return;
			}
			_registered = true;
			object obj = <>c.<>9__1_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					//IL_008e: 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)
					if (args.Length < 2)
					{
						args.Context.AddString("Usage: dt_mark_siege_portal <siegeId> [radius]");
					}
					else
					{
						string text = args[1].Trim();
						if (string.IsNullOrWhiteSpace(text))
						{
							args.Context.AddString("siegeId is required.");
						}
						else
						{
							float result2 = 12f;
							if (args.Length >= 3)
							{
								float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result2);
							}
							Player localPlayer2 = Player.m_localPlayer;
							if ((Object)(object)localPlayer2 == (Object)null)
							{
								args.Context.AddString("No local player found.");
							}
							else
							{
								float distance2;
								TeleportWorld val4 = FindNearestPortal(((Component)localPlayer2).transform.position, Mathf.Clamp(result2, 1f, 50f), out distance2);
								if ((Object)(object)val4 == (Object)null)
								{
									args.Context.AddString($"No portal found within {result2:0.#}m.");
								}
								else
								{
									ZNetView component = ((Component)val4).GetComponent<ZNetView>();
									ZDO val5 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
									if (val5 == null)
									{
										args.Context.AddString("Nearest portal has no valid ZDO.");
									}
									else
									{
										val5.Set("valheimCreativeSiegeId", text);
										val5.Set(ZDOVars.s_tag, "siege:" + text);
										args.Context.AddString($"Marked nearest portal {val5.m_uid} as siege {text} at {distance2:0.#}m.");
									}
								}
							}
						}
					}
				};
				<>c.<>9__1_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("dt_mark_siege_portal", "Mark the nearest portal as a valheimCreative siege portal. Usage: dt_mark_siege_portal <siegeId> [radius]", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__1_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					float result = 12f;
					if (args.Length >= 2)
					{
						float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out result);
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						args.Context.AddString("No local player found.");
					}
					else
					{
						float distance;
						TeleportWorld val3 = FindNearestPortal(((Component)localPlayer).transform.position, Mathf.Clamp(result, 1f, 50f), out distance);
						if ((Object)(object)val3 == (Object)null)
						{
							args.Context.AddString($"No portal found within {result:0.#}m.");
						}
						else
						{
							bool flag = SiegePortalBridge.TryHandle(val3, localPlayer);
							args.Context.AddString($"Nearest siege portal handled={flag} distance={distance:0.#}m.");
						}
					}
				};
				<>c.<>9__1_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("dt_enter_nearest_siege_portal", "Enter the nearest marked valheimCreative siege portal. Usage: dt_enter_nearest_siege_portal [radius]", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static TeleportWorld? FindNearestPortal(Vector3 center, float radius, out float distance)
		{
			//IL_0009: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			distance = float.MaxValue;
			TeleportWorld result = null;
			Collider[] array = Physics.OverlapSphere(center, radius);
			for (int i = 0; i < array.Length; i++)
			{
				TeleportWorld componentInParent = ((Component)array[i]).GetComponentInParent<TeleportWorld>();
				if (!((Object)(object)componentInParent == (Object)null))
				{
					float num = Vector3.Distance(center, ((Component)componentInParent).transform.position);
					if (num < distance)
					{
						distance = num;
						result = componentInParent;
					}
				}
			}
			return result;
		}
	}
	internal sealed class TelemetryJson
	{
		private readonly StringBuilder _builder = new StringBuilder();

		private readonly Stack<bool> _needsComma = new Stack<bool>();

		private TelemetryJson()
		{
		}

		internal static TelemetryJson Object()
		{
			TelemetryJson telemetryJson = new TelemetryJson();
			telemetryJson._builder.Append('{');
			telemetryJson._needsComma.Push(item: false);
			return telemetryJson;
		}

		internal void End()
		{
			_builder.Append('}');
			if (_needsComma.Count > 0)
			{
				_needsComma.Pop();
			}
		}

		internal void BeginObject(string name)
		{
			Name(name);
			_builder.Append('{');
			_needsComma.Push(item: false);
		}

		internal void EndObject()
		{
			End();
		}

		internal void BeginArray(string name)
		{
			Name(name);
			_builder.Append('[');
			_needsComma.Push(item: false);
		}

		internal void EndArray()
		{
			_builder.Append(']');
			if (_needsComma.Count > 0)
			{
				_needsComma.Pop();
			}
		}

		internal void BeginArrayObject()
		{
			ArrayPrefix();
			_builder.Append('{');
			_needsComma.Push(item: false);
		}

		internal void EndArrayObject()
		{
			End();
		}

		internal void ArrayString(string value)
		{
			ArrayPrefix();
			WriteString(value);
		}

		internal void Prop(string name, string value)
		{
			Name(name);
			WriteString(value);
		}

		internal void Prop(string name, bool value)
		{
			Name(name);
			_builder.Append(value ? "true" : "false");
		}

		internal void Prop(string name, int value)
		{
			Name(name);
			_builder.Append(value.ToString(CultureInfo.InvariantCulture));
		}

		internal void Prop(string name, uint value)
		{
			Name(name);
			_builder.Append(value.ToString(CultureInfo.InvariantCulture));
		}

		internal void Prop(string name, short value)
		{
			Name(name);
			_builder.Append(value.ToString(CultureInfo.InvariantCulture));
		}

		internal void Prop(string name, ushort value)
		{
			Name(name);
			_builder.Append(value.ToString(CultureInfo.InvariantCulture));
		}

		internal void Prop(string name, long value)
		{
			Name(name);
			_builder.Append(value.ToString(CultureInfo.InvariantCulture));
		}

		internal void Prop(string name, float value)
		{
			Name(name);
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				_builder.Append("null");
			}
			else
			{
				_builder.Append(value.ToString("R", CultureInfo.InvariantCulture));
			}
		}

		internal void Prop(string name, double value)
		{
			Name(name);
			if (double.IsNaN(value) || double.IsInfinity(value))
			{
				_builder.Append("null");
			}
			else
			{
				_builder.Append(value.ToString("R", CultureInfo.InvariantCulture));
			}
		}

		internal void Prop(string name, Vector3 value)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			BeginObject(name);
			Prop("x", value.x);
			Prop("y", value.y);
			Prop("z", value.z);
			EndObject();
		}

		internal void Prop(string name, Quaternion value)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			BeginObject(name);
			Prop("x", value.x);
			Prop("y", value.y);
			Prop("z", value.z);
			Prop("w", value.w);
			EndObject();
		}

		public override string ToString()
		{
			return _builder.ToString();
		}

		private void Name(string name)
		{
			if (_needsComma.Count == 0)
			{
				throw new InvalidOperationException("JSON object is not open.");
			}
			if (_needsComma.Peek())
			{
				_builder.Append(',');
			}
			_needsComma.Pop();
			_needsComma.Push(item: true);
			WriteString(name);
			_builder.Append(':');
		}

		private void ArrayPrefix()
		{
			if (_needsComma.Count == 0)
			{
				throw new InvalidOperationException("JSON array is not open.");
			}
			if (_needsComma.Peek())
			{
				_builder.Append(',');
			}
			_needsComma.Pop();
			_needsComma.Push(item: true);
		}

		private void WriteString(string value)
		{
			_builder.Append('"');
			string text = value ?? "";
			foreach (char c in text)
			{
				switch (c)
				{
				case '"':
					_builder.Append("\\\"");
					continue;
				case '\\':
					_builder.Append("\\\\");
					continue;
				case '\b':
					_builder.Append("\\b");
					continue;
				case '\f':
					_builder.Append("\\f");
					continue;
				case '\n':
					_builder.Append("\\n");
					continue;
				case '\r':
					_builder.Append("\\r");
					continue;
				case '\t':
					_builder.Append("\\t");
					continue;
				}
				if (char.IsControl(c))
				{
					StringBuilder stringBuilder = _builder.Append("\\u");
					int num = c;
					stringBuilder.Append(num.ToString("x4", CultureInfo.InvariantCulture));
				}
				else
				{
					_builder.Append(c);
				}
			}
			_builder.Append('"');
		}
	}
	internal readonly struct ClientZdoSnapshot
	{
		private readonly struct PlayerFields
		{
			internal static readonly PlayerFields Empty = new PlayerFields(0L, "", 0f, 0f, 0f, 0f, 0f, dead: false, pvp: false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", "", "", "", "", "", "", "", "", "", "");

			internal readonly long PlayerId;

			internal readonly string PlayerName;

			private readonly float _health;

			private readonly float _maxHealth;

			private readonly float _stamina;

			private readonly float _eitr;

			private readonly float _adrenaline;

			private readonly bool _dead;

			private readonly bool _pvp;

			private readonly int _rightItem;

			private readonly int _leftItem;

			private readonly int _chestItem;

			private readonly int _legItem;

			private readonly int _helmetItem;

			private readonly int _shoulderItem;

			private readonly int _utilityItem;

			private readonly int _trinketItem;

			private readonly int _leftBackItem;

			private readonly int _rightBackItem;

			private readonly int _hairItem;

			private readonly int _beardItem;

			private readonly string _rightItemName;

			private readonly string _leftItemName;

			private readonly string _chestItemName;

			private readonly string _legItemName;

			private readonly string _helmetItemName;

			private readonly string _shoulderItemName;

			private readonly string _utilityItemName;

			private readonly string _trinketItemName;

			private readonly string _leftBackItemName;

			private readonly string _rightBackItemName;

			private readonly string _hairItemName;

			private readonly string _beardItemName;

			private PlayerFields(long playerId, string playerName, float health, float maxHealth, float stamina, float eitr, float adrenaline, bool dead, bool pvp, int rightItem, int leftItem, int chestItem, int legItem, int helmetItem, int shoulderItem, int utilityItem, int trinketItem, int leftBackItem, int rightBackItem, int hairItem, int beardItem, string rightItemName, string leftItemName, string chestItemName, string legItemName, string helmetItemName, string shoulderItemName, string utilityItemName, string trinketItemName, string leftBackItemName, string rightBackItemName, string hairItemName, string beardItemName)
			{
				PlayerId = playerId;
				PlayerName = playerName;
				_health = health;
				_maxHealth = maxHealth;
				_stamina = stamina;
				_eitr = eitr;
				_adrenaline = adrenaline;
				_dead = dead;
				_pvp = pvp;
				_rightItem = rightItem;
				_leftItem = leftItem;
				_chestItem = chestItem;
				_legItem = legItem;
				_helmetItem = helmetItem;
				_shoulderItem = shoulderItem;
				_utilityItem = utilityItem;
				_trinketItem = trinketItem;
				_leftBackItem = leftBackItem;
				_rightBackItem = rightBackItem;
				_hairItem = hairItem;
				_beardItem = beardItem;
				_rightItemName = rightItemName;
				_leftItemName = leftItemName;
				_chestItemName = chestItemName;
				_legItemName = legItemName;
				_helmetItemName = helmetItemName;
				_shoulderItemName = shoulderItemName;
				_utilityItemName = utilityItemName;
				_trinketItemName = trinketItemName;
				_leftBackItemName = leftBackItemName;
				_rightBackItemName = rightBackItemName;
				_hairItemName = hairItemName;
				_beardItemName = beardItemName;
			}

			internal static PlayerFields Capture(ZDO zdo)
			{
				int @int = zdo.GetInt(ZDOVars.s_rightItem, 0);
				int int2 = zdo.GetInt(ZDOVars.s_leftItem, 0);
				int int3 = zdo.GetInt(ZDOVars.s_chestItem, 0);
				int int4 = zdo.GetInt(ZDOVars.s_legItem, 0);
				int int5 = zdo.GetInt(ZDOVars.s_helmetItem, 0);
				int int6 = zdo.GetInt(ZDOVars.s_shoulderItem, 0);
				int int7 = zdo.GetInt(ZDOVars.s_utilityItem, 0);
				int int8 = zdo.GetInt(ZDOVars.s_trinketItem, 0);
				int int9 = zdo.GetInt(ZDOVars.s_leftBackItem, 0);
				int int10 = zdo.GetInt(ZDOVars.s_rightBackItem, 0);
				int int11 = zdo.GetInt(ZDOVars.s_hairItem, 0);
				int int12 = zdo.GetInt(ZDOVars.s_beardItem, 0);
				return new PlayerFields(zdo.GetLong(ZDOVars.s_playerID, 0L), zdo.GetString(ZDOVars.s_playerName, ""), zdo.GetFloat(ZDOVars.s_health, 0f), zdo.GetFloat(ZDOVars.s_maxHealth, 0f), zdo.GetFloat(ZDOVars.s_stamina, 0f), zdo.GetFloat(ZDOVars.s_eitr, 0f), zdo.GetFloat(ZDOVars.s_adrenaline, 0f), zdo.GetBool(ZDOVars.s_dead, false), zdo.GetBool(ZDOVars.s_pvp, false), @int, int2, int3, int4, int5, int6, int7, int8, int9, int10, int11, int12, ResolveItemName(@int), ResolveItemName(int2), ResolveItemName(int3), ResolveItemName(int4), ResolveItemName(int5), ResolveItemName(int6), ResolveItemName(int7), ResolveItemName(int8), ResolveItemName(int9), ResolveItemName(int10), ResolveItemName(int11), ResolveItemName(int12));
			}

			internal void Write(TelemetryJson json, string propertyName)
			{
				json.BeginObject(propertyName);
				json.Prop("exists", value: true);
				json.Prop("playerId", PlayerId);
				json.Prop("playerName", PlayerName);
				json.Prop("health", _health);
				json.Prop("maxHealth", _maxHealth);
				json.Prop("stamina", _stamina);
				json.Prop("eitr", _eitr);
				json.Prop("adrenaline", _adrenaline);
				json.Prop("dead", _dead);
				json.Prop("pvp", _pvp);
				WriteItem(json, "rightItem", _rightItem, _rightItemName);
				WriteItem(json, "leftItem", _leftItem, _leftItemName);
				WriteItem(json, "chestItem", _chestItem, _chestItemName);
				WriteItem(json, "legItem", _legItem, _legItemName);
				WriteItem(json, "helmetItem", _helmetItem, _helmetItemName);
				WriteItem(json, "shoulderItem", _shoulderItem, _shoulderItemName);
				WriteItem(json, "utilityItem", _utilityItem, _utilityItemName);
				WriteItem(json, "trinketItem", _trinketItem, _trinketItemName);
				WriteItem(json, "leftBackItem", _leftBackItem, _leftBackItemName);
				WriteItem(json, "rightBackItem", _rightBackItem, _rightBackItemName);
				WriteItem(json, "hairItem", _hairItem, _hairItemName);
				WriteItem(json, "beardItem", _beardItem, _beardItemName);
				json.EndObject();
			}

			private static void WriteItem(TelemetryJson json, string prefix, int hash, string name)
			{
				json.Prop(prefix + "Hash", hash);
				json.Prop(prefix + "Name", name);
			}
		}

		internal static readonly ClientZdoSnapshot Empty = new ClientZdoSnapshot(exists: false, ZDOID.None, 0, "", Vector3.zero, Quaternion.identity, 0L, 0u, isPlayer: false, isCharacter: false, isMonster: false, isPiece: false, isWearNTear: false, isContainer: false, isPickable: false, PlayerFields.Empty, ClientEquipmentSnapshot.Empty, ClientFoodSlotsSnapshot.Empty, ClientResistanceSnapshot.Empty);

		internal readonly bool Exists;

		internal readonly ZDOID Id;

		internal readonly long PlayerId;

		internal readonly string PlayerName;

		private readonly int _prefabHash;

		private readonly string _prefabName;

		private readonly Vector3 _position;

		private readonly Quaternion _rotation;

		private readonly long _owner;

		private readonly uint _dataRevision;

		private readonly bool _isPlayer;

		private readonly bool _isCharacter;

		private readonly bool _isMonster;

		private readonly bool _isPiece;

		private readonly bool _isWearNTear;

		private readonly bool _isContainer;

		private readonly bool _isPickable;

		private readonly PlayerFields _fields;

		private readonly ClientEquipmentSnapshot _equipment;

		private readonly ClientFoodSlotsSnapshot _foodSlots;

		private readonly ClientResistanceSnapshot _resistances;

		private ClientZdoSnapshot(bool exists, ZDOID id, int prefabHash, string prefabName, Vector3 position, Quaternion rotation, long owner, uint dataRevision, bool isPlayer, bool isCharacter, bool isMonster, bool isPiece, bool isWearNTear, bool isContainer, bool isPickable, PlayerFields fields, ClientEquipmentSnapshot equipment, ClientFoodSlotsSnapshot foodSlots, ClientResistanceSnapshot resistances)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Exists = exists;
			Id = id;
			PlayerId = fields.PlayerId;
			PlayerName = fields.PlayerName;
			_prefabHash = prefabHash;
			_prefabName = prefabName;
			_position = position;
			_rotation = rotation;
			_owner = owner;
			_dataRevision = dataRevision;
			_isPlayer = isPlayer;
			_isCharacter = isCharacter;
			_isMonster = isMonster;
			_isPiece = isPiece;
			_isWearNTear = isWearNTear;
			_isContainer = isContainer;
			_isPickable = isPickable;
			_fields = fields;
			_equipment = equipment;
			_foodSlots = foodSlots;
			_resistances = resistances;
		}

		internal static ClientZdoSnapshot Capture(Character? character)
		{
			if ((Object)(object)character == (Object)null || (Object)(object)character.m_nview == (Object)null)
			{
				return Empty;
			}
			ZDO zDO = character.m_nview.GetZDO();
			if (zDO != null && !((ZDOID)(ref zDO.m_uid)).IsNone())
			{
				return Capture(zDO, ((Component)character).gameObject);
			}
			return Empty;
		}

		internal static ClientZdoSnapshot Capture(ZDOID id)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (((ZDOID)(ref id)).IsNone() || ZDOMan.instance == null)
			{
				return Empty;
			}
			return Capture(ZDOMan.instance.GetZDO(id));
		}

		internal static ClientZdoSnapshot Capture(ZDO zdo)
		{
			if (zdo == null || ((ZDOID)(ref zdo.m_uid)).IsNone())
			{
				return Empty;
			}
			GameObject go = null;
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetView val = ZNetScene.instance.FindInstance(zdo);
				if ((Object)(object)val != (Object)null)
				{
					go = ((Component)val).gameObject;
				}
			}
			return Capture(zdo, go);
		}

		private static ClientZdoSnapshot Capture(ZDO zdo, GameObject? go)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			int prefab = zdo.GetPrefab();
			string prefabName = "";
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
				if ((Object)(object)prefab2 != (Object)null)
				{
					prefabName = ((Object)prefab2).name;
				}
			}
			Player val = (((Object)(object)go != (Object)null) ? go.GetComponent<Player>() : null);
			Character val2 = (((Object)(object)go != (Object)null) ? go.GetComponent<Character>() : null);
			PlayerFields fields = PlayerFields.Capture(zdo);
			return new ClientZdoSnapshot(exists: true, zdo.m_uid, prefab, prefabName, zdo.GetPosition(), zdo.GetRotation(), zdo.GetOwner(), zdo.DataRevision, (Object)(object)val != (Object)null, (Object)(object)val2 != (Object)null, (Object)(object)go != (Object)null && (Object)(object)go.GetComponent<MonsterAI>() != (Object)null, (Object)(object)go != (Object)null && (Object)(object)go.GetComponent<Piece>() != (Object)null, (Object)(object)go != (Object)null && (Object)(object)go.GetComponent<WearNTear>() != (Object)null, (Object)(object)go != (Object)null && (Object)(object)go.GetComponent<Container>() != (Object)null, (Object)(object)go != (Object)null && (Object)(object)go.GetComponent<Pickable>() != (Object)null, fields, ClientEquipmentSnapshot.Capture(val, zdo), ClientFoodSlotsSnapshot.Capture(val), ClientResistanceSnapshot.Capture(val2));
		}

		internal void Write(TelemetryJson json, string propertyName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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)
			json.BeginObject(propertyName);
			json.Prop("exists", Exists);
			json.Prop("id", FormatId(Id));
			json.Prop("prefabHash", _prefabHash);
			json.Prop("prefabName", _prefabName);
			json.Prop("position", _position);
			json.Prop("rotation", _rotation);
			WriteWorldContext(json, _position);
			json.Prop("ownerPeerId", _owner);
			json.Prop("dataRevision", _dataRevision);
			json.BeginArray("components");
			if (_isPlayer)
			{
				json.ArrayString("Player");
			}
			if (_isCharacter)
			{
				json.ArrayString("Character");
			}
			if (_isMonster)
			{
				json.ArrayString("MonsterAI");
			}
			if (_isPiece)
			{
				json.ArrayString("Piece");
			}
			if (_isWearNTear)
			{
				json.ArrayString("WearNTear");
			}
			if (_isContainer)
			{
				json.ArrayString("Container");
			}
			if (_isPickable)
			{
				json.ArrayString("Pickable");
			}
			json.EndArray();
			_fields.Write(json, "fields");
			_equipment.Write(json, "equipment");
			_foodSlots.Write(json, "foodSlots");
			_resistances.Write(json, "resistances");
			json.EndObject();
		}

		internal static string FormatId(ZDOID id)
		{
			if (!((ZDOID)(ref id)).IsNone())
			{
				return ((object)(ZDOID)(ref id)).ToString();
			}
			return "";
		}

		internal static void WriteWorldContext(TelemetryJson json, Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			Vector2i zone = ZoneSystem.GetZone(position);
			object obj;
			if (WorldGenerator.instance == null)
			{
				obj = "";
			}
			else
			{
				Biome biome = WorldGenerator.instance.GetBiome(position);
				obj = ((object)(Biome)(ref biome)).ToString();
			}
			string value = (string)obj;
			json.BeginObject("worldContext");
			json.Prop("exists", value: true);
			json.Prop("biome", value);
			json.Prop("zoneX", zone.x);
			json.Prop("zoneY", zone.y);
			json.Prop("distanceFromCenter", Utils.DistanceXZ(Vector3.zero, position));
			json.EndObject();
		}

		internal bool IsPlayerSnapshot()
		{
			if (Exists)
			{
				if (!_isPlayer && PlayerId == 0L && string.IsNullOrEmpty(PlayerName))
				{
					return _prefabName == "Player";
				}
				return true;
			}
			return false;
		}

		private static string ResolveItemName(int itemHash)
		{
			if (itemHash == 0 || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return "";
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemHash);
			if (!((Object)(object)itemPrefab != (Object)null))
			{
				return "";
			}
			return ((Object)itemPrefab).name;
		}
	}
	internal readonly struct ClientEquipmentSnapshot
	{
		internal static readonly ClientEquipmentSnapshot Empty = new ClientEquipmentSnapshot(exists: false, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty, ClientEquipmentItemSnapshot.Empty);

		private readonly bool _exists;

		private readonly ClientEquipmentItemSnapshot _rightHand;

		private readonly ClientEquipmentItemSnapshot _leftHand;

		private readonly ClientEquipmentItemSnapshot _head;

		private readonly ClientEquipmentItemSnapshot _chest;

		private readonly ClientEquipmentItemSnapshot _legs;

		private readonly ClientEquipmentItemSnapshot _shoulder;

		private readonly ClientEquipmentItemSnapshot _utility;

		private readonly ClientEquipmentItemSnapshot _trinket;

		private ClientEquipmentSnapshot(bool exists, ClientEquipmentItemSnapshot rightHand, ClientEquipmentItemSnapshot leftHand, ClientEquipmentItemSnapshot head, ClientEquipmentItemSnapshot chest, ClientEquipmentItemSnapshot legs, ClientEquipmentItemSnapshot shoulder, ClientEquipmentItemSnapshot utility, ClientEquipmentItemSnapshot trinket)
		{
			_exists = exists;
			_rightHand = rightHand;
			_leftHand = leftHand;
			_head = head;
			_chest = chest;
			_legs = legs;
			_shoulder = shoulder;
			_utility = utility;
			_trinket = trinket;
		}

		internal static ClientEquipmentSnapshot Capture(Player? player, ZDO zdo)
		{
			if ((Object)(object)player != (Object)null)
			{
				return new ClientEquipmentSnapshot(exists: true, ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_rightItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_leftItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_helmetItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_chestItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_legItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_shoulderItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_utilityItem), ClientEquipmentItemSnapshot.Capture(((Humanoid)player).m_trinketItem));
			}
			return new ClientEquipmentSnapshot(exists: true, ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_rightItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_leftItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_helmetItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_chestItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_legItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_shoulderItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_utilityItem, 0)), ClientEquipmentItemSnapshot.Capture(zdo.GetInt(ZDOVars.s_trinketItem, 0)));
		}

		internal void Write(TelemetryJson json, string propertyName)
		{
			json.BeginObject(propertyName);
			json.Prop("exists", _exists);
			_rightHand.Write(json, "rightHand");
			_leftHand.Write(json, "leftHand");
			_head.Write(json, "head");
			_chest.Write(json, "chest");
			_legs.Write(json, "legs");
			_shoulder.Write(json, "shoulder");
			_utility.Write(json, "utility");
			_trinket.Write(json, "trinket");
			json.EndObject();
		}
	}
	internal readonly struct ClientEquipmentItemSnapshot
	{
		internal static readonly ClientEquipmentItemSnapshot Empty = new ClientEquipmentItemSnapshot(exists: false, 0, "", "", 0f, 0f, 0f);

		private readonly bool _exists;

		private readonly int _itemHash;

		private readonly string _prefabName;

		private readonly string _itemName;

		private readonly float _armor;

		private readonly float _durability;

		private readonly float _maxDurability;

		private ClientEquipmentItemSnapshot(bool exists, int itemHash, string prefabName, string itemName, float armor, float durability, float maxDurability)
		{
			_exists = exists;
			_itemHash = itemHash;
			_prefabName = prefabName;
			_itemName = itemName;
			_armor = armor;
			_durability = durability;
			_maxDurability = maxDurability;
		}

		internal static ClientEquipmentItemSnapshot Capture(ItemData? item)
		{
			if (item == null)
			{
				return Empty;
			}
			string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : item.m_shared.m_name);
			return new ClientEquipmentItemSnapshot(exists: true, StringExtensionMethods.GetStableHashCode(text), text, item.m_shared.m_name, item.GetArmor(), item.m_durability, item.GetMaxDurability());
		}

		internal static ClientEquipmentItemSnapshot Capture(int itemHash)
		{
			if (itemHash == 0)
			{
				return Empty;
			}
			string text = "";
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemHash);
				text = (((Object)(object)itemPrefab != (Object)null) ? ((Object)itemPrefab).name : "");
			}
			return new ClientEquipmentItemSnapshot(exists: true, itemHash, text, text, 0f, 0f, 0f);
		}

		internal void Write(TelemetryJson json, string propertyName)
		{
			json.BeginObject(propertyName);
			json.Prop("exists", _exists);
			json.Prop("itemHash", _itemHash);
			json.Prop("prefabName", _prefabName);
			json.Prop("itemName", _itemName);
			json.Prop("armor", _armor);
			json.Prop("durability", _durability);
			json.Prop("maxDurability", _maxDurability);
			json.EndObject();
		}
	}
	internal readonly struct ClientFoodSlotsSnapshot
	{
		internal static readonly ClientFoodSlotsSnapshot Empty = new ClientFoodSlotsSnapshot(exists: false, new List<ClientFoodSlotSnapshot>());

		private readonly bool _exists;

		private readonly List<ClientFoodSlotSnapshot> _slots;

		private ClientFoodSlotsSnapshot(bool exists, List<ClientFoodSlotSnapshot> slots)
		{
			_exists = exists;
			_slots = slots;
		}

		internal static ClientFoodSlotsSnapshot Capture(Player? player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return Empty;
			}
			List<ClientFoodSlotSnapshot> list = new List<ClientFoodSlotSnapshot>();
			IReadOnlyList<Food> foods = player.GetFoods();
			for (int i = 0; i < foods.Count; i++)
			{
				list.Add(ClientFoodSlotSnapshot.Capture(i, foods[i]));
			}
			return new ClientFoodSlotsSnapshot(exists: true, list);
		}

		internal void Write(TelemetryJson json, string propertyName)
		{
			json.BeginObject(propertyName);
			json.Prop("exists", _exists);
			json.BeginArray("slots");
			foreach (ClientFoodSlotSnapshot slot in _slots)
			{
				slot.Write(json);
			}
			json.EndArray();
			json.EndObject();
		}
	}
	internal readonly struct ClientFoodSlotSnapshot
	{
		private readonly int _slot;

		private readonly bool _exists;

		private readonly string _prefabName;

		private readonly string _itemName;

		private readonly float _remainingTime;

		private readonly float _duration;

		private readonly float _health;

		private readonly float _stamina;

		private readonly float _eitr;

		private readonly float _baseHealth;

		private readonly float _baseStamina;

		private readonly float _baseEitr;

		private readonly float _regen;

		private readonly bool _canEatAgain;

		private ClientFoodSlotSnapshot(int slot, bool exists, string prefabName, string itemName, float remainingTime, float duration, float health, float stamina, float eitr, float baseHealth, float baseStamina, float baseEitr, float regen, bool canEatAgain)
		{
			_slot = slot;
			_exists = exists;
			_prefabName = prefabName;
			_itemName = itemName;
			_remainingTime = remainingTime;
			_duration = duration;
			_health = health;
			_stamina = stamina;
			_eitr = eitr;
			_baseHealth = baseHealth;
			_baseStamina = baseStamina;
			_baseEitr = baseEitr;
			_regen = regen;
			_canEatAgain = canEatAgain;
		}

		internal static ClientFoodSlotSnapshot Capture(int slot, Food food)
		{
			ItemData item = food.m_item;
			SharedData val = item?.m_shared;
			string prefabName = (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : food.m_name);
			return new ClientFoodSlotSnapshot(slot, exists: true, prefabName, val?.m_name ?? food.m_name, food.m_time, val?.m_foodBurnTime ?? 0f, food.m_health, food.m_stamina, food.m_eitr, val?.m_food ?? 0f, val?.m_foodStamina ?? 0f, val?.m_foodEitr ?? 0f, val?.m_foodRegen ?? 0f, item != null && food.CanEatAgain());
		}

		internal void Write(TelemetryJson json)
		{
			json.BeginArrayObject();
			json.Prop("slot", _slot);
			json.Prop("exists", _exists);
			json.Prop("prefabName", _prefabName);
			json.Prop("itemName", _itemName);
			json.Prop("remainingTime", _remainingTime);
			json.Prop("duration", _duration);
			json.Prop("health", _health);
			json.Prop("stamina", _stamina);
			json.Prop("eitr", _eitr);
			json.Prop("baseHealth", _baseHealth);
			json.Prop("baseStamina", _baseStamina);
			json.Prop("baseEitr", _baseEitr);
			json.Prop("regen", _regen);
			json.Prop("canEatAgain", _canEatAgain);
			json.EndArrayObject();
		}
	}
	internal readonly struct ClientResistanceSnapshot
	{
		internal static readonly ClientResistanceSnapshot Empty = new ClientResistanceSnapshot(exists: false, default(DamageModifiers));

		private readonly bool _exists;

		private readonly DamageModifiers _modifiers;

		private ClientResistanceSnapshot(bool exists, DamageModifiers modifiers)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			_exists = exists;
			_modifiers = modifiers;
		}

		internal static ClientResistanceSnapshot Capture(Character? character)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)character == (Object)null))
			{
				return new ClientResistanceSnapshot(exists: true, character.GetDamageModifiers((WeakSpot)null));
			}
			return Empty;
		}

		internal void Write(TelemetryJson json, string propertyName)
		{
			//IL_002f: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			json.BeginObject(propertyName);
			json.Prop("exists", _exists);
			json.BeginObject("modifiers");
			json.Prop("blunt", Format(_modifiers.m_blunt));
			json.Prop("slash", Format(_modifiers.m_slash));
			json.Prop("pierce", Format(_modifiers.m_pierce));
			json.Prop("chop", Format(_modifiers.m_chop));
			json.Prop("pickaxe", Format(_modifiers.m_pickaxe));
			json.Prop("fire", Format(_modifiers.m_fire));
			json.Prop("frost", Format(_modifiers.m_frost));
			json.Prop("lightning", Format(_modifiers.m_lightning));
			json.Prop("poison", Format(_modifiers.m_poison));
			json.Prop("spirit", Format(_modifiers.m_spirit));
			json.EndObject();
			json.EndObject();
		}

		private static string Format(DamageModifier modifier)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected I4, but got Unknown
			return (modifier - 1) switch
			{
				0 => "resistant", 
				1 => "weak", 
				2 => "immune", 
				3 => "ignore", 
				4 => "very_resistant", 
				5 => "very_weak", 
				6 => "slightly_resistant", 
				7 => "slightly_weak", 
				_ => "normal", 
			};
		}
	}
	internal static class ValheimEventsTelemetry
	{
		private readonly struct ExploredCell
		{
			internal readonly int X;

			internal readonly int Y;

			internal ExploredCell(int x, int y)
			{
				X = x;
				Y = y;
			}
		}

		private const int ProtocolVersion = 1;

		private static readonly List<ExploredCell> PendingExplorationCells = new List<ExploredCell>();

		private static float _nextExplorationFlushTime;

		private static long _sequence;

		internal static DamageObservationState CaptureDamageBefore(Character? target, HitData? hit)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if (!CanCaptureCombat() || (Object)(object)target == (Object)null || hit == null || (Object)(object)target.m_nview == (Object)null || !target.m_nview.IsOwner())
			{
				return DamageObservationState.Empty;
			}
			try
			{
				ZDOID characterZdoId = GetCharacterZdoId(target);
				ZDOID attacker = hit.m_attacker;
				Character attacker2 = hit.GetAttacker();
				ClientZdoSnapshot targetBefore = ClientZdoSnapshot.Capture(target);
				ClientZdoSnapshot attackerBefore = CaptureCharacterOrZdo(attacker2, attacker);
				if (!targetBefore.IsPlayerSnapshot() && !attackerBefore.IsPlayerSnapshot())
				{
					return DamageObservationState.Empty;
				}
				DamageObservationState result = default(DamageObservationState);
				result.Exists = true;
				result.TargetZdo = characterZdoId;
				result.AttackerZdo = attacker;
				result.HealthBefore = target.GetHealth();
				result.MaxHealthBefore = target.GetMaxHealth();
				result.TargetBefore = targetBefore;
				result.AttackerBefore = attackerBefore;
				return result;
			}
			catch (Exception ex)
			{
				PraetorisClientPlugin.Log.LogWarning((object)("Failed to capture damage telemetry before state: " + ex.GetType().Name + ": " + ex.Message));
				return DamageObservationState.Empty;
			}
		}

		internal static void LogDamageApplied(Character? target, HitData? hit, DamageModifier modifier, DamageObservationState before)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if (!CanCaptureCombat() || !before.Exists || (Object)(object)target == (Object)null || hit == null)
			{
				return;
			}
			try
			{
				float health = target.GetHealth();
				float maxHealth = target.GetMaxHealth();
				float num = Math.Max(0f, before.HealthBefore - health);
				if (!(num <= 0f))
				{
					ZDOID characterZdoId = GetCharacterZdoId(target);
					ZDOID id = (((ZDOID)(ref hit.m_attacker)).IsNone() ? before.AttackerZdo : hit.m_attacker);
					Character attacker = hit.GetAttacker();
					ClientZdoSnapshot clientZdoSnapshot = ClientZdoSnapshot.Capture(target);
					ClientZdoSnapshot clientZdoSnapshot2 = CaptureCharacterOrZdo(attacker, id);
					ClientHitSummary clientHitSummary = ClientHitSummary.From(hit);
					TelemetryJson telemetryJson = ObjectWithEnvelope("damage_applied");
					telemetryJson.Prop("stage", "praetoris_client_apply_damage");
					telemetryJson.Prop("method", "ApplyDamage");
					telemetryJson.Prop("methodKnown", value: true);
					telemetryJson.Prop("sourceClass", "Character");
					telemetryJson.Prop("sourceMod", "PraetorisClient");
					telemetryJson.Prop("targetZdo", ClientZdoSnapshot.FormatId(characterZdoId));
					telemetryJson.Prop("attackerZdo", ClientZdoSnapshot.FormatId(id));
					telemetryJson.Prop("damageApplied", num);
					telemetryJson.Prop("healthBefore", before.HealthBefore);
					telemetryJson.Prop("healthAfter", health);
					telemetryJson.Prop("maxHealthBefore", before.MaxHealthBefore);
					telemetryJson.Prop("maxHealthAfter", maxHealth);
					telemetryJson.Prop("damageModifier", FormatDamageModifier(modifier));
					clientHitSummary.Write(telemetryJson, "hit");
					before.TargetBefore.Write(telemetryJson, "targetBefore");
					clientZdoSnapshot.Write(telemetryJson, "targetAfter");
					before.AttackerBefore.Write(telemetryJson, "attackerBefore");
					clientZdoSnapshot2.Write(telemetryJson, "attackerAfter");
					telemetryJson.End();
					Send(telemetryJson.ToString());
				}
			}
			catch (Exception ex)
			{
				PraetorisClientPlugin.Log.LogWarning((object)("Failed to send damage telemetry: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		internal static DeathObservationState CaptureDeathBefore(Player? player)
		{
			//IL_0044: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (!CanCaptureCombat() || (Object)(object)player == (Object)null || (Object)(object)((Character)player).m_nview == (Object)null || !((Character)player).m_nview.IsOwner())
			{
				return DeathObservationState.Empty;
			}
			try
			{
				HitData lastHit = ((Character)player).m_lastHit;
				ZDOID val = lastHit?.m_attacker ?? ZDOID.None;
				Character character = ((lastHit != null) ? lastHit.GetAttacker() : null);
				DeathObservationState result = default(DeathObservationState);
				result.Exists = true;
				result.PlayerZdo = GetCharacterZdoId((Character)(object)player);
				result.AttackerZdo = val;
				result.HealthBefore = ((Character)player).GetHealth();
				result.MaxHealthBefore = ((Character)player).GetMaxHealth();
				result.HasLastHit = lastHit != null;
				result.LastHit = ((lastHit != null) ? ClientHitSummary.From(lastHit) : ClientHitSummary.Empty);
				result.PlayerBefore = ClientZdoSnapshot.Capture((Character?)(object)player);
				result.AttackerBefore = CaptureCharacterOrZdo(character, val);
				return result;
			}
			catch (Exception ex)
			{
				PraetorisClientPlugin.Log.LogWarning((object)("Failed to capture death telemetry before state: " + ex.GetType().Name + ": " + ex.Message));
				return DeathObservationState.Empty;
			}
		}

		internal static void LogPlayerDied(Player? player, DeathObservationState before)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (!CanCaptureCombat() || !before.Exists || (Object)(object)player == (Object)null)
			{
				return;
			}
			try
			{
				float health = ((Character)player).GetHealth();
				float maxHealth = ((Character)player).GetMaxHealth();
				HitData lastHit = ((Character)player).m_lastHit;
				ZDOID id = ((lastHit != null && !((ZDOID)(ref lastHit.m_attacker)).IsNone()) ? lastHit.m_attacker : before.AttackerZdo);
				Character character = ((lastHit != null) ? lastHit.GetAttacker() : null);
				ClientZdoSnapshot clientZdoSnapshot = ClientZdoSnapshot.Capture((Character?)(object)player);
				ClientZdoSnapshot clientZdoSnapshot2 = CaptureCharacterOrZdo(character, id);
				TelemetryJson telemetryJson = ObjectWithEnvelope("player_died");
				telemetryJson.Prop("stage", "praetoris_client_player_on_death");
				telemetryJson.Prop("method", "OnDeath");
				telemetryJson.Prop("methodKnown", value: true);
				telemetryJson.Prop("sourceClass", "Player");
				telemetryJson.Prop("sourceMod", "PraetorisClient");
				telemetryJson.Prop("playerZdo", ClientZdoSnapshot.FormatId(before.PlayerZdo));
				telemetryJson.Prop("attackerZdo", ClientZdoSnapshot.FormatId(id));
				telemetryJson.Prop("deathDetectedBy", "praetoris_client_player_on_death");
				telemetryJson.Prop("damageApplied", Math.Max(0f, before.HealthBefore - health));
				telemetryJson.Prop("healthBefore", before.HealthBefore);
				telemetryJson.Prop("healthAfter", health);
				telemetryJson.Prop("maxHealthBefore", before.MaxHealthBefore);
				telemetryJson.Prop("maxHealthAfter", maxHealth);
				if (before.HasLastHit)
				{
					before.LastHit.Write(telemetryJson, "hit");
				}
				before.PlayerBefore.Write(telemetryJson, "playerBefore");
				clientZdoSnapshot.Write(telemetryJson, "playerAfter");
				before.AttackerBefore.Write(telemetryJson, "attackerBefore");
				clientZdoSnapshot2.Write(telemetryJson, "attackerAfter");
				telemetryJson.End();
				Send(telemetryJson.ToString());
			}
			catch (Exception ex)
			{
				PraetorisClientPlugin.Log.LogWarning((object)("Failed to send death telemetry: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		internal static void RecordExploredCell(Minimap minimap, int x, int y)
		{
			if (CanSendTelemetry() && PraetorisClientPlugin.ExplorationTelemetryEnabled.Value && !((Object)(object)minimap == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				PendingExplorationCells.Add(new ExploredCell(x, y));
				if (Time.time >= _nextExplorationFlushTime)
				{
					FlushExploration(minimap, "interval");
				}
			}
		}

		internal static void Update()
		{
			if (PendingExplorationCells.Count != 0 && !((Object)(object)Minimap.instance == (Object)null) && !(Time.time < _nextExplorationFlushTime))
			{
				FlushExploration(Minimap.instance, "timer");
			}
		}

		private static void FlushExploration(Minimap minimap, string reason)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			if (PendingExplorationCells.Count == 0 || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			try
			{
				Vector3 position = ((Component)Player.m_localPlayer).transform.position;
				Vector2i zone = ZoneSystem.GetZone(position);
				object obj;
				if (WorldGenerator.instance == null)
				{
					obj = "";
				}
				else
				{
					Biome biome = WorldGenerator.instance.GetBiome(position);
					obj = ((object)(Biome)(ref biome)).ToString();
				}
				string value = (string)obj;
				int count = PendingExplorationCells.Count;
				TelemetryJson telemetryJson = ObjectWithEnvelope("player_exploration");
				telemetryJson.Prop("stage", "praetoris_client_minimap_explore");
				telemetryJson.Prop("method", "Minimap.Explore");
				telemetryJson.Prop("methodKnown", value: true);
				telemetryJson.Prop("sourceClass", "Minimap");
				telemetryJson.Prop("sourceMod", "PraetorisClient");
				telemetryJson.Prop("reason", reason);
				telemetryJson.Prop("playerZdo", ((Object)(object)((Character)Player.m_localPlayer).m_nview != (Object)null) ? ClientZdoSnapshot.FormatId(((Character)Player.m_localPlayer).m_nview.GetZDO().m_uid) : "");
				telemetryJson.Prop("playerName", Player.m_localPlayer.GetPlayerName());
				telemetryJson.Prop("position", position);
				telemetryJson.Prop("biome", value);
				telemetryJson.Prop("zoneX", zone.x);
				telemetryJson.Prop("zoneY", zone.y);
				telemetryJson.Prop("distanceFromCenter", Utils.DistanceXZ(Vector3.zero, position));
				telemetryJson.Prop("newExploredCellCount", count);
				telemetryJson.Prop("mapTextureSize", minimap.m_textureSize);
				telemetryJson.Prop("mapPixelSize", minimap.m_pixelSize);
				telemetryJson.BeginArray("cells");
				int num = Math.Min(count, 128);
				for (int i = 0; i < num; i++)
				{
					ExploredCell exploredCell = PendingExplorationCells[i];
					telemetryJson.BeginArrayObject();
					telemetryJson.Prop("x", exploredCell.X);
					telemetryJson.Prop("y", exploredCell.Y);
					telemetryJson.EndArrayObject();
				}
				telemetryJson.EndArray();
				telemetryJson.End();
				PendingExplorationCells.Clear();
				_nextExplorationFlushTime = Time.time + Math.Max(0.5f, PraetorisClientPlugin.ExplorationFlushSeconds.Value);
				Send(telemetryJson.ToString());
			}
			catch (Exception ex)
			{
				PendingExplorationCells.Clear();
				PraetorisClientPlugin.Log.LogWarning((object)("Failed to send exploration telemetry: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static TelemetryJson ObjectWithEnvelope(string eventType)
		{
			TelemetryJson telemetryJson = TelemetryJson.Object();
			telemetryJson.Prop("schema", "valheim.events.client.v1");
			telemetryJson.Prop("eventType", eventType);
			telemetryJson.Prop("sequence", ++_sequence);
			telemetryJson.Prop("clientTimeUtc", DateTime.UtcNow.ToString("o"));
			telemetryJson.Prop("timeUtc", DateTime.UtcNow.ToString("o"));
			telemetryJson.Prop("worldTime", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().ToString("o") : "");
			telemetryJson.Prop("worldName", (ZNet.m_world != null) ? ZNet.m_world.m_name : "");
			telemetryJson.Prop("worldUid", (ZNet.m_world != null) ? ZNet.m_world.m_uid : 0);
			return telemetryJson;
		}

		private static bool CanCaptureCombat()
		{